Overhaul the lthread_prints_ buffer.
This commit is contained in:
@@ -83,23 +83,25 @@ it will get fixed by difference transmission.
|
||||
|
||||
## Implementation of print
|
||||
|
||||
Inside the Luprex DLL, class PrintBuffer is used to store
|
||||
the contents of the GUI console. 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 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.
|
||||
|
||||
When the luprex thread scheduler starts executing a thread,
|
||||
it sets up an ostringstream to collect any print statements.
|
||||
When the thread pauses or ends, the contents of the ostringstream
|
||||
are copied into the PrintBuffer. The code to create the
|
||||
stringstream and to copy it into the PrintBuffer are both
|
||||
in the thread scheduling code in world-core.cpp.
|
||||
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 isn't *always* copied into the PrintBuffer.
|
||||
There are exceptions: for example, in a 'probe',
|
||||
print statements don't go into the PrintBuffer, they get
|
||||
rerouted to dprint instead.
|
||||
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
|
||||
@@ -121,7 +123,7 @@ 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 flag is set, Unreal then calls
|
||||
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
|
||||
@@ -136,7 +138,8 @@ 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
|
||||
AddConsoleOutput feeds new prints into the LuprexGameMode,
|
||||
those prints get added to the UlxConsoleOutput. This stores
|
||||
the contents of the console as one big string. From there,
|
||||
the string is copied into a text widget.
|
||||
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.
|
||||
|
||||
@@ -387,29 +387,24 @@ eng::string World::probe_lua_expr(int64_t actor_id, std::string_view lua) {
|
||||
// Call the closure.
|
||||
int top = lua_gettop(L);
|
||||
lua_pushvalue(L, closure.index());
|
||||
open_lthread_state(actor_id, actor_id, 0, false, true);
|
||||
open_lthread_state(actor_id, actor_id, 0, false);
|
||||
eng::string msg = traceback_pcall(L, 0, LUA_MULTRET);
|
||||
|
||||
|
||||
// If there's an error message, print it.
|
||||
// Otherwise, pretty-print the results.
|
||||
std::ostream *ostream = lthread_print_stream();
|
||||
if (msg.empty()) {
|
||||
for (int i = top + 1; i <= lua_gettop(L); i++) {
|
||||
LuaSpecial root(i);
|
||||
pprint(LS, root, PrettyPrintOptions(), ostream);
|
||||
pprint(LS, root, PrettyPrintOptions(), <hread_prints_);
|
||||
// TODO: this endl is unnecessary if we just printed a newline.
|
||||
(*ostream) << std::endl;
|
||||
lthread_prints_ << std::endl;
|
||||
}
|
||||
} else {
|
||||
(*ostream) << msg << std::endl;
|
||||
lthread_prints_ << msg << std::endl;
|
||||
}
|
||||
|
||||
// Collect the lthread_prints (and also make sure they
|
||||
// don't go into the printbuffer).
|
||||
eng::string result = lthread_prints_->str();
|
||||
lthread_prints_.reset();
|
||||
|
||||
close_lthread_state();
|
||||
eng::string result = lthread_prints_.str();
|
||||
clear_lthread_state();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -478,15 +473,10 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
||||
return;
|
||||
}
|
||||
|
||||
open_lthread_state(actor_id, place_id, 0, false, true);
|
||||
open_lthread_state(actor_id, place_id, 0, false);
|
||||
eng::string msg = traceback_pcall(L, nargs, LUA_MULTRET);
|
||||
LuaExtraArgs returnvalues(calltop + 1, lua_gettop(L) - calltop);
|
||||
|
||||
// Send any prints to the console.
|
||||
eng::string prints = lthread_prints_->str();
|
||||
lthread_prints_.reset();
|
||||
util::dprint(prints);
|
||||
|
||||
// If a probe generates a lua error, we're not supposed to dprint it.
|
||||
// Instead, we're supposed to send it back to unreal as the first
|
||||
// return value of the function.
|
||||
@@ -526,7 +516,7 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
||||
}
|
||||
}
|
||||
|
||||
close_lthread_state();
|
||||
clear_lthread_state();
|
||||
}
|
||||
|
||||
|
||||
@@ -545,11 +535,10 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
||||
bool World::rebuild_sourcedb() {
|
||||
bool ok = true;
|
||||
for (const eng::string &mod: source_db_.modules()) {
|
||||
open_lthread_state(0, 0, 0, false, true);
|
||||
open_lthread_state(0, 0, 0, false);
|
||||
eng::string err = source_db_.rebuild_module(mod);
|
||||
eng::string prints = lthread_prints_->str();
|
||||
lthread_prints_.reset();
|
||||
close_lthread_state();
|
||||
eng::string prints = lthread_prints_.str();
|
||||
clear_lthread_state();
|
||||
if (!err.empty()) ok = false;
|
||||
if (!err.empty() || !prints.empty()) {
|
||||
util::dprint("Loading Module ", mod);
|
||||
@@ -705,9 +694,11 @@ HttpServerResponse World::http_serve(const HttpParser &request) {
|
||||
int oldtop = lua_gettop(L);
|
||||
lua_pushvalue(L, func.index());
|
||||
lua_pushvalue(L, reqtab.index());
|
||||
open_lthread_state(0, 0, 0, false, false);
|
||||
open_lthread_state(0, 0, 0, false);
|
||||
eng::string msg = traceback_pcall(L, 1, LUA_MULTRET);
|
||||
close_lthread_state();
|
||||
if (!msg.empty()) lthread_prints_ << msg << std::endl;
|
||||
lthread_prints_to_dprint();
|
||||
clear_lthread_state();
|
||||
|
||||
// If the call threw an error, return
|
||||
// a 500 Internal Server Error to the client.
|
||||
@@ -1073,10 +1064,9 @@ void World::run_scheduled_threads() {
|
||||
|
||||
// Resume the coroutine.
|
||||
lua_State *CO = LS.ckthread(thread);
|
||||
open_lthread_state(LS.ckinteger(actorid), sched.place_id(), sched.thread_id(), LS.ckboolean(useppool), true);
|
||||
open_lthread_state(LS.ckinteger(actorid), sched.place_id(), sched.thread_id(), LS.ckboolean(useppool));
|
||||
int nargs = LS.ckboolean(isnew) ? (lua_gettop(CO) - 1) : lua_gettop(CO);
|
||||
int status = lua_resume(CO, nullptr, nargs);
|
||||
std::ostream *ostream = lthread_print_stream();
|
||||
|
||||
if (status == LUA_OK) {
|
||||
// Successfully ran to completion. Print any return values.
|
||||
@@ -1086,8 +1076,8 @@ void World::run_scheduled_threads() {
|
||||
LuaCoreStack LSCO(CO);
|
||||
if (LS.ckboolean(print)) {
|
||||
for (int i = 1; i <= lua_gettop(CO); i++) {
|
||||
pprint(LSCO, LuaSpecial(i), PrettyPrintOptions(), ostream);
|
||||
(*ostream) << std::endl;
|
||||
pprint(LSCO, LuaSpecial(i), PrettyPrintOptions(), <hread_prints_);
|
||||
lthread_prints_ << std::endl;
|
||||
}
|
||||
}
|
||||
} else if (status == LUA_YIELD) {
|
||||
@@ -1106,11 +1096,12 @@ void World::run_scheduled_threads() {
|
||||
// Currently, the error is sent to the actor. That seems... not right in the long run.
|
||||
if (is_authoritative()) {
|
||||
traceback_coroutine(CO);
|
||||
(*ostream) << lua_tostring(CO, -1);
|
||||
lthread_prints_ << lua_tostring(CO, -1);
|
||||
}
|
||||
LS.rawset(threads, sched.thread_id(), LuaNil);
|
||||
}
|
||||
close_lthread_state();
|
||||
lthread_prints_to_printbuffer();
|
||||
clear_lthread_state();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1140,14 +1131,15 @@ void World::clear_lthread_state() {
|
||||
LS.rawset(globals, "actor", LuaNil);
|
||||
LS.rawset(globals, "place", LuaNil);
|
||||
|
||||
lthread_prints_.reset();
|
||||
lthread_actor_id_ = 0;
|
||||
lthread_place_id_ = 0;
|
||||
lthread_thread_id_ = 0;
|
||||
lthread_use_ppool_ = false;
|
||||
lthread_prints_.str();
|
||||
lthread_prints_.clear();
|
||||
}
|
||||
|
||||
void World::open_lthread_state(int64_t actor, int64_t place, int64_t thread, bool ppool, bool prints) {
|
||||
void World::open_lthread_state(int64_t actor, int64_t place, int64_t thread, bool ppool) {
|
||||
// Store actor and place in global variables.
|
||||
LuaVar lactor, lplace, tangibles, globals;
|
||||
LuaExtStack LS(state(), lactor, lplace, tangibles, globals);
|
||||
@@ -1170,37 +1162,30 @@ void World::open_lthread_state(int64_t actor, int64_t place, int64_t thread, boo
|
||||
lthread_place_id_ = place;
|
||||
lthread_thread_id_ = thread;
|
||||
lthread_use_ppool_ = ppool;
|
||||
if (prints) {
|
||||
lthread_prints_.reset(new eng::ostringstream);
|
||||
} else {
|
||||
lthread_prints_.reset();
|
||||
}
|
||||
lthread_prints_.str();
|
||||
lthread_prints_.clear();
|
||||
}
|
||||
|
||||
void World::close_lthread_state() {
|
||||
// Copy prints from lthread_prints_ stringstream into
|
||||
// the appropriate actor's PrintBuffer.
|
||||
if (lthread_prints_ != nullptr) {
|
||||
const eng::string &output = lthread_prints_->str();
|
||||
if (output.size() > 0) {
|
||||
Tangible *actor = tangible_get(lthread_actor_id_);
|
||||
if (actor != nullptr) {
|
||||
actor->print_buffer_.add_string(output, is_authoritative());
|
||||
}
|
||||
void World::lthread_prints_to_printbuffer()
|
||||
{
|
||||
const eng::string &output = lthread_prints_.str();
|
||||
if (output.size() > 0) {
|
||||
Tangible *actor = tangible_get(lthread_actor_id_);
|
||||
if (actor != nullptr) {
|
||||
actor->print_buffer_.add_string(output, is_authoritative());
|
||||
}
|
||||
}
|
||||
// Now clean up everything.
|
||||
clear_lthread_state();
|
||||
}
|
||||
|
||||
std::ostream *World::lthread_print_stream() const {
|
||||
if (lthread_prints_ != nullptr) {
|
||||
return lthread_prints_.get();
|
||||
} else {
|
||||
return &std::cerr;
|
||||
void World::lthread_prints_to_dprint()
|
||||
{
|
||||
const eng::string &output = lthread_prints_.str();
|
||||
if (output.size() > 0) {
|
||||
util::dprintview(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void World::set_global(const eng::string &gvar, std::string_view value) {
|
||||
// Store the serialized blob.
|
||||
//
|
||||
|
||||
@@ -358,10 +358,12 @@ public:
|
||||
// cleared.
|
||||
//
|
||||
void clear_lthread_state();
|
||||
void open_lthread_state(int64_t actor_id, int64_t place_id, int64_t thread_id, bool ppool, bool prints);
|
||||
void close_lthread_state();
|
||||
void open_lthread_state(int64_t actor_id, int64_t place_id, int64_t thread_id, bool ppool);
|
||||
|
||||
std::ostream *lthread_print_stream() const;
|
||||
std::ostream *lthread_print_stream() { return <hread_prints_; }
|
||||
|
||||
void lthread_prints_to_printbuffer();
|
||||
void lthread_prints_to_dprint();
|
||||
|
||||
// Set a lua global variable.
|
||||
//
|
||||
@@ -670,7 +672,7 @@ private:
|
||||
int64_t lthread_place_id_;
|
||||
int64_t lthread_thread_id_;
|
||||
int64_t lthread_use_ppool_;
|
||||
std::unique_ptr<eng::ostringstream> lthread_prints_;
|
||||
eng::ostringstream lthread_prints_;
|
||||
|
||||
friend class Tangible;
|
||||
friend int lfn_tangible_animate(lua_State *L);
|
||||
|
||||
Reference in New Issue
Block a user