### Handling Print Statements This document describes how "print" statements are handled within Luprex. It documents the full path by which print statements originate with Lua, and gradually travel to the Unreal virtual console and debug log. There are two types of print statements: - *dprint*, for messages that go to the debug logs. - *print*, for messages that go to a window in the user's GUI. The following sections explain the differences, and how each of these is implemented. ## dprint, for messages that go to the debug logs The lua code can use 'dprint' to print a message into Unreal's debugging logs. A 'dprint' goes to the same places that a debugging message within Unreal goes. That includes: - Visual studio's debug message window. - The Unreal Editor's debug message window. - Unreal's debug message log file. In the lua server, currently, dprints just go to stderr. We're probably going to enhance that by adding a log file as well. The unreal logs are not managed by predictive reexecution. To put it differently, once a message goes into the unreal logs, it can't be corrected by difference transmission. Because of this, if a dprint is reexecuted, you will get multiple possibly conflicting messages in the unreal logs. ## Implementation of dprint The luprex DLL contains a function util::dprintview, along with a couple of convenience wrappers like util::dprintf. This function is used to make a debugging print. It is used in a number of places throughout Luprex. It can also be called from lua, via the 'dprint' function. The Luprex DLL exports an API: EngineWrapper::hook_dprint. This function accepts a pointer to a C callback function, which takes a string as a parameter. The driver is expected to call hook_dprint early in 'main', to set the dprint callback. The pointer to the callback function is stored in the global variable util::dprint_hook. The function util::dprintview breaks the string into lines, and calls util::dprint_hook once per line. In the Unreal client, the dprint callback is set to a function that calls UE_LOG, the unreal error logging macro, with a log category of LogLuprex. So therefore, in the Unreal client, calling dprint is equivalent to calling UE_LOG. In the server, the dprint callback is set to a function that outputs the string to the console (ie, stdout). The print-callback is the *only* place where the Luprex DLL actually calls into the driver (via a callback). Normally, the driver is supposed to call into the Luprex DLL, but not the other way around. This one exception is necessary to handle the case where the Luprex DLL is about to crash and wants to print a message before it does. ## print, for messages that go to a window in the user's GUI The client is expected to have a GUI of some sort that includes a text console, where messages can be displayed. The print statement puts a message into this GUI console. Every person who is logged in has their own GUI text console. Therefore, it is possible to print a message onto any one of those. When the lua code executes a print statement, it sends its output to the GUI console of the *actor*. The contents of the GUI text console is part of the world model. Therefore, it can be corrected by difference transmission. If a print-statement is predicted incorrectly, the user's GUI text console will temporarily contain the wrong text, but it will get fixed by difference transmission. ## Implementation of print The world model contains an ostringstream lthread_prints_ which is used to temporarily collect normal print statements. Whenever a thread pauses or ends, the contents of the ostringstream are transferred to where they belong. If the thread is executing normally, as part of an 'invoke', then the contents of the stringstream are transferred into a "PrintBuffer." Class PrintBuffer is a class that the Luprex DLL uses to store the contents of a player's GUI console. The PrintBuffer is part of the world model: every logged in player has a PrintBuffer as part of their character tangible. Difference transmission is capable of amending the contents of the PrintBuffer. The stringstream doesn't always get transferred to a PrintBuffer. If the thread is a 'probe', then the stringstream is sent to 'dprint'. If the thread is running under the HTTP server, then the stringstream may be sent back as part of the HTTP response. The difference transmitter handles PrintBuffers specially. It doesn't just fix the contents of the PrintBuffer. It also leaves an 'authoritative' bit inside the PrintBuffer to indicate which print statements are confirmed as authoritative, and conversely, to indicate which ones are still just predictions. Because of this, the PrintBuffer knows the difference between a "final" print and a "tentative" print. The client and server in lpxclient.cpp and lpxserver.cpp both contain objects of class PrintChanneler. This class is designed to monitor a PrintBuffer to see if anything has changed. Specifically, it is capable of answering the question: does the PrintBuffer contain any new authoritative print statements? Periodically, lpxserver.cpp and lpxclient.cpp will check their PrintChannelers to see if there are any new authoritative print statements. If so, they will set a flag called "have_prints" in the DrivenEngine. Unreal periodically polls this flag using EngineWrapper::get_have_prints. If the have_prints is set, Unreal then calls EngineWrapper::play_access(... CHANNEL_PRINTS ...). This asks the PrintChanneler to fetch all new authoritative prints. Then, CHANNEL_PRINTS will send an invoke via the standard predictive reexecution channels to FLUSH_PRINTS - ie, to forget the print statements that it just channeled. When the PrintChanneler returns prints to Unreal, Unreal passes those prints to the LuprexGameMode blueprint by calling LuprexGameMode::AddConsoleOutput. The LuprexGameMode is currently responsible for implementing the GUI text console. That will probably change at some point. The LuprexGameMode maintains an object of class UlxConsoleOutput which keeps a record of what's in the GUI Console. When the LuprexGameMode receives new strings via AddConsoleOutput, it adds those string to the UlxConsoleOutput. The UlxConsoleOutput turns those individual lines into one big string. From there, the LuprexGameMode copies the entire string into the body of a UMG text widget. ## A Possible new lua print function