114 lines
3.7 KiB
C
114 lines
3.7 KiB
C
|
|
////////////////////////////////////////////////////////////
|
||
|
|
//
|
||
|
|
// BreakToDebugger
|
||
|
|
//
|
||
|
|
// When an error message gets written to UE_LOG, we can
|
||
|
|
// optionally trigger the blueprint debugger.
|
||
|
|
//
|
||
|
|
// This only affects UE_LOG messages that are generated
|
||
|
|
// during blueprint execution. Log messages from other
|
||
|
|
// threads do not trigger the debugger.
|
||
|
|
//
|
||
|
|
// The following explains how we trigger the blueprint
|
||
|
|
// debugger on UE_LOG messages. Log messages are sent to a
|
||
|
|
// long list of output devices, including: the visual studio
|
||
|
|
// output window, the unreal editor output window, the log
|
||
|
|
// file, and so forth. We add another pseudo output device.
|
||
|
|
// This output device doesn't actually send the log message
|
||
|
|
// anywhere, instead, it just activates the blueprint
|
||
|
|
// debugger.
|
||
|
|
//
|
||
|
|
// UE_LOG messages can be generated from any thread. The
|
||
|
|
// pseudo output device checks what thread it is running in,
|
||
|
|
// and if it's not the blueprint thread, it does nothing at
|
||
|
|
// all. If it is the blueprint thread, it's safe to trigger
|
||
|
|
// the blueprint debugger.
|
||
|
|
//
|
||
|
|
// One annoying limitation of this design is that our output
|
||
|
|
// device ends up early in the list, so the debugger runs
|
||
|
|
// *before* the message shows up in visual studio or the
|
||
|
|
// unreal editor. As a result, when you are in the
|
||
|
|
// debugger, the message won't be in your output window.
|
||
|
|
// Pressing 'single step' always reveals the message.
|
||
|
|
//
|
||
|
|
// The blueprint node "Format Log Message" uses UE_LOG
|
||
|
|
// internally, so therefore, that too can trigger the
|
||
|
|
// blueprint debugger.
|
||
|
|
//
|
||
|
|
////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
#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 "BreakToDebugger.generated.h"
|
||
|
|
|
||
|
|
// ElxBreakToDebuggerThreshold:
|
||
|
|
//
|
||
|
|
// Controls the sensitivity level at which UE_LOG messages
|
||
|
|
// trigger the blueprint debugger.
|
||
|
|
//
|
||
|
|
UENUM(BlueprintType)
|
||
|
|
enum class ElxBreakToDebuggerThreshold : uint8 {
|
||
|
|
|
||
|
|
/* Break on errors. */
|
||
|
|
Error,
|
||
|
|
|
||
|
|
/* Break on warnings and above. */
|
||
|
|
Warning,
|
||
|
|
|
||
|
|
/* Break on display messages and above. */
|
||
|
|
Display,
|
||
|
|
|
||
|
|
/* Break on log messages and above. */
|
||
|
|
Log,
|
||
|
|
|
||
|
|
/* Break on verbose messages and above. */
|
||
|
|
Verbose,
|
||
|
|
|
||
|
|
/* Break on all messages. */
|
||
|
|
VeryVerbose,
|
||
|
|
|
||
|
|
/* Break on fatal errors only (ie, never break -- the process crashes instead). */
|
||
|
|
Fatal,
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
struct FlxBreakToDebuggerOutputDevice : 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 the LuprexGameMode 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.
|
||
|
|
//
|
||
|
|
FlxBreakToDebuggerOutputDevice(const ElxBreakToDebuggerThreshold &SensitivityRef);
|
||
|
|
~FlxBreakToDebuggerOutputDevice();
|
||
|
|
|
||
|
|
// 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:
|
||
|
|
static ELogVerbosity::Type ConvertThreshold(ElxBreakToDebuggerThreshold Verbosity);
|
||
|
|
const ElxBreakToDebuggerThreshold &Sensitivity;
|
||
|
|
};
|