lxGameMode can now trap UE_LOG Error into the debugger
This commit is contained in:
BIN
Content/Luprex/lxGameMode.uasset
LFS
Executable file → Normal file
BIN
Content/Luprex/lxGameMode.uasset
LFS
Executable file → Normal file
Binary file not shown.
Binary file not shown.
@@ -81,8 +81,9 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
|
||||
bChanged = false;
|
||||
Action = TEXT("");
|
||||
|
||||
if (prefix.IsEmpty()) {
|
||||
UlxUtilityLibrary::Assert(false, TEXT("You may not pass an empty string for prefix"));
|
||||
if (prefix.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogBlueprint, Error, TEXT("UnpackAnimationStep: You may not pass an empty string for prefix"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,8 +93,7 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
|
||||
|
||||
FStructProperty* stepproperty = FindAnimationStepProperty(uclass, prefix);
|
||||
if (stepproperty == nullptr) {
|
||||
UE_LOG(LogBlueprint, Error, TEXT("Target object: %s Prefix: %s"), *(target->GetName()), *prefix);
|
||||
UlxUtilityLibrary::Assert(false, TEXT("Target object does not have an variable named '<prefix> Animation Step'"));
|
||||
UE_LOG(LogBlueprint, Error, TEXT("UnpackAnimationStep: Target object does not have a variable named: '%s Animation Step'"), *prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
137
Source/Integration/BlueprintErrors.cpp
Normal file
137
Source/Integration/BlueprintErrors.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
181
Source/Integration/BlueprintErrors.h
Normal file
181
Source/Integration/BlueprintErrors.h
Normal 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;
|
||||
};
|
||||
@@ -15,12 +15,10 @@
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "HAL/PlatformCrt.h"
|
||||
#include "Internationalization/Internationalization.h"
|
||||
#include "Internationalization/TextFormatter.h"
|
||||
#include "K2Node_CallFunction.h"
|
||||
#include "K2Node_MakeArray.h"
|
||||
#include "K2Node_MakeStruct.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include "Kismet/KismetTextLibrary.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "Kismet2/CompilerResultsLog.h"
|
||||
@@ -115,7 +113,7 @@ void UK2Node_FormatError::CreateCorrectPins()
|
||||
}
|
||||
|
||||
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->AutogeneratedDefaultValue = P->DefaultValue;
|
||||
}
|
||||
@@ -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.
|
||||
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->AllocateDefaultPins();
|
||||
CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFormatFunction, this);
|
||||
@@ -608,75 +606,5 @@ FText UK2Node_FormatError::GetMenuCategory() const
|
||||
return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::Text);
|
||||
}
|
||||
|
||||
void UlxFormatErrorLibrary::FormatErrorInternal(UObject *Context, ElxLogVerbosity Verbosity, ElxDisplayDuration 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
//
|
||||
if (VerbosityValue <= ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY)
|
||||
{
|
||||
FMsg::Logf(BlueprintNameAnsi.Get(), 0, BlueprintNameLogCategory, VerbosityValue, TEXT("%s"), *MessageString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlueprintErrors.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
@@ -12,6 +13,7 @@
|
||||
#include "UObject/NameTypes.h"
|
||||
#include "UObject/ObjectMacros.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
#include "BlueprintErrors.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_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,
|
||||
};
|
||||
|
||||
//
|
||||
// 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, const FString &InPattern, TArray<FFormatArgumentData> InArgs);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The Format Error Message K2Node.
|
||||
//
|
||||
|
||||
@@ -77,6 +77,9 @@ void AIntegrationGameModeBase::ResetToInitialState()
|
||||
w->release(w.Get());
|
||||
}
|
||||
|
||||
// Stop trapping log errors to the debugger.
|
||||
BreakToDebuggerLogVerbosityDevice.Reset();
|
||||
|
||||
// Clear the lua call assembly buffer.
|
||||
LuaCallBuffer.clear();
|
||||
|
||||
@@ -316,6 +319,10 @@ void AIntegrationGameModeBase::BeginPlay()
|
||||
// Initialize the tangible manager.
|
||||
TangibleManager = NewObject<UlxTangibleManager>();
|
||||
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)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "TangibleManager.h"
|
||||
#include "LuprexSockets.h"
|
||||
#include "TriggeredTask.h"
|
||||
#include "BlueprintErrors.h"
|
||||
#include "IntegrationGameModeBase.generated.h"
|
||||
|
||||
|
||||
@@ -118,6 +119,10 @@ public:
|
||||
UPROPERTY()
|
||||
AActor *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.
|
||||
FlxConsoleOutput ConsoleOutput;
|
||||
|
||||
@@ -150,4 +155,7 @@ public:
|
||||
// These allow us to pre-tick and post-tick.
|
||||
FDelegateHandle OnWorldPreActorTickHandle;
|
||||
FDelegateHandle OnWorldPostActorTickHandle;
|
||||
|
||||
// The device that implements BreakToDebuggerLogVerbosity, above.
|
||||
TUniquePtr<FlxDebugBlueprintErrorsOutputDevice> BreakToDebuggerLogVerbosityDevice;
|
||||
};
|
||||
|
||||
@@ -7,21 +7,11 @@
|
||||
|
||||
#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) {
|
||||
FString fullname = namepart1 + namepart2;
|
||||
if (!IsValid(object)) {
|
||||
const FBlueprintExceptionInfo ExceptionInfo(
|
||||
EBlueprintExceptionType::FatalError,
|
||||
LOCTEXT("CallFunctionByName_ObjectIsNotValid", "In CallFunctionByName, object passed in is not valid.")
|
||||
);
|
||||
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
|
||||
UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, object passed in is not valid."));
|
||||
return;
|
||||
}
|
||||
UFunction* function = object->FindFunction(FName(*fullname));
|
||||
@@ -31,20 +21,12 @@ void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namep
|
||||
if (!bFailIfNotFound) {
|
||||
return;
|
||||
}
|
||||
const FBlueprintExceptionInfo ExceptionInfo(
|
||||
EBlueprintExceptionType::FatalError,
|
||||
LOCTEXT("CallFunctionByName_NoSuchFunction", "In CallFunctionByName, cannot find the named function or the fallback function.")
|
||||
);
|
||||
FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo);
|
||||
UE_LOG(LogBlueprint, Error, TEXT("In CallFunctionByName, cannot find the named function or the fallback function"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (function->ParmsSize != 0) {
|
||||
const FBlueprintExceptionInfo ExceptionInfo(
|
||||
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);
|
||||
UE_LOG(LogBlueprint, Error, TEXT("CallFunctionByName can only call functions that have no parameters and no return values"));
|
||||
return;
|
||||
}
|
||||
object->ProcessEvent(function, nullptr);
|
||||
|
||||
@@ -20,11 +20,6 @@ class INTEGRATION_API UlxUtilityLibrary : public UObject
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
// If condition is false, quit the game, reporting an error message to the log.
|
||||
//
|
||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Utility")
|
||||
static void Assert(bool condition, const FString &ErrorMessage);
|
||||
|
||||
// Call a function by name, on any UObject. If the function doesn't exist, calls
|
||||
// the fallback function instead. If that isn't found either, returns false.
|
||||
|
||||
Reference in New Issue
Block a user