#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" 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 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 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) { 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); }