This guide describes a Widget to replicate what the development-only PrintString node does. In other words, it prints text to the screen. This can be very useful when debugging mods.
A Widget is something that puts stuff on the screen. It's as simple as that. To give you an idea what I mean, here's the Debug Widget in action:
Regular readers will know that I included a Debug Widget in the previous tutorial (regarding the MyDemiguiseFinder mod), but said I'd describe how it worked in this one. I'm actually not going to do that. I'm going to describe how a better Debug Widget works. The one I included with MyDemiguiseFinder was a brute-force caveman solution that I came up with because I couldn't see an easier way to do it. The obvious way would have been to use a Multi-line Editable Text Box but I couldn't find any Blueprint Nodes to change the text inside one of those so I assumed it couldn't be done. It turns out I just didn't look hard enough. (Sometimes the Level Blueprint search utility can be a little tricky to master.) I subsequently discovered a Debug Widget by Narknon on the Hogwarts Legacy Modding Discord which more-or-less did exactly what I wanted. Even better, it did it in a way that was far superior to the solution I came up with. In particular, it handles scrolling for you, and allows you to reposition and/or resize the debug window real-time.
You can find Narknon's original Widget here, but I will be using a tailored version in this tutorial so you don't need to download that one.
Download an updated version of
MyDemiguiseFinderhere andMyDebugWidgethere.
Please note that:
Blueprint Apparate Modloader. Your game will get stuck when you fast-travel if you do. This is because all Levels get unloaded and re-loaded when you fast-travel. When the game tries to load your Widget as a Level it will wait forever for the Level to fire up… because the widget doesn't contain a Level.MyDemiguiseFinder you'll be able to use the same Widget for all your mods - they can all write to the same Widget !!!Widget yourself, if you want to annotate the debug info, or cut-and-paste the contents into a file.Yes, you're right. That is genius!
All the usual prerequisites apply at this point. I won't keep repeating them. But if you're a beginner and you haven't read the previous tutorials you should. You'll struggle to follow this one if you don't.
The Event Graph looks quite different to the previous version of MyDemiguiseFinder. I was able to remove all the key-bindings related to scrolling, because that's all handled by the Widget now. Here's how it breaks down:
Debug Widget is named MyDebug-something to keep them distinct from everything else.Event BeginPlay is triggered when the mod loads. It sets up the name of the mod in a String Variable called MyModName. This is an improvement which I forgot to mentioned in the last tutorial. Whenever you create a new mod you can simply copy an old one, change this variable, and you're good to go with all your usual Functions and Events already in place. This Variable is also used to indicate which mod a particular Debug message came from. Since we're planning to use the same Widget for all our mods, this will be important.MyDebugGetWidget is called to set up the Debug Widget. This happens before Initialize is called because Initialize uses the Debug Widget to report any errors.MyDebugPrintString nodes. These print a String to the Debug Widget. You'll also see some others like MyDebugMarkers and MyDebugBeaconArray. These are custom Functions I've created to display the contents of some internal Arrays. We'll cover these in more detail later.Toggle the Debug Window On and Off. This looks quite complicated, but it's really not. Ctrl-Alt-Home is the key combination I chose to call the Event that makes the Debug Widget appear and disappear, but you can choose something else if you like. The Event works like this:Gets the Variable MyDebugWidget . I declared this Variable to be of Class MyDebugWidget when I created it. This is a Class that will become available once the Widget is created in (or loaded into) your CustomContent folder. The node that Gets it also checks that MyDebugWidget is Valid. If it's not then MyDebugGetWidget failed to set-up the Debug Widget (probably because the Widget files are missing) so the Widget doesn't exist. In which case there's nothing to do and the Event ends.Get Node into a Validated Get simply right-click on the Get Node and select Convert to Validated Get.MyDebug Variable is TRUE and the Widget is Visible then it's made Invisible. And vice-versa. The Input Mode is also set up to allow/disallow the user to use the Cursor and the Cursor is made Visible or Invisible.
This Function spawns a Widget called MyDebugWidget (if one doesn't already exist) otherwise it just sets Variable MyDebugWidget to point to the Widget that's already been spawned (presumably by another one of your mods).
This Function actually does the spawning. If it succeeds it adds the Widget to the Viewport (i.e. screen).
Most of this Function is actually dedicated to creating a timestamp. The business of adding the String to the DebugWidget is handled by that final node. Note that the Target is MyDebugWidget, meaning that this Node is actually calling a Event inside MyDebugWidget not an Event inside this mod. To add a Node like this you need to search for the name and then select the one that's listed underneath the Heading that corresponds to the Asset in which that Function resides (as shown in the screenshot). You may need to untick Context Sensitive before it will appear.
There's an array inside the game called Beacon Info Array. I wanted to know what was inside that Array. This is how I found out.
And this is how I printed out just the Waymarker and Locator Beacons: I looped through all the Beacons and printed out the ones I wanted.
Now we'll move on to discussing the actual Widget.
I'm not going to go into much detail about how to create this. By now you should be familiar enough with the Editor that you can figure it out, and there's lots of info online. But to summarise…
In your CustomContent Folder right-click and select User Interface > Widget Blueprint:
Then:
Designer search for the items you want (top left arrow) and drag them down to the Hierarchy section below.Hierarchy order is important - it determines what goes in front of what, and what properties get inherited.Canvas (if there isn't one already present) and add stuff to it. There are lots of tutorials on YouTube about this.MyDebugWidget for clues about what's what. The type of each item is show in the top right (top right box).Font in the TextBox from Bold to Regular and Size from 16 to 10. I also changed the Font colour to Yellow with Opacity A of 1.0.Button Text (like the x top right) I used an Opacity A of 0.5.Is Variable box in the top right (circled in green). This will give us access to those elements in the Widget's Graph section (where we add Events and Functions).
There are seven sections to the Event Graph. Again I won't go into details (you can find lots of info online) but in summary:
Debug Widget.Buttons (to yellow) when your mouse hovers over them.Events like those, select an object in the Hierarchy then scroll to the bottom of the Details window. You'll find a load of Green Buttons you can click to add Events.Add Text comment box contains an AddTextEvent which actually adds text to the Debug Widget by calling the AddText Macro. (Don't worry about what a Macro is right now. We'll discuss it at a later date. Like a Function or an Event a Macro can be called to do stuff. And like those it has its strengths and weaknesses.)AddTextEvent is what was called by MyDebugPrintString in our mod. So this is how text gets from our mod to this widget.Close Button box just makes the Debug Widget Invisible when the user clicks on the x.
The AddText Macro actually adds text to the Debug Widget, as follows:
GetText (Multi-Line Editable Text).Append a newline to it (which you produce by hitting SHIFT-Enter in the little box beside Append Input B).Append whatever text was provided as an Input.SetText (Multi-Line Editable Text).Delay (i.e. wait) for 0.01 seconds, to be sure that completed.Scroll to End with the Scroll Box (in which the Multi-Line Editable Text Box resides) as the Target.
This Macro just prevents the user from making the Debug Widget too small:
That's it! As usual, the actual “meat” of the thing is quite limited. Most of the work went into setting up the supporting infrastructure.
In case you missed it, the Debug Widget works like this:
MyDebugPrintString Function inside our mod calls AddTextEvent inside the Widget, with the text we want to print as the input.AddTextEvent calls the AddText Macro with the same input.AddText Macro gets the existing text, adds a newline, adds the new text, and updates the Widget.Simple.
The great thing about this is that because the text is stored inside the Widget (rather than inside an Array inside our mod, like it was with my original version of MyDebugWidget) and it's updated via a Macro inside the Widget, any number of mods can send text to the widget and it will simply store them all in one place!
Many thanks to Narknon, who created the original PrintDebugWidget (upon which my version MyDebugWidget is based). I say “based”… but it's 95% Narknon's widget with 5% cosmetic changes by me… so I claim no credit for it, but I accept all the blame if I broke something. I also accept the blame if anyone dislikes the way I lay out my Blueprints. That's all me. Narknon does theirs differently. (In my defence, I have to pack as much as I can into a single screenshot. That's not why I do it, admittedly. I do it because I like this compact format. But screenshots are my excuse for sticking with it.)