Major overhaul of DebugPrint
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
using namespace DebugPrint;
|
||||
|
||||
AIntegrationGameModeBase::AIntegrationGameModeBase()
|
||||
{
|
||||
Thread = nullptr;
|
||||
@@ -19,6 +21,7 @@ AIntegrationGameModeBase::AIntegrationGameModeBase()
|
||||
//PrimaryActorTick.TickGroup = TG_PrePhysics; // Probably wrong
|
||||
SetActorTickEnabled(true);
|
||||
SetActorTickInterval(0.0f);
|
||||
DebugPrintControl::EnableCollection();
|
||||
}
|
||||
|
||||
AIntegrationGameModeBase::~AIntegrationGameModeBase()
|
||||
@@ -33,11 +36,11 @@ uint32 AIntegrationGameModeBase::Run()
|
||||
{
|
||||
bool triggered = ThreadEvent->Wait(3000);
|
||||
if (ThreadStopRequested) {
|
||||
engineutil::DPrint("Thread stopping as requested");
|
||||
DPrint("Thread stopping as requested");
|
||||
break;
|
||||
}
|
||||
if (!triggered) {
|
||||
engineutil::DPrint("Thread waiting a long time...");
|
||||
DPrint("Thread waiting a long time...");
|
||||
continue;
|
||||
}
|
||||
{
|
||||
@@ -111,7 +114,7 @@ void AIntegrationGameModeBase::Tick(float DeltaSeconds)
|
||||
HandleLuprexConsoleOutput(lockedwrap);
|
||||
}
|
||||
}
|
||||
TArray<FString> prints = engineutil::DPrintGetStored();
|
||||
TArray<FString> prints = DebugPrintControl::GetStored();
|
||||
for (const FString& fs : prints) {
|
||||
ConsoleOutput.AppendLine(fs);
|
||||
}
|
||||
@@ -168,7 +171,7 @@ void AIntegrationGameModeBase::BeginPlay()
|
||||
// If we failed to initialize the wrapper, print an error message.
|
||||
if (w->play_initialize == nullptr)
|
||||
{
|
||||
engineutil::DPrint("Luprex wrapper initialization failed");
|
||||
DPrint("Luprex wrapper initialization failed");
|
||||
}
|
||||
|
||||
// If wrapper is initialized, try to initialize the luprex engine.
|
||||
@@ -178,7 +181,7 @@ void AIntegrationGameModeBase::BeginPlay()
|
||||
std::string srcpakerr = drvutil::package_lua_source("c:\\Luprex", &srcpak);
|
||||
if (!srcpakerr.empty())
|
||||
{
|
||||
engineutil::DPrint(srcpakerr.c_str());
|
||||
DPrint(srcpakerr.c_str());
|
||||
}
|
||||
std::string_view srcpakv = srcpak.view();
|
||||
char* argv[1];
|
||||
@@ -186,11 +189,11 @@ void AIntegrationGameModeBase::BeginPlay()
|
||||
w->play_initialize(w.Get(), 1, argv, srcpakv.size(), srcpakv.data(), "");
|
||||
if (w->error[0])
|
||||
{
|
||||
engineutil::DPrint(w->error);
|
||||
DPrint(w->error);
|
||||
}
|
||||
else
|
||||
{
|
||||
engineutil::DPrint("Luprex initialize success");
|
||||
DPrint("Luprex initialize success");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
FTangibleManager TangibleManager;
|
||||
|
||||
// This stores the entire text currently visible in the console.
|
||||
engineutil::ConsoleOutput ConsoleOutput;
|
||||
FConsoleOutput ConsoleOutput;
|
||||
|
||||
// The worker thread.
|
||||
FRunnableThread *Thread;
|
||||
|
||||
@@ -13,7 +13,7 @@ void FLockedWrapper::InitWrapper() {
|
||||
InitFn init = (InitFn)FPlatformProcess::GetDllExport(DLL, TEXT("init_engine_wrapper"));
|
||||
if (init != nullptr) {
|
||||
init(&Lockable.Wrapper);
|
||||
Lockable.Wrapper.hook_dprint(engineutil::DPrintHook);
|
||||
Lockable.Wrapper.hook_dprint(DebugPrint::DPrint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "SocketSubsystem.h"
|
||||
#include "AddressInfoTypes.h"
|
||||
|
||||
using namespace DebugPrint;
|
||||
|
||||
#define UI UI_ST
|
||||
THIRD_PARTY_INCLUDES_START
|
||||
#include <openssl/ssl.h>
|
||||
@@ -903,7 +905,7 @@ void FLpxSocketsI::DPrintTrace()
|
||||
char* data;
|
||||
int ndata = BIO_get_mem_data(TraceBIO, &data);
|
||||
if (ndata == 0) return;
|
||||
engineutil::DPrintHook(data, ndata);
|
||||
DPrint(data, ndata);
|
||||
BIO_reset(TraceBIO);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,150 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "engineutil.hpp"
|
||||
|
||||
namespace engineutil {
|
||||
using DPrintCallback = DebugPrintControl::DPrintCallback;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DPrintState
|
||||
//
|
||||
// The global state of the DPrint routine. There is only
|
||||
// ever one of these, and it is owned by DPrintAccess below.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
struct DPrintState {
|
||||
// True if buffering is enabled.
|
||||
bool Collect;
|
||||
|
||||
// The array of buffered messages.
|
||||
TArray<FString> Messages;
|
||||
|
||||
// The array of callback functions.
|
||||
TArray<DPrintCallback> Callbacks;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// The DPrint array. This stores the dprints
|
||||
// until they can be collected by the console implementation.
|
||||
static TArray<FString> dprint_array;
|
||||
static FCriticalSection dprint_mutex;
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrint.
|
||||
//
|
||||
// This contains all the various versions of the DPrint routine.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void DPrint(const FString& fs) {
|
||||
FScopeLock lk(&dprint_mutex);
|
||||
dprint_array.Emplace(fs);
|
||||
}
|
||||
namespace DebugPrint {
|
||||
|
||||
void DPrint(const char* msg) {
|
||||
FScopeLock lk(&dprint_mutex);
|
||||
dprint_array.Emplace(msg);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
void DPrintHook(const char* msg, size_t len) {
|
||||
FScopeLock lk(&dprint_mutex);
|
||||
dprint_array.Emplace(len, (const UTF8CHAR*)msg);
|
||||
}
|
||||
// Alternative interface to the dispatcher.
|
||||
void DPrint(const char* msg) {
|
||||
DPrint(FString(msg));
|
||||
}
|
||||
|
||||
TArray<FString> DPrintGetStored() {
|
||||
FScopeLock lk(&dprint_mutex);
|
||||
TArray<FString> result = std::move(dprint_array);
|
||||
dprint_array.Empty();
|
||||
return result;
|
||||
}
|
||||
// Alternative interface to the dispatcher.
|
||||
void DPrint(const char* msg, size_t len) {
|
||||
DPrint(FString(len, (const UTF8CHAR*)msg));
|
||||
}
|
||||
|
||||
void ConsoleOutput::Append(const FString& text) {
|
||||
} // namespace DebugPrint
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrintControl.
|
||||
//
|
||||
// Configuration and control for the DPrint routine.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace DebugPrintControl {
|
||||
|
||||
// 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void FConsoleOutput::Append(const FString& text) {
|
||||
if (!text.IsEmpty()) {
|
||||
Content += text;
|
||||
Truncate();
|
||||
@@ -39,7 +152,7 @@ void ConsoleOutput::Append(const FString& text) {
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleOutput::AppendLine(const FString& text) {
|
||||
void FConsoleOutput::AppendLine(const FString& text) {
|
||||
int csize = Content.Len();
|
||||
if ((csize > 0) && (Content[csize - 1] != '\n')) {
|
||||
Content += TEXT("\n");
|
||||
@@ -50,7 +163,7 @@ void ConsoleOutput::AppendLine(const FString& text) {
|
||||
Dirty = true;
|
||||
}
|
||||
|
||||
void ConsoleOutput::Truncate() {
|
||||
void FConsoleOutput::Truncate() {
|
||||
int lines = 50;
|
||||
int csize = Content.Len();
|
||||
int total = 0;
|
||||
@@ -65,5 +178,3 @@ void ConsoleOutput::Truncate() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace engineutil
|
||||
|
||||
|
||||
@@ -1,24 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include "enginewrapper.hpp"
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Namespace DebugPrint
|
||||
//
|
||||
// This namespace contains the function "DPrint",
|
||||
// which is short for debugging print. This
|
||||
// is what you should use if you want to print
|
||||
// a debugging message.
|
||||
//
|
||||
// Messages printed using "DPrint" will
|
||||
// be routed to several destinations. These
|
||||
// might include a logfile, the unreal console,
|
||||
// and the visual studio debugging log.
|
||||
//
|
||||
// In order for "DPrint" to work, you have to
|
||||
// configure them once, at program initialization
|
||||
// time. This is done using the functions in
|
||||
// namespace DebugPrintConfig, below.
|
||||
//
|
||||
// We promise that namespace DebugPrint will
|
||||
// only ever contain one function, 'DPrint.'
|
||||
// that way, it's safe for you to put
|
||||
// 'using namespace DebugPrint' in your code.
|
||||
//
|
||||
// All DPrint-related functionality is
|
||||
// thread-safe. A single 'DPrint' is meant to
|
||||
// be output atomically.
|
||||
//
|
||||
// It is fine for the content of the DPrint
|
||||
// string to contain newlines.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
namespace engineutil {
|
||||
// Load the DLL and initialize the wrapper, if possible.
|
||||
void init_wrapper(EngineWrapper* w);
|
||||
namespace DebugPrint {
|
||||
// Print text into the debug log.
|
||||
void DPrint(const FString& fs);
|
||||
|
||||
// Print text on the console.
|
||||
void DPrint(const FString& fs);
|
||||
// Print text into the debug log.
|
||||
void DPrint(const char* msg);
|
||||
|
||||
// Print text on the console.
|
||||
void DPrint(const char* msg);
|
||||
// Print text into the debug log.
|
||||
void DPrint(const char* msg, size_t len);
|
||||
};
|
||||
|
||||
// Print text on the console.
|
||||
void DPrintHook(const char* msg, size_t len);
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// namespace DebugPrintControl
|
||||
//
|
||||
// This namespace contains the functions
|
||||
// necessary to initialize "DPrint", and
|
||||
// route its output to several destinations.
|
||||
//
|
||||
// "DPrint" is a callback-based design.
|
||||
// Initialization might consist of: register a
|
||||
// callback that sends a string to a logfile,
|
||||
// register another callback that sends a string
|
||||
// to visual studio's debug console, and register
|
||||
// a third one that sends a string to the
|
||||
// unreal console. Each time somebody calls
|
||||
// 'DPrint', all three callbacks will get invoked.
|
||||
//
|
||||
// There is also a 'collect' option where you
|
||||
// can ask "DPrint" to save the messages in a
|
||||
// buffer, which you can then collect at
|
||||
// your leisure. You can use buffering and
|
||||
// callbacks at the same time. Note that
|
||||
// buffering is inherently less than ideal for
|
||||
// messages that warn of imminent program aborts.
|
||||
// So it is recommended that you use at least one
|
||||
// callback that sends its output without delay.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// Get all the stored dprints.
|
||||
TArray<FString> DPrintGetStored();
|
||||
namespace DebugPrintControl {
|
||||
// The prototype for a callback function.
|
||||
//
|
||||
using DPrintCallback = void (*)(const FString& fs);
|
||||
|
||||
class ConsoleOutput {
|
||||
// Register a callback.
|
||||
//
|
||||
// Registering a callback that is already
|
||||
// registered is a no-op.
|
||||
//
|
||||
void RegisterCallback(DPrintCallback f);
|
||||
|
||||
// Enable collection in a buffer.
|
||||
//
|
||||
// If collection is already enabled, this is a no-op.
|
||||
//
|
||||
void EnableCollection();
|
||||
|
||||
// Collect all the stored messages, and clear the storage.
|
||||
//
|
||||
TArray<FString> GetStored();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ConsoleOutput
|
||||
//
|
||||
// This class stores the text that's in the unreal console.
|
||||
// It stores it as one great big string, which contains
|
||||
// newlines to denote line breaks.
|
||||
//
|
||||
// This class also contains a 'dirty' bit. Each time somebody
|
||||
// appends a line of text to the console, the dirty bit is
|
||||
// automatically set. The bit can be checked using 'IsDirty'
|
||||
// and cleared using 'ClearDirty'. This makes it so that
|
||||
// you don't have to update the unreal widget unless the
|
||||
// text has actually changed.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class FConsoleOutput {
|
||||
private:
|
||||
FString Content;
|
||||
bool Dirty;
|
||||
@@ -44,5 +139,3 @@ public:
|
||||
};
|
||||
|
||||
|
||||
} // namespace engineutil
|
||||
|
||||
|
||||
Reference in New Issue
Block a user