This commit is contained in:
2025-02-05 13:14:42 -05:00
124 changed files with 1229 additions and 731 deletions

View File

@@ -21,3 +21,63 @@ ConnectionType=USBOnly
bUseManualIPAddress=False bUseManualIPAddress=False
ManualIPAddress= ManualIPAddress=
[/Script/Engine.UserInterfaceSettings]
UIScaleCurve=(EditorCurveData=(Keys=((Time=480.000000,Value=0.444000),(Time=720.000000,Value=0.666000),(Time=1080.000000,Value=1.000000),(Time=8640.000000,Value=8.000000)),DefaultValue=340282346638528859811704183484516925440.000000,PreInfinityExtrap=RCCE_Constant,PostInfinityExtrap=RCCE_Constant),ExternalCurve=None)
[/Script/Engine.CollisionProfile]
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
-Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ",bCanModify=False)
-Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ",bCanModify=False)
-Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic",Response=ECR_Block),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.",bCanModify=False)
-Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors",bCanModify=False)
-Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors",bCanModify=False)
-Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.",bCanModify=False)
-Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.",bCanModify=False)
-Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=True,bStaticObject=False,Name="Clickable")
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
-ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
-ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
+ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
+ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
+ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
+ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
+ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
-CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
-CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
-CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
-CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")

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/Luprex/lxGameMode.uasset LFS Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +1,28 @@
diff --git a/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py b/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py
index f56f5ea9cac4..ff1c4030b38f 100644
--- a/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py
+++ b/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py
@@ -32,7 +32,7 @@ def UETCharSummaryProvider(valobj,dict):
if DataVal == 0:
Val = 'NULL'
else:
- Expr = '(char16_t*)(%s)' % Data
+ Expr = '(char16_t*)(%s)' % DataVal
ValRef = valobj.CreateValueFromExpression('string', Expr)
Val = ValRef.GetSummary()
elif Type.IsReferenceType():
@@ -47,6 +47,11 @@ def UETCharSummaryProvider(valobj,dict):
Expr = '(char16_t*)(%s)' % valobj.GetAddress()
ValRef = valobj.CreateValueFromExpression('string', Expr)
Val = ValRef.GetSummary()
+ else:
+ DataVal = valobj.GetValueAsUnsigned(0)
+ Expr = '(char16_t)(%s)' % DataVal
+ ValRef = valobj.CreateValueFromExpression('string', Expr)
+ Val = ValRef.GetSummary()
return Val
def UESignedCharSummaryProvider(valobj,dict):
diff --git a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp b/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp diff --git a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp b/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp
index ca5f4b5fb5ff..a436a624d5b7 100644 index ca5f4b5fb5ff..a436a624d5b7 100644
--- a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp --- a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformApplicationMisc.cpp

View File

@@ -81,8 +81,9 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
bChanged = false; bChanged = false;
Action = TEXT(""); Action = TEXT("");
if (prefix.IsEmpty()) { if (prefix.IsEmpty())
UlxUtilityLibrary::Assert(false, TEXT("You may not pass an empty string for prefix")); {
UE_LOG(LogBlueprint, Error, TEXT("UnpackAnimationStep: You may not pass an empty string for prefix"));
return; return;
} }
@@ -92,8 +93,7 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
FStructProperty* stepproperty = FindAnimationStepProperty(uclass, prefix); FStructProperty* stepproperty = FindAnimationStepProperty(uclass, prefix);
if (stepproperty == nullptr) { if (stepproperty == nullptr) {
UE_LOG(LogBlueprint, Error, TEXT("Target object: %s Prefix: %s"), *(target->GetName()), *prefix); UE_LOG(LogBlueprint, Error, TEXT("UnpackAnimationStep: Target object does not have a variable named: '%s Animation Step'"), *prefix);
UlxUtilityLibrary::Assert(false, TEXT("Target object does not have an variable named '<prefix> Animation Step'"));
return; return;
} }

View File

@@ -16,7 +16,7 @@
// //
//////////////////////////////////////////////// ////////////////////////////////////////////////
USTRUCT(Blueprintable) USTRUCT(BlueprintType)
struct INTEGRATION_API FlxAnimationStep { struct INTEGRATION_API FlxAnimationStep {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -0,0 +1,137 @@
#include "BlueprintErrors.h"
#include "Internationalization/TextFormatter.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet2/KismetDebugUtilities.h"
#include "Kismet/KismetTextLibrary.h"
ELogVerbosity::Type UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(ElxLogVerbosity Verbosity) {
switch (Verbosity) {
case ElxLogVerbosity::Error: return ELogVerbosity::Error;
case ElxLogVerbosity::Warning: return ELogVerbosity::Warning;
case ElxLogVerbosity::Display: return ELogVerbosity::Display;
case ElxLogVerbosity::Log: return ELogVerbosity::Log;
case ElxLogVerbosity::Verbose: return ELogVerbosity::Verbose;
case ElxLogVerbosity::VeryVerbose: return ELogVerbosity::VeryVerbose;
case ElxLogVerbosity::Fatal: return ELogVerbosity::Fatal;
}
}
void UlxBlueprintErrorLibrary::FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, ElxErrorDisplayDuration DisplayDuration, const FString &InPattern, TArray<FFormatArgumentData> InArgs)
{
// Generate the formatted string.
//
FText InPatternText(FText::FromString(InPattern));
FText Message = FTextFormatter::Format(MoveTemp(InPatternText), MoveTemp(InArgs), false, false);
FString MessageString = Message.ToString();
// Convert the DisplayDuration enum into a number of seconds.
//
int Seconds = int(DisplayDuration);
if (Seconds > 100) Seconds = (Seconds - 100) * 60;
// Choose a color appropriate to the verbosity level.
//
FLinearColor Color;
switch (Verbosity) {
case ElxLogVerbosity::Fatal : Color = FLinearColor(1.0, 0.6, 0.6); break;
case ElxLogVerbosity::Error : Color = FLinearColor(1.0, 0.6, 0.6); break;
case ElxLogVerbosity::Warning : Color = FLinearColor(0.9, 0.9, 0.6); break;
default: Color = FLinearColor(0.8, 0.8, 0.8); break;
}
// 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 <category> 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<ANSICHAR>(*BlueprintNameString);
FLogCategoryName BlueprintNameLogCategory(Context->GetClass()->GetFName());
// Output to Screen, if requested.
//
if (Seconds != 0)
{
UKismetSystemLibrary::PrintText(NULL, Message, true, false, Color, Seconds, NAME_None);
}
// 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);
}
}
FlxDebugBlueprintErrorsOutputDevice::FlxDebugBlueprintErrorsOutputDevice(const ElxLogVerbosity &SensitivityRef)
: Sensitivity(SensitivityRef)
{
GLog->AddOutputDevice(this);
}
FlxDebugBlueprintErrorsOutputDevice::~FlxDebugBlueprintErrorsOutputDevice()
{
GLog->RemoveOutputDevice(this);
}
namespace UBreakPoint {
static volatile int V;
FORCENOINLINE static void OnLogFatal() {
V = 0;
}
FORCENOINLINE static void OnLogError() {
V = 1;
OnLogFatal();
}
FORCENOINLINE static void OnLogWarning() {
V = 2;
OnLogError();
}
}
static const FName LogBlueprintDebugName(TEXT("LogBlueprintDebug"));
void FlxDebugBlueprintErrorsOutputDevice::Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category)
{
// If the error isn't serious enough, do nothing.
//
if (Verbosity > UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(Sensitivity))
{
return;
}
// If the Category is LogBlueprintDebug, then we're inside the debugger already.
//
if (Category == LogBlueprintDebugName)
{
return;
}
// Find out if we're running in a blueprint thread. If not, return.
//
FFrame* Frame = FFrame::GetThreadLocalTopStackFrame();
if (Frame == nullptr) return;
UObject *TopObject = Frame->Object;
if (TopObject == nullptr) return;
// Notify the debugger that there's been an exception.
//
FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::Breakpoint, FText::FromStringView(FStringView(V)));
FBlueprintCoreDelegates::ThrowScriptException(TopObject, *Frame, ExceptionInfo);
}

View File

@@ -0,0 +1,181 @@
//
// BlueprintErrors: Better error handling for blueprint errors.
//
#pragma once
#include "Containers/Array.h"
#include "CoreMinimal.h"
#include "HAL/Platform.h"
#include "Misc/OutputDeviceError.h"
#include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/UObjectGlobals.h"
#include "BlueprintErrors.generated.h"
/*
* enum class ElxLogVerbosity, below, contains all the same error severity levels
* as ELogVerbosity, but in a form that the blueprint editor can manipulate.
*
* We deliberately moved 'Fatal' to the end of the list, and made 'Error' option 0.
* We did that because we want the editor to default to 'Error' in most cases.
* Unfortunately, that means the numeric values of the two enums don't match up,
* so we will need a conversion function.
*
*/
/** Log Verbosity: The importance of an error message, which affects which logs the error
* message gets written to, and how that message gets filtered.
*
*/
UENUM(BlueprintType)
enum class ElxLogVerbosity : uint8 {
/* Prints an error to the console and log file. The editor collects and reports errors. */
Error,
/* Prints a warning to the console and log file. The editor collects and report warnings. */
Warning,
/* Prints a message to the console and log file. */
Display,
/* Prints a message to the log file, however, it does not print to the console. */
Log,
/* Prints a message to a log file only if Verbose logging is enabled for the given category. This is usually used for detailed logging. */
Verbose,
/* Prints a message to a log file. If VeryVerbose logging is enabled, then this is used for detailed logging that would otherwise spam output. */
VeryVerbose,
/* Danger! Prints a fatal error to the console and log file, then crashes (this crashes the editor too). */
Fatal,
};
/** Display Duration: How long to display an error message in the game's viewport.
*
*/
UENUM(BlueprintType)
enum class ElxErrorDisplayDuration : uint8 {
/* Do not display the message in the viewport */
No_Show = 0,
/* Display the message in the viewport for 1 seconds */
Show_1_Seconds = 1,
/* Display the message in the viewport for 2 seconds */
Show_2_Seconds = 2,
/* Display the message in the viewport for 3 seconds */
Show_3_Seconds = 3,
/* Display the message in the viewport for 4 seconds */
Show_4_Seconds = 4,
/* Display the message in the viewport for 5 seconds */
Show_5_Seconds = 5,
/* Display the message in the viewport for 10 seconds */
Show_10_Seconds = 10,
/* Display the message in the viewport for 20 seconds */
Show_20_Seconds = 20,
/* Display the message in the viewport for 30 seconds */
Show_30_Seconds = 30,
/* Display the message in the viewport for 40 seconds */
Show_40_Seconds = 40,
/* Display the message in the viewport for 50 seconds */
Show_50_Seconds = 50,
/* Display the message in the viewport for 60 seconds */
Show_60_Seconds = 60,
/* Display the message in the viewport for 70 seconds */
Show_70_Seconds = 70,
/* Display the message in the viewport for 80 seconds */
Show_80_Seconds = 80,
/* Display the message in the viewport for 90 seconds */
Show_90_Seconds = 90,
/* Display the message in the viewport for 1 minutes */
Show_1_Minutes = 101,
/* Display the message in the viewport for 2 minutes */
Show_2_Minutes = 102,
/* Display the message in the viewport for 3 minutes */
Show_3_Minutes = 103,
/* Display the message in the viewport for 4 minutes */
Show_4_Minutes = 104,
/* Display the message in the viewport for 5 minutes */
Show_5_Minutes = 105,
};
/* A library containing assorted useful functions for blueprint error handling.
*
*/
UCLASS(MinimalAPI)
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, ElxErrorDisplayDuration DisplayDuration, const FString &InPattern, TArray<FFormatArgumentData> InArgs);
// Convert an ElxLogVerbosity to an ELogVerbosity::Type
//
static ELogVerbosity::Type ConvertElxLogVerbosity(ElxLogVerbosity Verbosity);
};
/* Debug Blueprint Errors output device.
*
* When an error message gets written to the log, using "Format Error Message,"
* or any other means that writes an error message to the log,
* we can optionally notify the blueprint debugger to pause execution.
* This only affects errors that are generated during blueprint execution.
* Errors in other threads do not pause the blueprint.
*
*/
struct FlxDebugBlueprintErrorsOutputDevice : public FOutputDevice
{
public:
// The constructor and destructor automatically register this output device with GLog.
//
// This struct doesn't store the sensitivity threshold. It relies on some blueprint
// class to do that, so that the threshold can be easily edited with the blueprint
// editor. This struct must be initialized with a reference to the threshold variable.
//
FlxDebugBlueprintErrorsOutputDevice(const ElxLogVerbosity &SensitivityRef);
~FlxDebugBlueprintErrorsOutputDevice();
// Inspect a log message.
//
INTEGRATION_API virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override;
// If the device is marked 'CanBeUsedOnMultipleThreads,' then UE_LOG will
// call Serialize from the current thread, otherwise, it will call Serialize from
// the logging thread. Using the logging thread would defeat the purpose of this
// device, so it's imperative that we set this flag.
//
INTEGRATION_API virtual bool CanBeUsedOnMultipleThreads() const override { return true; }
private:
const ElxLogVerbosity &Sensitivity;
};

View File

@@ -15,12 +15,10 @@
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
#include "HAL/PlatformCrt.h" #include "HAL/PlatformCrt.h"
#include "Internationalization/Internationalization.h" #include "Internationalization/Internationalization.h"
#include "Internationalization/TextFormatter.h"
#include "K2Node_CallFunction.h" #include "K2Node_CallFunction.h"
#include "K2Node_MakeArray.h" #include "K2Node_MakeArray.h"
#include "K2Node_MakeStruct.h" #include "K2Node_MakeStruct.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetTextLibrary.h" #include "Kismet/KismetTextLibrary.h"
#include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/CompilerResultsLog.h" #include "Kismet2/CompilerResultsLog.h"
@@ -104,8 +102,8 @@ void UK2Node_FormatError::CreateCorrectPins()
} }
if (FindPin(FormatPinName, EGPD_Input) == nullptr) { if (FindPin(FormatPinName, EGPD_Input) == nullptr) {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Text, FormatPinName); UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_String, FormatPinName);
P->DefaultTextValue = LOCTEXT("FormatErrorMessage_DefaultMessage", "Error Message"); P->DefaultValue = TEXT("Error Message");
} }
if (FindPin(VerbosityPinName, EGPD_Input) == nullptr) { if (FindPin(VerbosityPinName, EGPD_Input) == nullptr) {
@@ -115,7 +113,7 @@ void UK2Node_FormatError::CreateCorrectPins()
} }
if (FindPin(DisplayDurationPinName, EGPD_Input) == nullptr) { if (FindPin(DisplayDurationPinName, EGPD_Input) == nullptr) {
UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, StaticEnum<ElxDisplayDuration>(), DisplayDurationPinName); UEdGraphPin *P = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Byte, StaticEnum<ElxErrorDisplayDuration>(), DisplayDurationPinName);
P->DefaultValue = TEXT("No_Display"); P->DefaultValue = TEXT("No_Display");
P->AutogeneratedDefaultValue = P->DefaultValue; P->AutogeneratedDefaultValue = P->DefaultValue;
} }
@@ -252,7 +250,7 @@ void UK2Node_FormatError::PinDefaultValueChanged(UEdGraphPin* Pin)
if(IsFormatPin(Pin)) if(IsFormatPin(Pin))
{ {
PinNames.Empty(); PinNames.Empty();
FText::GetFormatPatternParameters(Pin->DefaultTextValue, PinNames); FText::GetFormatPatternParameters(FText::FromString(Pin->DefaultValue), PinNames);
CreateCorrectPins(); CreateCorrectPins();
GetGraph()->NotifyNodeChanged(this); GetGraph()->NotifyNodeChanged(this);
} }
@@ -318,7 +316,7 @@ void UK2Node_FormatError::ExpandNode(class FKismetCompilerContext& CompilerConte
// This is the node that does all the Format work and outputs the message. // This is the node that does all the Format work and outputs the message.
UK2Node_CallFunction* CallFormatFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); UK2Node_CallFunction* CallFormatFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
UFunction *FormatFunction = UlxFormatErrorLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxFormatErrorLibrary, FormatErrorInternal)); UFunction *FormatFunction = UlxBlueprintErrorLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UlxBlueprintErrorLibrary, FormatErrorInternal));
CallFormatFunction->SetFromFunction(FormatFunction); CallFormatFunction->SetFromFunction(FormatFunction);
CallFormatFunction->AllocateDefaultPins(); CallFormatFunction->AllocateDefaultPins();
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFormatFunction, this); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFormatFunction, this);
@@ -608,71 +606,5 @@ FText UK2Node_FormatError::GetMenuCategory() const
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Text); return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Text);
} }
void UlxFormatErrorLibrary::FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, ElxDisplayDuration DisplayDuration, FText InPattern, TArray<FFormatArgumentData> InArgs)
{
// Generate the formatted string.
//
FText Message = FTextFormatter::Format(MoveTemp(InPattern), MoveTemp(InArgs), false, false);
FString MessageString = Message.ToString();
// Convert the DisplayDuration enum into a number of seconds.
//
int Seconds = int(DisplayDuration);
if (Seconds > 100) Seconds = (Seconds - 100) * 60;
// Choose a color appropriate to the verbosity level.
//
FLinearColor Color;
switch (Verbosity) {
case ElxLogVerbosity::Fatal : Color = FLinearColor(1.0, 0.6, 0.6); break;
case ElxLogVerbosity::Error : Color = FLinearColor(1.0, 0.6, 0.6); break;
case ElxLogVerbosity::Warning : Color = FLinearColor(0.9, 0.9, 0.6); break;
default: Color = FLinearColor(0.8, 0.8, 0.8); break;
}
// Convert verbosity to an internal value.
//
ELogVerbosity::Type VerbosityValue;
switch (Verbosity) {
case ElxLogVerbosity::Error: VerbosityValue = ELogVerbosity::Error; break;
case ElxLogVerbosity::Warning: VerbosityValue = ELogVerbosity::Warning; break;
case ElxLogVerbosity::Display: VerbosityValue = ELogVerbosity::Display; break;
case ElxLogVerbosity::Log: VerbosityValue = ELogVerbosity::Log; break;
case ElxLogVerbosity::Verbose: VerbosityValue = ELogVerbosity::Verbose; break;
case ElxLogVerbosity::VeryVerbose: VerbosityValue = ELogVerbosity::VeryVerbose; break;
case ElxLogVerbosity::Fatal: VerbosityValue = ELogVerbosity::Fatal; break;
}
// 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 <category> 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<ANSICHAR>(*BlueprintNameString);
FLogCategoryName BlueprintNameLogCategory(Context->GetClass()->GetFName());
// Output to Screen, if requested.
//
if (Seconds != 0)
{
UKismetSystemLibrary::PrintText(NULL, Message, true, false, Color, Seconds, NAME_None);
}
// Output to Log
//
FMsg::Logf(BlueprintNameAnsi.Get(), 0, BlueprintNameLogCategory, VerbosityValue, TEXT("%s"), *MessageString);
}
#undef LOCTEXT_NAMESPACE #undef LOCTEXT_NAMESPACE

View File

@@ -2,6 +2,7 @@
#pragma once #pragma once
#include "BlueprintErrors.h"
#include "Containers/Array.h" #include "Containers/Array.h"
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
@@ -12,6 +13,7 @@
#include "UObject/NameTypes.h" #include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h" #include "UObject/ObjectMacros.h"
#include "UObject/UObjectGlobals.h" #include "UObject/UObjectGlobals.h"
#include "BlueprintErrors.h"
#include "FormatError.generated.h" #include "FormatError.generated.h"
@@ -23,121 +25,6 @@ class UObject;
//
// The following UENUM contains all the ELogVerbosity levels, in a form
// that the blueprint editor can manipulate.
//
// We deliberately moved Fatal to the end of the list, because the editor
// will display these values in the order shown here, and we want Error to
// be the value that is 'promoted', and we want Fatal to be buried as a
// rarely-used option.
//
/** Log Verbosity: The importance of the message, which affects where the message goes and how it is filtered. */
UENUM(BlueprintType)
enum class ElxLogVerbosity : uint8 {
/* Prints an error to the console and log file. The editor collects and reports errors. */
Error,
/* Prints a warning to the console and log file. The editor collects and report warnings. */
Warning,
/* Prints a message to the console and log file. */
Display,
/* Prints a message to the log file, however, it does not print to the console. */
Log,
/* Prints a message to a log file only if Verbose logging is enabled for the given category. This is usually used for detailed logging. */
Verbose,
/* Prints a message to a log file. If VeryVerbose logging is enabled, then this is used for detailed logging that would otherwise spam output. */
VeryVerbose,
/* Danger! Prints a fatal error to the console and log file, then crashes (this crashes the editor too). */
Fatal,
};
/** Display Duration: How long to display a message in the game's viewport */
UENUM(BlueprintType)
enum class ElxDisplayDuration : uint8 {
/* Do not display the message in the viewport */
No_Display_in_Viewport = 0,
/* Display the message in the viewport for 1 second */
Display_1_Seconds = 1,
/* Display the message in the viewport for 2 second */
Display_2_Seconds = 2,
/* Display the message in the viewport for 3 second */
Display_3_Seconds = 3,
/* Display the message in the viewport for 4 second */
Display_4_Seconds = 4,
/* Display the message in the viewport for 5 second */
Display_5_Seconds = 5,
/* Display the message in the viewport for 10 second */
Display_10_Seconds = 10,
/* Display the message in the viewport for 20 second */
Display_20_Seconds = 20,
/* Display the message in the viewport for 30 second */
Display_30_Seconds = 30,
/* Display the message in the viewport for 1 second */
Display_40_Seconds = 40,
/* Display the message in the viewport for 1 second */
Display_50_Seconds = 50,
/* Display the message in the viewport for 1 second */
Display_60_Seconds = 60,
/* Display the message in the viewport for 1 second */
Display_70_Seconds = 70,
/* Display the message in the viewport for 1 second */
Display_80_Seconds = 80,
/* Display the message in the viewport for 1 second */
Display_90_Seconds = 90,
/* Display the message in the viewport for 1 second */
Display_1_Minute = 101,
/* Display the message in the viewport for 1 second */
Display_2_Minutes = 102,
/* Display the message in the viewport for 1 second */
Display_3_Minutes = 103,
/* Display the message in the viewport for 1 second */
Display_4_Minutes = 104,
/* Display the message in the viewport for 1 second */
Display_5_Minutes = 105,
};
//
// Library functions used by Format Error Message.
//
UCLASS(MinimalAPI)
class UlxFormatErrorLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, meta=(WorldContext = "Context", BlueprintInternalUseOnly = "true"))
static void FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, ElxDisplayDuration DisplayDuration, FText InPattern, TArray<FFormatArgumentData> InArgs);
};
// //
// The Format Error Message K2Node. // The Format Error Message K2Node.
// //

View File

@@ -77,6 +77,9 @@ void AIntegrationGameModeBase::ResetToInitialState()
w->release(w.Get()); w->release(w.Get());
} }
// Stop trapping log errors to the debugger.
BreakToDebuggerLogVerbosityDevice.Reset();
// Clear the lua call assembly buffer. // Clear the lua call assembly buffer.
LuaCallBuffer.clear(); LuaCallBuffer.clear();
@@ -84,8 +87,8 @@ void AIntegrationGameModeBase::ResetToInitialState()
PlayerId = 0; PlayerId = 0;
// Clear the look-at state; // Clear the look-at state;
PreviousLookAt = nullptr; PreviousLookAt.Init();
CurrentLookAt = nullptr; CurrentLookAt.Init();
// Reset the clocks. // Reset the clocks.
EngineSeconds = 0.0; EngineSeconds = 0.0;
@@ -316,6 +319,10 @@ void AIntegrationGameModeBase::BeginPlay()
// Initialize the tangible manager. // Initialize the tangible manager.
TangibleManager = NewObject<UlxTangibleManager>(); TangibleManager = NewObject<UlxTangibleManager>();
TangibleManager->Init(GetWorld(), this); TangibleManager->Init(GetWorld(), this);
// If somebody generates a log message that's severe enough, break to debugger.
BreakToDebuggerLogVerbosityDevice.Reset(
new FlxDebugBlueprintErrorsOutputDevice(BreakToDebuggerLogVerbosity));
} }
void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
@@ -342,7 +349,7 @@ AIntegrationGameModeBase *AIntegrationGameModeBase::GetFromContext(UObject *cont
void AIntegrationGameModeBase::UpdateLookAt() { void AIntegrationGameModeBase::UpdateLookAt() {
// Rotate the variables. // Rotate the variables.
PreviousLookAt = CurrentLookAt; PreviousLookAt = CurrentLookAt;
CurrentLookAt = nullptr; CurrentLookAt.Init();
// Make sure the world is fully configured before we attempt to cast rays. // Make sure the world is fully configured before we attempt to cast rays.
UlxTangible *possessed = TangibleManager->GetPossessedTangible(); UlxTangible *possessed = TangibleManager->GetPossessedTangible();

View File

@@ -10,6 +10,7 @@
#include "TangibleManager.h" #include "TangibleManager.h"
#include "LuprexSockets.h" #include "LuprexSockets.h"
#include "TriggeredTask.h" #include "TriggeredTask.h"
#include "BlueprintErrors.h"
#include "IntegrationGameModeBase.generated.h" #include "IntegrationGameModeBase.generated.h"
@@ -46,13 +47,13 @@ public:
int64 GetPlayerId(); int64 GetPlayerId();
UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection") UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection")
void SetLookAt(AActor *actor) { CurrentLookAt = actor; } void SetLookAt(const FHitResult &hit) { CurrentLookAt = hit; }
UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection") UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection")
AActor *GetLookAt() const { return CurrentLookAt; } const FHitResult &GetLookAt() const { return CurrentLookAt; }
UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection") UFUNCTION(BlueprintCallable, Category = "Luprex|Look-At Detection")
bool LookAtChanged() const { return CurrentLookAt != PreviousLookAt; } bool LookAtChanged() const { return CurrentLookAt.HitObjectHandle != PreviousLookAt.HitObjectHandle; }
UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Look-At Detection") UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Look-At Detection")
void CalculateLookAt(AActor *Player, APlayerController *PlayerController, APlayerCameraManager *Camera); void CalculateLookAt(AActor *Player, APlayerController *PlayerController, APlayerCameraManager *Camera);
@@ -110,13 +111,17 @@ public:
UPROPERTY() UPROPERTY()
UlxTangibleManager *TangibleManager; UlxTangibleManager *TangibleManager;
// The actor that the player is looking at, previous frame. // The actor that the player was looking at, previous frame.
UPROPERTY() UPROPERTY()
AActor *PreviousLookAt; FHitResult PreviousLookAt;
// The actor that the player is looking at, current frame. // The actor that the player is looking at, current frame.
UPROPERTY() UPROPERTY()
AActor *CurrentLookAt; FHitResult CurrentLookAt;
// The sensitivity level at which a log message triggers a debugger breakpoint.
UPROPERTY(EditAnywhere, Category="Debugging Tools")
ElxLogVerbosity BreakToDebuggerLogVerbosity;
// This stores the entire text currently visible in the console. // This stores the entire text currently visible in the console.
FlxConsoleOutput ConsoleOutput; FlxConsoleOutput ConsoleOutput;
@@ -150,4 +155,7 @@ public:
// These allow us to pre-tick and post-tick. // These allow us to pre-tick and post-tick.
FDelegateHandle OnWorldPreActorTickHandle; FDelegateHandle OnWorldPreActorTickHandle;
FDelegateHandle OnWorldPostActorTickHandle; FDelegateHandle OnWorldPostActorTickHandle;
// The device that implements BreakToDebuggerLogVerbosity, above.
TUniquePtr<FlxDebugBlueprintErrorsOutputDevice> BreakToDebuggerLogVerbosityDevice;
}; };

View File

@@ -4,24 +4,17 @@
#include "UtilityLibrary.h" #include "UtilityLibrary.h"
#include "GameFramework/PlayerController.h" #include "GameFramework/PlayerController.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/GameplayStatics.h"
#define LOCTEXT_NAMESPACE "Luprex Utility" #define LOCTEXT_NAMESPACE "Luprex Utility"
void UlxUtilityLibrary::Assert(bool condition, const FString &message) {
if (!condition) {
FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::FatalError, FText::FromString(message));
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
}
}
void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namepart1, const FString &namepart2, const FString &fallback, bool bFailIfNotFound) { void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namepart1, const FString &namepart2, const FString &fallback, bool bFailIfNotFound) {
FString fullname = namepart1 + namepart2; FString fullname = namepart1 + namepart2;
if (!IsValid(object)) { if (!IsValid(object)) {
const FBlueprintExceptionInfo ExceptionInfo( UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, object passed in is not valid."));
EBlueprintExceptionType::FatalError,
LOCTEXT("CallFunctionByName_ObjectIsNotValid", "In CallFunctionByName, object passed in is not valid.")
);
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
return; return;
} }
UFunction* function = object->FindFunction(FName(*fullname)); UFunction* function = object->FindFunction(FName(*fullname));
@@ -31,20 +24,12 @@ void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namep
if (!bFailIfNotFound) { if (!bFailIfNotFound) {
return; return;
} }
const FBlueprintExceptionInfo ExceptionInfo( UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, cannot find the named function or the fallback function"));
EBlueprintExceptionType::FatalError,
LOCTEXT("CallFunctionByName_NoSuchFunction", "In CallFunctionByName, cannot find the named function or the fallback function.")
);
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
return; return;
} }
} }
if (function->ParmsSize != 0) { if (function->ParmsSize != 0) {
const FBlueprintExceptionInfo ExceptionInfo( UE_LOG(LogBlueprint, Error, TEXT("CallFunctionByName can only call functions that have no parameters and no return values"));
EBlueprintExceptionType::FatalError,
LOCTEXT("CallFunctionByName_FunctionHasParameters", "CallFunctionByName can only call functions that have no parameters and no return values.")
);
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
return; return;
} }
object->ProcessEvent(function, nullptr); object->ProcessEvent(function, nullptr);
@@ -91,3 +76,45 @@ UEnhancedInputLocalPlayerSubsystem *UlxUtilityLibrary::GetEnhancedInputLocalPlay
} }
return nullptr; return nullptr;
} }
bool UlxUtilityLibrary::LineTraceThroughPixel(const APlayerController* PlayerController,
FVector2D PixelXY, double MaxDistanceFromCamera,
ETraceTypeQuery TraceChannel, bool bTraceComplex, EDrawDebugTrace::Type DrawDebugType, bool bIgnorePlayerPawn,
const TArray<AActor*>& ActorsToIgnore, FHitResult& HitResult)
{
const FLinearColor TraceColor = FLinearColor::Red;
const FLinearColor TraceHitColor = FLinearColor::Green;
const double DrawTime = 1.0;
// Zero out the return values.
HitResult.Init();
// Sanity check the distance.
if (MaxDistanceFromCamera <= 0.0)
{
return false;
}
// Make sure there's a player pawn.
AActor *PlayerPawn = PlayerController->GetPawn();
if (!PlayerPawn) return false;
// Calculate the trace start and trace end positions in world space.
FVector WorldStart, WorldDirection, WorldEnd;
if (!UGameplayStatics::DeprojectScreenToWorld(PlayerController, PixelXY, WorldStart, WorldDirection))
{
return false;
}
WorldEnd = WorldStart + (WorldDirection * MaxDistanceFromCamera);
// Find the hit.
if (UKismetSystemLibrary::LineTraceSingle(PlayerPawn, WorldStart, WorldEnd, TraceChannel, bTraceComplex,
ActorsToIgnore, DrawDebugType, HitResult, bIgnorePlayerPawn, TraceColor, TraceHitColor, DrawTime))
{
return true;
}
// Fail.
HitResult.Init();
return false;
}

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