diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 78c3915b..dad07245 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -1,5 +1,6 @@ [/Script/Engine.Engine] +ActiveClassRedirects=(OldClassName="/Script/Integration.lxLookAtWidget",NewClassName="/Script/Integration.lxLuaWidget") ++ActiveClassRedirects=(OldClassName="/Script/Integration.K2Node_FormatErrorMessage",NewClassName="/Script/Integration.K2Node_FormatLogMessage") [/Script/Engine.Engine] diff --git a/Content/Characters/Mannequins/Animations/ABP_Manny.uasset b/Content/Characters/Mannequins/Animations/ABP_Manny.uasset index 98563fc9..f1d2bc4a 100644 --- a/Content/Characters/Mannequins/Animations/ABP_Manny.uasset +++ b/Content/Characters/Mannequins/Animations/ABP_Manny.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6f196551cd5f7efda68a41c7f8f3398b36a14ee8bd59ad371bb82bc2b67ebe9 -size 403792 +oid sha256:62d527e544915e62d7343cb4cfd1f4f20789958c957eac6d8fbf860a61f67be2 +size 402045 diff --git a/Content/Tangibles/TAN_Character.uasset b/Content/Tangibles/TAN_Character.uasset index 814933f4..47ac99cb 100644 --- a/Content/Tangibles/TAN_Character.uasset +++ b/Content/Tangibles/TAN_Character.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7120f545caec529c725ddf8bed8d920bee650b12e8523ce33a6f60a0939f0492 -size 368674 +oid sha256:2fbba3e317d578e8d258dde359f4f51cc1bfe9f0a87f21fc41aa67832f701dca +size 350967 diff --git a/Source/Integration/BlueprintErrors.cpp b/Source/Integration/BlueprintErrors.cpp index 195af844..e4818c96 100644 --- a/Source/Integration/BlueprintErrors.cpp +++ b/Source/Integration/BlueprintErrors.cpp @@ -1,12 +1,7 @@ #include "BlueprintErrors.h" #include "Blueprint/BlueprintExceptionInfo.h" -#include "LuaCall.h" -#include "Internationalization/TextFormatter.h" -#include "Kismet/KismetSystemLibrary.h" #include "Kismet2/KismetDebugUtilities.h" -#include "Kismet/KismetTextLibrary.h" -#include "AnimQueue.h" ELogVerbosity::Type UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(ElxLogVerbosity Verbosity) { switch (Verbosity) { @@ -20,231 +15,6 @@ ELogVerbosity::Type UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(ElxLogVerbo } } -void UlxBlueprintErrorLibrary::FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray InArgs) -{ - // Generate the formatted string. - // - FText InPatternText(FText::FromString(InPattern)); - FText Message = FTextFormatter::Format(MoveTemp(InPatternText), MoveTemp(InArgs), false, false); - FString MessageString = Message.ToString(); - - // Get the blueprint name. - // - // Normally, the log function expects you to pass in a filename, and a log - // category name. We use the blueprint name for both. - // - // Using the blueprint name as a log category name is not technically - // correct. However, there is no correct way to create log categories - // from inside of blueprints. Doing it this way at least produces a reasonable - // message inside the log. What doesn't work correctly is the log message - // suppression system. Ie, console commands like 'log verbose' - // don't have any effect here. The design of the log message suppression - // system is such that there just is no reasonable way to hook into it from - // inside of blueprints. - // - FString BlueprintNameString = Context->GetClass()->GetName(); - auto BlueprintNameAnsi = StringCast(*BlueprintNameString); - FLogCategoryName BlueprintNameLogCategory(Context->GetClass()->GetFName()); - - // Output to Log - // - ELogVerbosity::Type VerbosityValue = ConvertElxLogVerbosity(Verbosity); - if (VerbosityValue <= ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY) - { - FMsg::Logf(BlueprintNameAnsi.Get(), 0, BlueprintNameLogCategory, VerbosityValue, TEXT("%s"), *MessageString); - } -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataBool(bool Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_BoolToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataByte(uint8 Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Int; - Result.ArgumentName = Name; - Result.ArgumentValueInt = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataInt(int Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Int; - Result.ArgumentName = Name; - Result.ArgumentValueInt = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataInt64(int64 Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Int; - Result.ArgumentName = Name; - Result.ArgumentValueInt = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataFloat(float Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Float; - Result.ArgumentName = Name; - Result.ArgumentValueFloat = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataDouble(double Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Double; - Result.ArgumentName = Name; - Result.ArgumentValueDouble = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataText(FText Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataString(FString Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_StringToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataName(FName Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_NameToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataKey(FKey Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_NameToText(Value.GetFName()); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataGender(ETextGender Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Gender; - Result.ArgumentName = Name; - Result.ArgumentValueGender = Value; - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataObject(UObject *Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_ObjectToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataVector(const FVector &Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_VectorToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataVector2D(const FVector2D &Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_Vector2dToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataRotator(const FRotator &Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_RotatorToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataTransform(const FTransform &Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = UKismetTextLibrary::Conv_TransformToText(Value); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataLuaValues(const UlxLuaValues *Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = FText::FromString(Value->DebugString()); - return Result; -} - -FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataAnimationStep(const FlxAnimationStep &Value, const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = FText::FromString(UlxAnimationStepLibrary::AnimationStepDebugString(Value)); - return Result; -} - -FFormatArgumentData UlxBlueprintErrorLibrary::FormatArgumentDataBlank(const FString &Name) -{ - FFormatArgumentData Result; - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = FText(); - return Result; -} - -FFormatArgumentData UlxBlueprintErrorLibrary::FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject) -{ - const UEnum *Enum = Cast(PinSubCategoryObject); - FFormatArgumentData Result; - if (Enum == nullptr) - { - Result.ArgumentValueType = EFormatArgumentType::Int; - Result.ArgumentName = Name; - Result.ArgumentValueInt = Value; - } - else - { - Result.ArgumentValueType = EFormatArgumentType::Text; - Result.ArgumentName = Name; - Result.ArgumentValue = FText::Format(INVTEXT("<{0}>"), Enum->GetDisplayNameTextByValue(Value)); - } - return Result; -} - FlxDebugBlueprintErrorsOutputDevice::FlxDebugBlueprintErrorsOutputDevice(const ElxLogVerbosity &SensitivityRef) : Sensitivity(SensitivityRef) { diff --git a/Source/Integration/BlueprintErrors.h b/Source/Integration/BlueprintErrors.h index 5e3925cb..519afdbb 100644 --- a/Source/Integration/BlueprintErrors.h +++ b/Source/Integration/BlueprintErrors.h @@ -6,7 +6,6 @@ #include "Containers/Array.h" #include "CoreMinimal.h" -#include "InputCoreTypes.h" #include "HAL/Platform.h" #include "Misc/OutputDeviceError.h" #include "UObject/NameTypes.h" @@ -16,9 +15,6 @@ #include "BlueprintErrors.generated.h" -class UlxLuaValues; -struct FlxAnimationStep; - /* * enum class ElxLogVerbosity, below, contains all the same error severity levels * as ELogVerbosity, but in a form that the blueprint editor can manipulate. @@ -69,93 +65,11 @@ class UlxBlueprintErrorLibrary : public UBlueprintFunctionLibrary GENERATED_BODY() public: - // The Format Error Message blueprint node macroexpands, the following - // function is the core of the expansion. The actual K2Node itself is in - // its own source file. - // - UFUNCTION(BlueprintCallable, meta=(WorldContext = "Context", BlueprintInternalUseOnly = "true")) - static void FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray InArgs); - - // A formatting routine for pins that were never connected. - // - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataBlank(const FString &Name); - - // A specialized formatting routine for pins of enum types. - // - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject); - // Convert an ElxLogVerbosity to an ELogVerbosity::Type // static ELogVerbosity::Type ConvertElxLogVerbosity(ElxLogVerbosity Verbosity); }; -/* - * A library that contains functions that convert data into FFormatArgumentData - * structs, so that the data can be passed to FText::Format. - */ -UCLASS(MinimalAPI) -class UlxFormatDataLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataBool(bool Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataByte(uint8 Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataInt(int Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataInt64(int64 Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataFloat(float Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataDouble(double Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataText(FText Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataString(FString Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataName(FName Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataKey(FKey Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataGender(ETextGender Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataObject(UObject *Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataVector(const FVector &Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataVector2D(const FVector2D &Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataRotator(const FRotator &Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataTransform(const FTransform &Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataLuaValues(const UlxLuaValues *Value, const FString &Name); - - UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") - static FFormatArgumentData FormatArgumentDataAnimationStep(const FlxAnimationStep &Value, const FString &Name); -}; - /* Debug Blueprint Errors output device. * * When an error message gets written to the log, using "Format Error Message," diff --git a/Source/Integration/FormatDataLibrary.cpp b/Source/Integration/FormatDataLibrary.cpp new file mode 100644 index 00000000..158fe834 --- /dev/null +++ b/Source/Integration/FormatDataLibrary.cpp @@ -0,0 +1,205 @@ + +#include "FormatDataLibrary.h" +#include "LuaCall.h" +#include "AnimQueue.h" +#include "MovementComponentState.h" +#include "Kismet/KismetTextLibrary.h" + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataBool(bool AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_BoolToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataByte(uint8 AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Int; + Result.ArgumentName = Name; + Result.ArgumentValueInt = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataInt(int AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Int; + Result.ArgumentName = Name; + Result.ArgumentValueInt = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataInt64(int64 AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Int; + Result.ArgumentName = Name; + Result.ArgumentValueInt = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataFloat(float AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Float; + Result.ArgumentName = Name; + Result.ArgumentValueFloat = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataDouble(double AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Double; + Result.ArgumentName = Name; + Result.ArgumentValueDouble = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataText(FText AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataString(FString AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_StringToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataName(FName AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_NameToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataKey(FKey AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_NameToText(AutoConvertedValue.GetFName()); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataGender(ETextGender AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Gender; + Result.ArgumentName = Name; + Result.ArgumentValueGender = AutoConvertedValue; + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataObject(UObject *AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_ObjectToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataVector(const FVector &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_VectorToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataVector2D(const FVector2D &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_Vector2dToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataRotator(const FRotator &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_RotatorToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataTransform(const FTransform &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = UKismetTextLibrary::Conv_TransformToText(AutoConvertedValue); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataLuaValues(const UlxLuaValues *AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = FText::FromString(AutoConvertedValue->DebugString()); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataAnimationStep(const FlxAnimationStep &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = FText::FromString(UlxAnimationStepLibrary::AnimationStepDebugString(AutoConvertedValue)); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataMovementComponentState(const FlxMovementComponentState &AutoConvertedValue, const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = FText::FromString(UlxMovementComponentStateLibrary::DebugString(AutoConvertedValue)); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataBlank(const FString &Name) +{ + FFormatArgumentData Result; + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = FText(); + return Result; +} + +FFormatArgumentData UlxFormatDataLibrary::FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject) +{ + const UEnum *Enum = Cast(PinSubCategoryObject); + FFormatArgumentData Result; + if (Enum == nullptr) + { + Result.ArgumentValueType = EFormatArgumentType::Int; + Result.ArgumentName = Name; + Result.ArgumentValueInt = Value; + } + else + { + Result.ArgumentValueType = EFormatArgumentType::Text; + Result.ArgumentName = Name; + Result.ArgumentValue = FText::Format(INVTEXT("<{0}>"), Enum->GetDisplayNameTextByValue(Value)); + } + return Result; +} diff --git a/Source/Integration/FormatDataLibrary.h b/Source/Integration/FormatDataLibrary.h new file mode 100644 index 00000000..57c84725 --- /dev/null +++ b/Source/Integration/FormatDataLibrary.h @@ -0,0 +1,104 @@ +// +// FormatDataLibrary: Functions that convert data into FFormatArgumentData +// structs, so that the data can be passed to FText::Format. +// + +#pragma once + +#include "CoreMinimal.h" +#include "InputCoreTypes.h" +#include "HAL/Platform.h" +#include "UObject/ObjectMacros.h" +#include "UObject/UObjectGlobals.h" +#include "Kismet/BlueprintFunctionLibrary.h" + +#include "FormatDataLibrary.generated.h" + +class UlxLuaValues; +struct FlxAnimationStep; +struct FlxMovementComponentState; + +/* + * A library that contains functions that convert data into FFormatArgumentData + * structs, so that the data can be passed to FTextFormatter::Format. + * + * The FormatLogMessage K2Node scans this library using reflection, + * looking for functions that have a parameter named "AutoConvertedValue". + * It uses the type of that parameter to determine which function to + * call for a given pin type. Functions without an "AutoConvertedValue" + * parameter are ignored by the reflection scan. + * + */ +UCLASS(MinimalAPI) +class UlxFormatDataLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataBool(bool AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataByte(uint8 AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataInt(int AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataInt64(int64 AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataFloat(float AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataDouble(double AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataText(FText AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataString(FString AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataName(FName AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataKey(FKey AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataGender(ETextGender AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataObject(UObject *AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataVector(const FVector &AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataVector2D(const FVector2D &AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataRotator(const FRotator &AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataTransform(const FTransform &AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataLuaValues(const UlxLuaValues *AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataAnimationStep(const FlxAnimationStep &AutoConvertedValue, const FString &Name); + + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataMovementComponentState(const FlxMovementComponentState &AutoConvertedValue, const FString &Name); + + // A formatting routine for pins that were never connected. + // + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataBlank(const FString &Name); + + // A specialized formatting routine for pins of enum types. + // + UFUNCTION(BlueprintPure, meta = (BlueprintInternalUseOnly = "true"), Category = "Luprex|Utility") + static FFormatArgumentData FormatArgumentDataEnum(uint8 Value, const FString &Name, const UObject *PinSubCategoryObject); +}; diff --git a/Source/Integration/FormatError.cpp b/Source/Integration/FormatMessage.cpp similarity index 88% rename from Source/Integration/FormatError.cpp rename to Source/Integration/FormatMessage.cpp index f41f32f6..179a0b34 100644 --- a/Source/Integration/FormatError.cpp +++ b/Source/Integration/FormatMessage.cpp @@ -1,8 +1,9 @@ // Copyright Epic Games, Inc. All Rights Reserved. -#include "FormatError.h" +#include "FormatMessage.h" +#include "Internationalization/TextFormatter.h" #include "BlueprintActionDatabaseRegistrar.h" #include "BlueprintNodeSpawner.h" #include "Containers/EnumAsByte.h" @@ -301,7 +302,7 @@ UFunction *ToFormatArgumentData(const UEdGraphSchema_K2 *Schema, const FEdGraphP // if (PinType.PinCategory == UEdGraphSchema_K2::PC_Wildcard && AllowWild) { - return UlxBlueprintErrorLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxBlueprintErrorLibrary, FormatArgumentDataBlank)); + return UlxFormatDataLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxFormatDataLibrary, FormatArgumentDataBlank)); } // Try to find a match in the UlxFormatDataLibrary. @@ -309,7 +310,7 @@ UFunction *ToFormatArgumentData(const UEdGraphSchema_K2 *Schema, const FEdGraphP for (auto It = TFieldIterator(UlxFormatDataLibrary::StaticClass()); It; ++It) { UFunction* Function = *It; - FProperty* ValueProperty = Function->FindPropertyByName(TEXT("Value")); + FProperty* ValueProperty = Function->FindPropertyByName(TEXT("AutoConvertedValue")); FEdGraphPinType ValuePinType; bool Convertible = Schema->ConvertPropertyToPinType(ValueProperty, ValuePinType); if (!Convertible) continue; @@ -322,7 +323,7 @@ UFunction *ToFormatArgumentData(const UEdGraphSchema_K2 *Schema, const FEdGraphP // if ((PinType.PinCategory == UEdGraphSchema_K2::PC_Byte) && (nullptr != Cast(PinType.PinSubCategoryObject))) { - return UlxBlueprintErrorLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxBlueprintErrorLibrary, FormatArgumentDataEnum)); + return UlxFormatDataLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxFormatDataLibrary, FormatArgumentDataEnum)); } // A case for subclasses of 'Object' which are not exactly 'Object' @@ -359,7 +360,7 @@ void UK2Node_FormatMessage::ExpandNode(class FKismetCompilerContext& CompilerCon UFunction *FormatFunction; if (IsFormatErrorMessage()) { - FormatFunction = UlxBlueprintErrorLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxBlueprintErrorLibrary, FormatErrorInternal)); + FormatFunction = UK2Node_FormatMessage::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UK2Node_FormatMessage, FormatLogMessageInternal)); } else { @@ -399,7 +400,7 @@ void UK2Node_FormatMessage::ExpandNode(class FKismetCompilerContext& CompilerCon ConvertNode->SetFromFunction(Converter); ConvertNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(ConvertNode, this); - UEdGraphPin *ValuePin = ConvertNode->FindPin(TEXT("Value")); + UEdGraphPin *ValuePin = ConvertNode->FindPin(TEXT("AutoConvertedValue")); UEdGraphPin *NamePin = ConvertNode->FindPinChecked(TEXT("Name")); UEdGraphPin *SubCategoryObjectPin = ConvertNode->FindPin(TEXT("PinSubCategoryObject")); @@ -559,7 +560,7 @@ UK2Node_FormatMessage::UK2Node_FormatMessage(const FObjectInitializer& ObjectIni ); } -UK2Node_FormatErrorMessage::UK2Node_FormatErrorMessage(const FObjectInitializer& ObjectInitializer) +UK2Node_FormatLogMessage::UK2Node_FormatLogMessage(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { NodeTooltip = LOCTEXT("NodeTooltip", @@ -572,4 +573,39 @@ UK2Node_FormatErrorMessage::UK2Node_FormatErrorMessage(const FObjectInitializer& ); } +void UK2Node_FormatMessage::FormatLogMessageInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray InArgs) +{ + // Generate the formatted string. + // + FText InPatternText(FText::FromString(InPattern)); + FText Message = FTextFormatter::Format(MoveTemp(InPatternText), MoveTemp(InArgs), false, false); + FString MessageString = Message.ToString(); + + // Get the blueprint name. + // + // Normally, the log function expects you to pass in a filename, and a log + // category name. We use the blueprint name for both. + // + // Using the blueprint name as a log category name is not technically + // correct. However, there is no correct way to create log categories + // from inside of blueprints. Doing it this way at least produces a reasonable + // message inside the log. What doesn't work correctly is the log message + // suppression system. Ie, console commands like 'log verbose' + // don't have any effect here. The design of the log message suppression + // system is such that there just is no reasonable way to hook into it from + // inside of blueprints. + // + FString BlueprintNameString = Context->GetClass()->GetName(); + auto BlueprintNameAnsi = StringCast(*BlueprintNameString); + FLogCategoryName BlueprintNameLogCategory(Context->GetClass()->GetFName()); + + // Output to Log + // + ELogVerbosity::Type VerbosityValue = UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(Verbosity); + if (VerbosityValue <= ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY) + { + FMsg::Logf(BlueprintNameAnsi.Get(), 0, BlueprintNameLogCategory, VerbosityValue, TEXT("%s"), *MessageString); + } +} + #undef LOCTEXT_NAMESPACE diff --git a/Source/Integration/FormatError.h b/Source/Integration/FormatMessage.h similarity index 87% rename from Source/Integration/FormatError.h rename to Source/Integration/FormatMessage.h index 4d661e8b..e32ff845 100644 --- a/Source/Integration/FormatError.h +++ b/Source/Integration/FormatMessage.h @@ -3,6 +3,7 @@ #pragma once #include "BlueprintErrors.h" +#include "FormatDataLibrary.h" #include "Containers/Array.h" #include "CoreMinimal.h" #include "EdGraph/EdGraphNode.h" @@ -15,7 +16,7 @@ #include "UObject/UObjectGlobals.h" #include "BlueprintErrors.h" -#include "FormatError.generated.h" +#include "FormatMessage.generated.h" class FBlueprintActionDatabaseRegistrar; class FString; @@ -77,6 +78,12 @@ protected: /** Our derived class will set this to true, altering the behavior of this K2Node. **/ virtual bool IsFormatErrorMessage() const { return false; } + // When IsFormatErrorMessage is true, the K2Node macroexpands to call this + // function, which formats the message and outputs it to the log. + // + UFUNCTION(BlueprintCallable, meta=(WorldContext = "Context", BlueprintInternalUseOnly = "true")) + static void FormatLogMessageInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray InArgs); + protected: /** When adding arguments to the node, their names are placed here and are generated as pins during construction */ UPROPERTY() @@ -91,7 +98,7 @@ protected: // This derives from FormatMessage. // UCLASS(MinimalAPI) -class UK2Node_FormatErrorMessage : public UK2Node_FormatMessage +class UK2Node_FormatLogMessage : public UK2Node_FormatMessage { GENERATED_UCLASS_BODY() diff --git a/Source/Integration/LxCharacterBase.cpp b/Source/Integration/LxCharacterBase.cpp new file mode 100644 index 00000000..ab1d460f --- /dev/null +++ b/Source/Integration/LxCharacterBase.cpp @@ -0,0 +1,11 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "LxCharacterBase.h" +#include "GameFramework/CharacterMovementComponent.h" + + +void AlxCharacterBase::SetMovementComponentMode(EMovementMode MovementMode) +{ + UCharacterMovementComponent *CMC = GetCharacterMovement(); + if (CMC) CMC->SetMovementMode(MovementMode); +} diff --git a/Source/Integration/LxCharacterBase.h b/Source/Integration/LxCharacterBase.h new file mode 100644 index 00000000..ceeaf1f1 --- /dev/null +++ b/Source/Integration/LxCharacterBase.h @@ -0,0 +1,29 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Character.h" +#include "MovementComponentState.h" +#include "LxCharacterBase.generated.h" + +////////////////////////////////////////////////////////////// +// +// We provide an AlxCharacterBase for characters in Luprex. +// +////////////////////////////////////////////////////////// + +UCLASS(BlueprintType) +class INTEGRATION_API AlxCharacterBase : public ACharacter +{ + GENERATED_BODY() + +public: + AlxCharacterBase() {} + + // Set the movement component mode. This is a thin wrapper + // around CharacterMovementComponent::SetMovementMode. + // + UFUNCTION(BlueprintCallable, Category = "Luprex|Movement Component State") + void SetMovementComponentMode(EMovementMode MovementMode = MOVE_None); +}; diff --git a/Source/Integration/MovementComponentState.cpp b/Source/Integration/MovementComponentState.cpp new file mode 100644 index 00000000..0fe94e4a --- /dev/null +++ b/Source/Integration/MovementComponentState.cpp @@ -0,0 +1,60 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "MovementComponentState.h" +#include "Animation/AnimInstance.h" +#include "GameFramework/CharacterMovementComponent.h" +#include "Tangible.h" + +FlxMovementComponentState::FlxMovementComponentState(UCharacterMovementComponent *CMC) +{ + Velocity = CMC->Velocity; + bIsAccelerating = !CMC->GetCurrentAcceleration().IsNearlyZero(); + MaxWalkSpeed = CMC->MaxWalkSpeed; + MovementMode = CMC->MovementMode; + bIsFalling = CMC->IsFalling(); + bIsCrouching = CMC->IsCrouching(); +} + +FString UlxMovementComponentStateLibrary::DebugString(const FlxMovementComponentState &State) +{ + const UEnum *ModeEnum = StaticEnum(); + FString ModeName = ModeEnum ? ModeEnum->GetNameStringByValue(State.MovementMode.GetValue()) : FString::FromInt(State.MovementMode.GetValue()); + ModeName.RemoveFromStart(TEXT("MOVE_")); + return FString::Printf(TEXT("Vel=(%.1f, %.1f, %.1f) MaxWalk=%.1f Mode=%s Accel=%s Fall=%s Crouch=%s"), + State.Velocity.X, State.Velocity.Y, State.Velocity.Z, + State.MaxWalkSpeed, + *ModeName, + State.bIsAccelerating ? TEXT("true") : TEXT("false"), + State.bIsFalling ? TEXT("true") : TEXT("false"), + State.bIsCrouching ? TEXT("true") : TEXT("false")); +} + +bool UlxMovementComponentStateLibrary::GetShouldMove(const FlxMovementComponentState &State) +{ + return State.bIsAccelerating && State.Velocity.Size2D() >= 3.0; +} + +FlxMovementComponentState UlxMovementComponentStateLibrary::GetMovementComponentState(UAnimInstance *AnimInstance) +{ + if (!AnimInstance) return FlxMovementComponentState(); + + AActor *Actor = AnimInstance->GetOwningActor(); + if (!Actor) return FlxMovementComponentState(); + + UCharacterMovementComponent *CMC = Actor->FindComponentByClass(); + if (CMC && CMC->MovementMode != MOVE_None) return FlxMovementComponentState(CMC); + + UlxTangible *Tangible = UlxTangible::GetActorTangibleQuiet(Actor); + if (Tangible) return Tangible->FakeMovementComponentState; + + if (CMC) return FlxMovementComponentState(CMC); + return FlxMovementComponentState(); +} + +FlxMovementComponentState UlxMovementComponentStateLibrary::SetFakeMovementComponentState(AActor *Actor, const FlxMovementComponentState &State) +{ + if (!Actor) return State; + UlxTangible *Tangible = UlxTangible::GetActorTangibleOrLog(Actor); + if (Tangible) Tangible->FakeMovementComponentState = State; + return State; +} diff --git a/Source/Integration/MovementComponentState.h b/Source/Integration/MovementComponentState.h new file mode 100644 index 00000000..f8eed65d --- /dev/null +++ b/Source/Integration/MovementComponentState.h @@ -0,0 +1,129 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "MovementComponentState.generated.h" + +////////////////////////////////////////////////////////////// +// +// Very often, the animation blueprint of a character will +// want to know the state of the character movement +// component, including such things as Velocity, +// Acceleration, IsFalling, etc. However, the movement +// component cannot be accessed directly from the +// animation graph, since it runs on a worker thread. +// By copying the data into this plain struct, the +// animation graph can safely read it. +// +////////////////////////////////////////////////////////////// + +USTRUCT(BlueprintType) +struct INTEGRATION_API FlxMovementComponentState +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + FVector Velocity = FVector::ZeroVector; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + bool bIsAccelerating = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + float MaxWalkSpeed = 0.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + TEnumAsByte MovementMode = MOVE_None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + bool bIsFalling = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Luprex|Movement Component State") + bool bIsCrouching = false; + + FlxMovementComponentState() = default; + explicit FlxMovementComponentState(class UCharacterMovementComponent *CMC); +}; + +UCLASS() +class INTEGRATION_API UlxMovementComponentStateLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /////////////////////////////////////////////////////////// + // + // True field getters. + // + /////////////////////////////////////////////////////////// + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static FVector GetVelocity(const FlxMovementComponentState &State) { return State.Velocity; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static bool GetIsAccelerating(const FlxMovementComponentState &State) { return State.bIsAccelerating; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static float GetMaxWalkSpeed(const FlxMovementComponentState &State) { return State.MaxWalkSpeed; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static EMovementMode GetMovementMode(const FlxMovementComponentState &State) { return State.MovementMode; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static bool GetIsFalling(const FlxMovementComponentState &State) { return State.bIsFalling; } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static bool GetIsCrouching(const FlxMovementComponentState &State) { return State.bIsCrouching; } + + /////////////////////////////////////////////////////////// + // + // These are not true getters, but actually calculate + // simple values from the existing fields. + // + /////////////////////////////////////////////////////////// + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static float GetGroundSpeed(const FlxMovementComponentState &State) { return State.Velocity.Size2D(); } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State", meta = (BlueprintThreadSafe)) + static bool GetShouldMove(const FlxMovementComponentState &State); + + /////////////////////////////////////////////////////////// + // + // Debugging. + // + /////////////////////////////////////////////////////////// + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Movement Component State") + static FString DebugString(const FlxMovementComponentState &State); + + /////////////////////////////////////////////////////////// + // + // Other operations. + // + /////////////////////////////////////////////////////////// + + // Get a snapshot the Movement Component State. + // + // Normally, this just pulls data directly from the + // character movement component. However, we sometimes + // need to disable the movement component, especially + // during cutscenes. We provide an alternative 'Fake + // Movement Component State' stored on the actor's + // UlxTangible. When the movement component's mode is + // MOVE_None, this function returns the fake movement + // component state instead. The fake movement component + // state can be updated manually in blueprints. + // + UFUNCTION(BlueprintCallable, Category = "Luprex|Movement Component State", meta = (DefaultToSelf = "AnimInstance")) + static FlxMovementComponentState GetMovementComponentState(UAnimInstance *AnimInstance); + + // Update the fake movement component state stored on + // the actor's tangible. The fake movement component + // state is usually read by the animation blueprint + // when the real movement component is disabled. + // + UFUNCTION(BlueprintCallable, Category = "Luprex|Movement Component State", meta = (AutoCreateRefTerm = "State")) + static FlxMovementComponentState SetFakeMovementComponentState(AActor *Actor, const FlxMovementComponentState &State); +}; diff --git a/Source/Integration/ScriptedAnimation.h b/Source/Integration/ScriptedAnimation.h index 05512ddc..323f7a52 100644 --- a/Source/Integration/ScriptedAnimation.h +++ b/Source/Integration/ScriptedAnimation.h @@ -234,7 +234,7 @@ class INTEGRATION_API UlxScriptedAnimationLibrary : public UBlueprintFunctionLib public: // Get all the major 'World Clocks' in a single struct. // - UFUNCTION(BlueprintPure, Category = "Utilities|Time", meta=(WorldContext = "WorldContextObject")) + UFUNCTION(BlueprintCallable, Category = "Utilities|Time", meta=(WorldContext = "WorldContextObject")) static FlxWorldClocks GetAllWorldClocks(const UObject *WorldContextObject); // Get the data to drive Sequence Evaluators and Multi Blend diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index 009b5e09..24b1146e 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "AnimQueue.h" +#include "MovementComponentState.h" #include "ScriptedAnimation.h" #include "Tangible.generated.h" @@ -55,10 +56,14 @@ public: UPROPERTY() FString ActorBlueprintName; - // This is + // Every tangible can store a set of scripted animations. UPROPERTY() UlxScriptedAnimations *ScriptedAnimations = nullptr; + // Every tangible can store a fake movement component state. + UPROPERTY() + FlxMovementComponentState FakeMovementComponentState; + // Animation tracker FlxAnimTracker AnimTracker; diff --git a/Source/Integration/UtilityLibrary.cpp b/Source/Integration/UtilityLibrary.cpp index 01ba37cd..e1259889 100644 --- a/Source/Integration/UtilityLibrary.cpp +++ b/Source/Integration/UtilityLibrary.cpp @@ -239,3 +239,15 @@ FKey UlxUtilityLibrary::GetKeyByNameString(const FString &Name) FKey Key = FKey(FName(*Name)); return Key.IsValid() ? Key : FKey(); } + +FVector UlxUtilityLibrary::GetActorForwardVelocity(const AActor *Actor, double Speed, bool bSnapToXY) +{ + if (!Actor) return FVector::ZeroVector; + FVector Forward = Actor->GetActorForwardVector(); + if (bSnapToXY) + { + Forward.Z = 0.0; + if (!Forward.Normalize()) return FVector::ZeroVector; + } + return Forward * Speed; +} diff --git a/Source/Integration/UtilityLibrary.h b/Source/Integration/UtilityLibrary.h index fa21143a..c7db2f29 100644 --- a/Source/Integration/UtilityLibrary.h +++ b/Source/Integration/UtilityLibrary.h @@ -158,4 +158,11 @@ public: // UFUNCTION(BlueprintPure, Category = "Input|Key") static FKey GetKeyByNameString(const FString &Name); + + // Get the actor's forward vector multiplied by a speed. + // If SnapToXY is true, the forward vector is projected + // onto the XY plane and renormalized before scaling. + // + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Utility", meta = (DefaultToSelf = "Actor")) + static FVector GetActorForwardVelocity(const AActor *Actor, double Speed = 1.0, bool bSnapToXY = false); };