Now echoing Luprex console messages to the Unreal Log as well. Had to make them warnings in order to make them more visible, which in turn meant I had to modify the BreakToDebugger system to be able to ignore these console messages.

This commit is contained in:
2026-06-10 17:20:45 -04:00
parent 0b5c47d8c7
commit f7e9305d64
11 changed files with 70 additions and 39 deletions

Binary file not shown.

View File

@@ -2,6 +2,7 @@
#include "BreakToDebugger.h" #include "BreakToDebugger.h"
#include "Blueprint/BlueprintExceptionInfo.h" #include "Blueprint/BlueprintExceptionInfo.h"
#include "Kismet2/KismetDebugUtilities.h" #include "Kismet2/KismetDebugUtilities.h"
#include "LuprexEditorSettings.h"
ELogVerbosity::Type FlxBreakToDebuggerOutputDevice::ConvertThreshold(ElxBreakToDebuggerThreshold Verbosity) { ELogVerbosity::Type FlxBreakToDebuggerOutputDevice::ConvertThreshold(ElxBreakToDebuggerThreshold Verbosity) {
switch (Verbosity) { switch (Verbosity) {
@@ -15,8 +16,8 @@ ELogVerbosity::Type FlxBreakToDebuggerOutputDevice::ConvertThreshold(ElxBreakToD
} }
} }
FlxBreakToDebuggerOutputDevice::FlxBreakToDebuggerOutputDevice(const ElxBreakToDebuggerThreshold &SensitivityRef) FlxBreakToDebuggerOutputDevice::FlxBreakToDebuggerOutputDevice()
: Sensitivity(SensitivityRef) : Settings(GetDefault<UlxEditorSettings>())
{ {
GLog->AddOutputDevice(this); GLog->AddOutputDevice(this);
} }
@@ -48,7 +49,7 @@ void FlxBreakToDebuggerOutputDevice::Serialize(const TCHAR* V, ELogVerbosity::Ty
{ {
// If the error isn't serious enough, do nothing. // If the error isn't serious enough, do nothing.
// //
if (Verbosity > ConvertThreshold(Sensitivity)) if (Verbosity > ConvertThreshold(Settings->BreakToDebuggerLogVerbosity))
{ {
return; return;
} }
@@ -67,6 +68,13 @@ void FlxBreakToDebuggerOutputDevice::Serialize(const TCHAR* V, ELogVerbosity::Ty
UObject *TopObject = Frame->Object; UObject *TopObject = Frame->Object;
if (TopObject == nullptr) return; if (TopObject == nullptr) return;
// If the category is in the exclude list, do nothing.
//
if (Settings->BreakToDebuggerExcludeCategories.Contains(Category))
{
return;
}
// Notify the debugger that there's been an exception. // Notify the debugger that there's been an exception.
// //
FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::Breakpoint, FText::FromStringView(FStringView(V))); FBlueprintExceptionInfo ExceptionInfo(EBlueprintExceptionType::Breakpoint, FText::FromStringView(FStringView(V)));

View File

@@ -79,19 +79,15 @@ enum class ElxBreakToDebuggerThreshold : uint8 {
}; };
class UlxEditorSettings;
struct FlxBreakToDebuggerOutputDevice : public FOutputDevice struct FlxBreakToDebuggerOutputDevice : public FOutputDevice
{ {
public: public:
// The constructor and destructor automatically register // The constructor and destructor automatically register
// this output device with GLog. // this output device with GLog.
// //
// This struct doesn't store the sensitivity threshold. FlxBreakToDebuggerOutputDevice();
// 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(); ~FlxBreakToDebuggerOutputDevice();
// Inspect a log message. // Inspect a log message.
@@ -109,5 +105,5 @@ public:
private: private:
static ELogVerbosity::Type ConvertThreshold(ElxBreakToDebuggerThreshold Verbosity); static ELogVerbosity::Type ConvertThreshold(ElxBreakToDebuggerThreshold Verbosity);
const ElxBreakToDebuggerThreshold &Sensitivity; const UlxEditorSettings *Settings = nullptr;
}; };

View File

@@ -2,3 +2,4 @@
DEFINE_LOG_CATEGORY(LogLuprex); DEFINE_LOG_CATEGORY(LogLuprex);
DEFINE_LOG_CATEGORY(LogLuprexIntegration); DEFINE_LOG_CATEGORY(LogLuprexIntegration);
DEFINE_LOG_CATEGORY(LogLuprexConsole);

View File

@@ -153,3 +153,7 @@ DECLARE_LOG_CATEGORY_EXTERN(LogLuprex, Display, All);
// Messages about the Luprex integration with Unreal. // Messages about the Luprex integration with Unreal.
// //
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All); DECLARE_LOG_CATEGORY_EXTERN(LogLuprexIntegration, Display, All);
// Messages from the Luprex console.
//
DECLARE_LOG_CATEGORY_EXTERN(LogLuprexConsole, Display, All);

View File

@@ -1 +1,7 @@
#include "LuprexEditorSettings.h" #include "LuprexEditorSettings.h"
#include "Common.h"
UlxEditorSettings::UlxEditorSettings()
{
BreakToDebuggerExcludeCategories.Add(LogLuprexConsole.GetCategoryName());
}

View File

@@ -25,6 +25,8 @@ class INTEGRATION_API UlxEditorSettings : public UDeveloperSettings
GENERATED_BODY() GENERATED_BODY()
public: public:
UlxEditorSettings();
virtual FName GetContainerName() const override { return TEXT("Editor"); } virtual FName GetContainerName() const override { return TEXT("Editor"); }
virtual FName GetCategoryName() const override { return TEXT("Luprex"); } virtual FName GetCategoryName() const override { return TEXT("Luprex"); }
virtual FName GetSectionName() const override { return TEXT("Settings"); } virtual FName GetSectionName() const override { return TEXT("Settings"); }
@@ -39,5 +41,9 @@ public:
// severity, the blueprint debugger will automatically pause with a breakpoint. // severity, the blueprint debugger will automatically pause with a breakpoint.
UPROPERTY(Config, EditAnywhere, Category="Debugging Tools") UPROPERTY(Config, EditAnywhere, Category="Debugging Tools")
ElxBreakToDebuggerThreshold BreakToDebuggerLogVerbosity; ElxBreakToDebuggerThreshold BreakToDebuggerLogVerbosity;
// Log categories in this set are excluded from BreakToDebugger triggering.
UPROPERTY(Config, EditAnywhere, Category="Debugging Tools")
TSet<FName> BreakToDebuggerExcludeCategories;
}; };

View File

@@ -238,7 +238,7 @@ void ALuprexGameModeBase::InitializeGlobalState()
// If somebody generates a log message that's severe enough, break to debugger. // If somebody generates a log message that's severe enough, break to debugger.
BreakToDebuggerLogVerbosityDevice.Reset( BreakToDebuggerLogVerbosityDevice.Reset(
new FlxBreakToDebuggerOutputDevice(GetDefault<UlxEditorSettings>()->BreakToDebuggerLogVerbosity)); new FlxBreakToDebuggerOutputDevice());
} }
void ALuprexGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) void ALuprexGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)

View File

@@ -242,3 +242,8 @@ void UlxUtilityLibrary::ValidateLuaExpr(
Status = w.ValidateLuaExpr(Code, ErrorMessage); Status = w.ValidateLuaExpr(Code, ErrorMessage);
} }
void UlxUtilityLibrary::LogLuprexConsoleMessage(const FString &Message)
{
UE_LOG(LogLuprexConsole, Warning, TEXT("%s"), *Message);
}

View File

@@ -144,4 +144,9 @@ public:
// //
UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Utility") UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Utility")
static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code); static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code);
// Log a message to the LogLuprexConsole category.
//
UFUNCTION(BlueprintCallable, Category = "Luprex|Utility")
static void LogLuprexConsoleMessage(const FString &Message);
}; };

View File

@@ -35,7 +35,7 @@ end
function login.init(self, config) function login.init(self, config)
local player = global.get("nextplayer") local player = global.get("nextplayer")
global.set("nextplayer", player + 1) global.set("nextplayer", player + 1)
dprintf("login.init initializing %p, player %d", self, player) printf("login.init initializing %p, player %d", self, player)
self.player = player self.player = player
self.color={0,0,0,0,0,0,0,0,0,0,0,0} self.color={0,0,0,0,0,0,0,0,0,0,0,0}
self.kills=0 self.kills=0
@@ -45,7 +45,7 @@ function login.init(self, config)
end end
function login.startscanning() function login.startscanning()
dprintf("Scanning started. Actor=%p Place=%p", actor, place) printf("Scanning started. Actor=%p Place=%p", actor, place)
while true do while true do
login.onescan() login.onescan()
wait(1) wait(1)
@@ -75,7 +75,7 @@ end
-- This gets called on the admin user. You can call login.init in here if you want. -- This gets called on the admin user. You can call login.init in here if you want.
function world.init(self, config) function world.init(self, config)
dprint("world.init") print("world.init")
global.set("nextplayer", 0) global.set("nextplayer", 0)
tangible.build{class=roster, anim={plane="earth", xyz={2000,0,0} } } tangible.build{class=roster, anim={plane="earth", xyz={2000,0,0} } }
tangible.build{class=cube, anim={plane="earth", xyz={500,-100,0}, mat_color={1,0,0}}} tangible.build{class=cube, anim={plane="earth", xyz={500,-100,0}, mat_color={1,0,0}}}
@@ -89,7 +89,7 @@ function roster.init(self,config)
end end
function world.buildpylon() function world.buildpylon()
dprint("Building pylon") print("Building pylon")
local radius=1000 local radius=1000
tangible.build{class=pylon,plane="earth",xyz={math.random(-radius,radius),math.random(-radius,radius),0}}.color=math.random(1,12) tangible.build{class=pylon,plane="earth",xyz={math.random(-radius,radius),math.random(-radius,radius),0}}.color=math.random(1,12)
end end
@@ -110,29 +110,29 @@ end
-- Four cases: Unnamed to new, Unnamed to existing, Named to new, Named to Existing -- Four cases: Unnamed to new, Unnamed to existing, Named to new, Named to Existing
function playas(who) function playas(who)
dprintf("Playas %lP",place) printf("Playas %lP",place)
if not actor.name and not place.character[who] then -- Unnamed to new if not actor.name and not place.character[who] then -- Unnamed to new
dprintf("Case 1: Naming this character "..who) printf("Case 1: Naming this character "..who)
actor.name=who actor.name=who
tangible.keepactor(actor) tangible.keepactor(actor)
place.character[who]=actor place.character[who]=actor
elseif actor.name and not place.character[who] then -- Named to new (Hard one) elseif actor.name and not place.character[who] then -- Named to new (Hard one)
dprintf("Case 2: Creating new character "..who) printf("Case 2: Creating new character "..who)
dprintf("Case 2.0") printf("Case 2.0")
local nc=tangible.build{class=login, anim={plane="earth", xyz={0,0,0} } } local nc=tangible.build{class=login, anim={plane="earth", xyz={0,0,0} } }
dprintf("Case 2.1") printf("Case 2.1")
nc.name=who nc.name=who
dprintf("Case 2.2") printf("Case 2.2")
tangible.keepactor(nc) tangible.keepactor(nc)
dprintf("Case 2.3") printf("Case 2.3")
place.character[who]=nc place.character[who]=nc
dprintf("Case 2.4: ...Place is now "..place) printf("Case 2.4: ...Place is now "..place)
tangible.redirect(actor,nc) tangible.redirect(actor,nc)
elseif not actor.name and place.character[who] then elseif not actor.name and place.character[who] then
dprintf("Case 3: Logging in from unnamed to existing character "..who) printf("Case 3: Logging in from unnamed to existing character "..who)
tangible.redirect(actor,place.character[who]) tangible.redirect(actor,place.character[who])
elseif actor.name and place.character[who] then elseif actor.name and place.character[who] then
dprintf("Case 4: Logging in from "..actor.name.." to existing character "..who) printf("Case 4: Logging in from "..actor.name.." to existing character "..who)
tangible.redirect(actor,place.character[who]) tangible.redirect(actor,place.character[who])
end end
end end
@@ -144,24 +144,24 @@ function roster.lookmenu(add)
end end
function cube.lookmenu(add) function cube.lookmenu(add)
add("Cube A", function () dprint("Doing Cube A") end) add("Cube A", function () print("Doing Cube A") end)
add("Cube B", function () dprint("Doing Cube B") end) add("Cube B", function () print("Doing Cube B") end)
add("Cube C", function () dprint("Doing Cube C") end) add("Cube C", function () print("Doing Cube C") end)
add("Cube Hi", function () dprint("Doing Cube Hi") end) add("Cube Hi", function () print("Doing Cube Hi") end)
add("Cube Bye", function () dprint("Doing Cube Bye") end) add("Cube Bye", function () print("Doing Cube Bye") end)
add("Cube Yo", function () dprint("Doing Cube Yo") end) add("Cube Yo", function () print("Doing Cube Yo") end)
add("Cube Z", function () dprint("Doing Cube Z") end) add("Cube Z", function () print("Doing Cube Z") end)
end end
function sphere.lookhotkeys(add) function sphere.lookhotkeys(add)
add("FaceL", "Sphere Hi", function () dprint("Doing Sphere Hi") end) add("FaceL", "Sphere Hi", function () print("Doing Sphere Hi") end)
add("FaceM", "Sphere Bye", function () dprint("Doing Sphere Bye") end) add("FaceM", "Sphere Bye", function () print("Doing Sphere Bye") end)
add("FaceR", "Sphere Yo", function () dprint("Doing Sphere Yo") end) add("FaceR", "Sphere Yo", function () print("Doing Sphere Yo") end)
end end
function sphere.tick(foo) function sphere.tick(foo)
dprint("Tick") print("Tick")
end end