Files
integration/Source/Integration/BlueprintErrors.cpp

287 lines
9.4 KiB
C++

#include "BlueprintErrors.h"
#include "LuaCall.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, 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();
// 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 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::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 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<const UEnum>(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)
{
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);
}