2023-09-04 03:27:31 -04:00
|
|
|
#include "DebugPrint.h"
|
2023-06-08 17:10:14 -04:00
|
|
|
#include "CoreMinimal.h"
|
|
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
using DPrintCallback = DebugPrintControl::DPrintCallback;
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// DPrintState
|
|
|
|
|
//
|
|
|
|
|
// The global state of the DPrint routine. There is only
|
|
|
|
|
// ever one of these, and it is owned by DPrintAccess below.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
struct DPrintState {
|
|
|
|
|
// True if buffering is enabled.
|
|
|
|
|
bool Collect;
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
// The array of buffered messages.
|
|
|
|
|
TArray<FString> Messages;
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
// The array of callback functions.
|
|
|
|
|
TArray<DPrintCallback> Callbacks;
|
|
|
|
|
};
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// DPrintAccess
|
|
|
|
|
//
|
|
|
|
|
// This class grants you safe access to the global state
|
|
|
|
|
// of the DPrint routine. Constructing an object of
|
|
|
|
|
// class DPrintAccess will lock the global mutex and make
|
|
|
|
|
// sure that the DPrintState is initialized. Then it will
|
|
|
|
|
// give you unrestricted access to the DPrintState through
|
|
|
|
|
// operator right arrow.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
class DPrintAccess {
|
|
|
|
|
private:
|
|
|
|
|
// The Mutex that protects the global state.
|
|
|
|
|
static FCriticalSection Mutex;
|
|
|
|
|
|
|
|
|
|
// The Global State. A pointer, to avoid static init issues.
|
|
|
|
|
static DPrintState* State;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// Constructor. Locks mutex and initializes state if necessary.
|
|
|
|
|
DPrintAccess() {
|
|
|
|
|
Mutex.Lock();
|
|
|
|
|
if (State == nullptr) {
|
|
|
|
|
State = new DPrintState;
|
|
|
|
|
State->Collect = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Destructor. Releases mutex.
|
|
|
|
|
~DPrintAccess() {
|
|
|
|
|
Mutex.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Access the DPrintState.
|
|
|
|
|
DPrintState* operator ->() {
|
|
|
|
|
return State;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FCriticalSection DPrintAccess::Mutex;
|
|
|
|
|
DPrintState* DPrintAccess::State;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Namespace DebugPrint.
|
|
|
|
|
//
|
|
|
|
|
// This contains all the various versions of the DPrint routine.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
namespace DebugPrint {
|
|
|
|
|
|
|
|
|
|
// DPrint. Invoke all the callbacks, and store the message.
|
|
|
|
|
void DPrint(const FString& fs) {
|
|
|
|
|
DPrintAccess state;
|
|
|
|
|
for (DPrintCallback cb : state->Callbacks) {
|
|
|
|
|
cb(fs);
|
|
|
|
|
}
|
|
|
|
|
if (state->Collect) {
|
|
|
|
|
state->Messages.Emplace(fs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Alternative interface to the dispatcher.
|
|
|
|
|
void DPrint(const char* msg) {
|
|
|
|
|
DPrint(FString(msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Alternative interface to the dispatcher.
|
|
|
|
|
void DPrint(const char* msg, size_t len) {
|
|
|
|
|
DPrint(FString(len, (const UTF8CHAR*)msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace DebugPrint
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Namespace DebugPrintControl.
|
|
|
|
|
//
|
|
|
|
|
// Configuration and control for the DPrint routine.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
namespace DebugPrintControl {
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-04 03:21:23 -04:00
|
|
|
// Register a callback. Check for duplication.
|
|
|
|
|
void RegisterCallback(DPrintCallback cb) {
|
|
|
|
|
DPrintAccess state;
|
|
|
|
|
for (DPrintCallback old : state->Callbacks) {
|
|
|
|
|
if (cb == old) return;
|
|
|
|
|
}
|
|
|
|
|
state->Callbacks.Add(cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the collection bit in the global state.
|
|
|
|
|
void EnableCollection() {
|
|
|
|
|
DPrintAccess state;
|
|
|
|
|
state->Collect = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the array of collected messages, if any.
|
|
|
|
|
TArray<FString> GetStored() {
|
|
|
|
|
DPrintAccess state;
|
|
|
|
|
TArray<FString> result = std::move(state->Messages);
|
|
|
|
|
state->Messages.Empty();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// ConsoleOutput
|
|
|
|
|
//
|
|
|
|
|
// Storing the text that goes in the unreal console.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-06-08 17:10:14 -04:00
|
|
|
|
2023-09-15 13:28:18 -04:00
|
|
|
void FlxConsoleOutput::Truncate() {
|
2023-06-08 17:10:14 -04:00
|
|
|
int lines = 50;
|
|
|
|
|
int csize = Content.Len();
|
|
|
|
|
int total = 0;
|
|
|
|
|
for (int i = csize - 1; i >= 0; i--) {
|
|
|
|
|
if (Content[i] == '\n') {
|
|
|
|
|
total += 1;
|
|
|
|
|
if (total == lines) {
|
|
|
|
|
Content = Content.RightChop(i + 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 13:28:18 -04:00
|
|
|
bool FlxConsoleOutput::MaybeAppendNewline() {
|
2023-09-05 03:20:11 -04:00
|
|
|
int csize = Content.Len();
|
|
|
|
|
if ((csize > 0) && (Content[csize - 1] != '\n')) {
|
|
|
|
|
Content += TEXT("\n");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 13:28:18 -04:00
|
|
|
bool FlxConsoleOutput::MaybeAppendText(const FString& text) {
|
2023-09-05 03:20:11 -04:00
|
|
|
if (!text.IsEmpty()) {
|
|
|
|
|
Content += text;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 13:28:18 -04:00
|
|
|
void FlxConsoleOutput::Append(const FString& text) {
|
2023-09-05 03:20:11 -04:00
|
|
|
bool modified = MaybeAppendText(text);
|
|
|
|
|
if (modified) {
|
|
|
|
|
Dirty = true;
|
|
|
|
|
Truncate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 13:28:18 -04:00
|
|
|
void FlxConsoleOutput::AppendLine(const FString& text) {
|
2023-09-05 03:20:11 -04:00
|
|
|
bool modified = MaybeAppendNewline();
|
|
|
|
|
modified |= MaybeAppendText(text);
|
|
|
|
|
modified |= MaybeAppendNewline();
|
|
|
|
|
if (modified) {
|
|
|
|
|
Dirty = true;
|
|
|
|
|
Truncate();
|
|
|
|
|
}
|
|
|
|
|
}
|