Some output now going through PrintBuffer
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
#include "print.hpp"
|
||||
#include "pprint.hpp"
|
||||
#include "util.hpp"
|
||||
#include "table.hpp"
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
// This file provides these functions for lua.
|
||||
//
|
||||
// They direct all output to std::cout
|
||||
//
|
||||
extern "C" {
|
||||
void luai_writestring(const char *s, size_t len);
|
||||
void luai_writeline();
|
||||
}
|
||||
|
||||
void luai_writestring(const char *s, size_t len) {
|
||||
std::cout.write(s, len);
|
||||
}
|
||||
@@ -250,15 +259,6 @@ void pprint(LuaStack &LS0, LuaSlot root, bool indent, std::ostream *os) {
|
||||
LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(pprint_pprint, "f") {
|
||||
LuaStack LS(L);
|
||||
for (int i = 1; i <= lua_gettop(L); i++) {
|
||||
LuaSpecial root(i);
|
||||
pprint(LS, root, true, &std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(string_pprint, "c") {
|
||||
LuaArg root, indent;
|
||||
@@ -6,20 +6,11 @@
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PRINT_HPP
|
||||
#define PRINT_HPP
|
||||
#ifndef PPRINT_HPP
|
||||
#define PPRINT_HPP
|
||||
|
||||
#include "luastack.hpp"
|
||||
|
||||
// This file provides these functions for lua.
|
||||
//
|
||||
// They direct all output to std::cout
|
||||
//
|
||||
extern "C" {
|
||||
void luai_writestring(const char *s, size_t len);
|
||||
void luai_writeline();
|
||||
}
|
||||
|
||||
// Output a simple value to a stream.
|
||||
//
|
||||
// If the value is a string, number, boolean, or nil, it is
|
||||
@@ -52,4 +43,4 @@ void pprint(LuaStack &LS, LuaSlot val, bool indent, std::ostream *os);
|
||||
int lfn_pprint_pprint(lua_State *L);
|
||||
int lfn_string_pprint(lua_State *L);
|
||||
|
||||
#endif // PRINT_HPP
|
||||
#endif // PPRINT_HPP
|
||||
@@ -96,22 +96,30 @@ private:
|
||||
// a newline (or any other weird control characters).
|
||||
void add_line(const char *line, int len);
|
||||
|
||||
// Return the line number beyond the end of the buffer.
|
||||
int last_line() const { return first_line_ + int(lines_.size()); }
|
||||
|
||||
// Get the specified line number.
|
||||
const std::string &nth(int n) const { return lines_[n - first_line_]; }
|
||||
|
||||
|
||||
public:
|
||||
PrintBuffer(util::WorldType wt);
|
||||
|
||||
// Get the current first line.
|
||||
int first_line() const { return first_line_; }
|
||||
|
||||
// Return the line number beyond the end of the buffer.
|
||||
int last_line() const { return first_line_ + int(lines_.size()); }
|
||||
|
||||
// Get the current first unchecked line.
|
||||
int first_unchecked() const { return first_unchecked_; }
|
||||
|
||||
// Get the specified line number.
|
||||
const std::string &nth(int n) const { return lines_[n - first_line_]; }
|
||||
|
||||
// Add a string. If the string doesn't end in a newline, a newline
|
||||
// is added. The string is broken into lines, and the lines are added
|
||||
// to the PrintBuffer.
|
||||
void add_string(const char *text, int len);
|
||||
void add_string(const std::string &s);
|
||||
|
||||
|
||||
// Discard lines up to but not including line N.
|
||||
void discard_upto(int n);
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
#include "traceback.hpp"
|
||||
#include "textgame.hpp"
|
||||
#include "luaconsole.hpp"
|
||||
#include "print.hpp"
|
||||
#include "pprint.hpp"
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
class TextGame : public DrivenEngine {
|
||||
@@ -26,6 +27,7 @@ private:
|
||||
Gui gui_;
|
||||
int64_t gui_place_;
|
||||
int64_t actor_id_;
|
||||
int64_t printbuffer_line_;
|
||||
|
||||
void do_view_command(const StringVec &cmd);
|
||||
void do_menu_command(const StringVec &cmd);
|
||||
@@ -39,6 +41,7 @@ private:
|
||||
void do_command(const StringVec &exp);
|
||||
|
||||
void check_redirects();
|
||||
void channel_printbuffer();
|
||||
|
||||
public:
|
||||
virtual void event_init(int argc, char *argv[]);
|
||||
@@ -167,12 +170,26 @@ void TextGame::check_redirects() {
|
||||
}
|
||||
}
|
||||
|
||||
void TextGame::channel_printbuffer() {
|
||||
const PrintBuffer *printbuffer = world_->get_printbuffer(actor_id_);
|
||||
if (printbuffer == nullptr) return;
|
||||
if (printbuffer->first_line() > printbuffer_line_) {
|
||||
printbuffer_line_ = printbuffer->first_line();
|
||||
}
|
||||
while (printbuffer_line_ < printbuffer->first_unchecked()) {
|
||||
std::cerr << "* " << printbuffer->nth(printbuffer_line_) << std::endl;
|
||||
printbuffer_line_ += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextGame::event_init(int argc, char *argv[])
|
||||
{
|
||||
world_.reset(new World(util::WORLD_TYPE_STANDALONE));
|
||||
world_->update_source(get_lua_source());
|
||||
world_->run_unittests();
|
||||
actor_id_ = world_->create_login_actor();
|
||||
printbuffer_line_ = 0;
|
||||
std::cerr << "Login actor ID: " << actor_id_ << std::endl;
|
||||
get_stdio_channel()->out()->write_bytes(console_.get_prompt());
|
||||
}
|
||||
@@ -188,9 +205,11 @@ void TextGame::event_update()
|
||||
if (action == LuaConsole::DO_LUA) {
|
||||
do_lua(console_.lua_expression());
|
||||
console_.clear();
|
||||
channel_printbuffer();
|
||||
} else if (action == LuaConsole::DO_COMMAND) {
|
||||
do_command(console_.words());
|
||||
console_.clear();
|
||||
channel_printbuffer();
|
||||
} else if (action == LuaConsole::DO_SYNTAX) {
|
||||
std::cerr << console_.syntax() << std::endl;
|
||||
console_.clear();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "world.hpp"
|
||||
#include "pprint.hpp"
|
||||
|
||||
LuaDefine(tangible_animstate, "c") {
|
||||
LuaArg tanobj;
|
||||
@@ -209,3 +210,14 @@ LuaDefine(world_settabletype, "f") {
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(world_pprint, "f") {
|
||||
World *w = World::fetch_global_pointer(L);
|
||||
std::ostream *ostream = w->lthread_print_stream();
|
||||
LuaStack LS(L);
|
||||
for (int i = 1; i <= lua_gettop(L); i++) {
|
||||
LuaSpecial root(i);
|
||||
pprint(LS, root, true, ostream);
|
||||
(*ostream) << std::endl;
|
||||
}
|
||||
return LS.result();
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "animqueue.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "traceback.hpp"
|
||||
#include "print.hpp"
|
||||
#include "pprint.hpp"
|
||||
#include <iostream>
|
||||
|
||||
void World::store_global_pointer(lua_State *L, World *v) {
|
||||
@@ -49,7 +49,7 @@ World::World(util::WorldType wt) {
|
||||
Gui::store_global_pointer(state(), nullptr);
|
||||
|
||||
// Clear the lthread state.
|
||||
set_lthread_state(0, 0, false);
|
||||
clear_lthread_state();
|
||||
|
||||
// Set the tabletype of the registry.
|
||||
LS.settabletype(LuaRegistry, LUA_TT_REGISTRY);
|
||||
@@ -262,6 +262,7 @@ int64_t World::create_login_actor() {
|
||||
LS.rawset(mt, "__index", classtab);
|
||||
LS.result();
|
||||
tan->configure_id_pool_for_actor();
|
||||
tan->print_buffer_.reset(new PrintBuffer(world_type_));
|
||||
assert(stack_is_clear());
|
||||
return tan->id();
|
||||
}
|
||||
@@ -305,9 +306,9 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
|
||||
lua_pushvalue(L, actor.index());
|
||||
lua_pushvalue(L, place.index());
|
||||
Gui::store_global_pointer(L, gui);
|
||||
set_lthread_state(actor_id, place_id, false);
|
||||
open_lthread_state(actor_id, place_id, false, false);
|
||||
int status = traceback_pcall(L, 2, 0);
|
||||
set_lthread_state(0, 0, false);
|
||||
close_lthread_state();
|
||||
Gui::store_global_pointer(L, nullptr);
|
||||
if (status != 0) {
|
||||
gui->clear();
|
||||
@@ -372,25 +373,27 @@ void World::invoke_lua(int64_t actor_id, int64_t place_id, const std::string &ac
|
||||
// Call the closure.
|
||||
int top = lua_gettop(L);
|
||||
lua_pushvalue(L, closure.index());
|
||||
set_lthread_state(actor_id, place_id, false);
|
||||
open_lthread_state(actor_id, place_id, false, true);
|
||||
status = traceback_pcall(L, 0, LUA_MULTRET);
|
||||
set_lthread_state(0, 0, false);
|
||||
|
||||
|
||||
// If there's an error message, print it.
|
||||
// Otherwise, pretty-print the results.
|
||||
std::ostream *ostream = lthread_print_stream();
|
||||
if (status == LUA_OK) {
|
||||
for (int i = top + 1; i <= lua_gettop(L); i++) {
|
||||
LuaSpecial root(i);
|
||||
pprint(LS, root, true, &std::cout);
|
||||
std::cout << std::endl;
|
||||
pprint(LS, root, true, ostream);
|
||||
(*ostream) << std::endl;
|
||||
}
|
||||
} else {
|
||||
const char *msg = lua_tostring(L, top);
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
if (msg == NULL) {
|
||||
msg = "(error object is not a string)";
|
||||
}
|
||||
std::cerr << msg << std::endl;
|
||||
(*ostream) << msg << std::endl;
|
||||
}
|
||||
close_lthread_state();
|
||||
|
||||
LS.result();
|
||||
assert(stack_is_clear());
|
||||
}
|
||||
@@ -535,10 +538,10 @@ void World::run_scheduled_threads(int64_t clk) {
|
||||
|
||||
// Resume the coroutine.
|
||||
lua_State *CO = LS.ckthread(thread);
|
||||
set_lthread_state(LS.ckinteger(actorid), sched.place_id(), LS.ckboolean(useppool));
|
||||
open_lthread_state(LS.ckinteger(actorid), sched.place_id(), LS.ckboolean(useppool), true);
|
||||
int status = lua_resume(CO, nullptr, LS.ckboolean(isnew) ? 3 : 0);
|
||||
set_lthread_state(0, 0, false);
|
||||
|
||||
close_lthread_state();
|
||||
|
||||
// Three possible outcomes: finished, yielded, or errored.
|
||||
if (status == LUA_YIELD) {
|
||||
// When the wait statement yields, it yields the desired timestamp.
|
||||
@@ -580,10 +583,60 @@ int64_t World::alloc_id_predictable() {
|
||||
return t->id_player_pool_.get_one();
|
||||
}
|
||||
|
||||
void World::set_lthread_state(int64_t actor, int64_t place, bool ppool) {
|
||||
const PrintBuffer *World::get_printbuffer(int64_t actor_id) {
|
||||
Tangible *actor = tangible_get(actor_id);
|
||||
if (actor != nullptr) {
|
||||
return actor->print_buffer_.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void World::clear_lthread_state() {
|
||||
lthread_prints_.reset();
|
||||
lthread_actor_id_ = 0;
|
||||
lthread_place_id_ = 0;
|
||||
lthread_use_ppool_ = false;
|
||||
}
|
||||
|
||||
void World::open_lthread_state(int64_t actor, int64_t place, bool ppool, bool prints) {
|
||||
lthread_actor_id_ = actor;
|
||||
lthread_place_id_ = place;
|
||||
lthread_use_ppool_ = ppool;
|
||||
if (prints) {
|
||||
lthread_prints_.reset(new std::ostringstream);
|
||||
} else {
|
||||
lthread_prints_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void World::close_lthread_state() {
|
||||
// Copy prints from lthread_prints_ stringstream into
|
||||
// the appropriate actor's PrintBuffer. If for some reason
|
||||
// there isn't an actor, or if the actor doesn't have a PrintBuffer,
|
||||
// send the output to std::cerr.
|
||||
if (lthread_prints_ != nullptr) {
|
||||
const std::string &output = lthread_prints_->str();
|
||||
PrintBuffer *pbuffer = nullptr;
|
||||
Tangible *actor = tangible_get(lthread_actor_id_);
|
||||
if (actor != nullptr) {
|
||||
pbuffer = actor->print_buffer_.get();
|
||||
}
|
||||
if (pbuffer != nullptr) {
|
||||
pbuffer->add_string(output);
|
||||
} else {
|
||||
std::cerr << output;
|
||||
}
|
||||
}
|
||||
// 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::serialize(StreamBuffer *sb) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "world.hpp"
|
||||
#include "print.hpp"
|
||||
#include "pprint.hpp"
|
||||
#include <cassert>
|
||||
|
||||
void World::tangible_walkto(int64_t id, int64_t animid, float x, float y) {
|
||||
|
||||
@@ -182,6 +182,10 @@ public:
|
||||
//
|
||||
void invoke(const Invocation &inv);
|
||||
|
||||
// Get the PrintBuffer of the actor.
|
||||
//
|
||||
const PrintBuffer *get_printbuffer(int64_t actor_id);
|
||||
|
||||
// Update the source database from disk.
|
||||
//
|
||||
// Special case: if the source pointer is nullptr, does not update.
|
||||
@@ -225,11 +229,16 @@ public:
|
||||
// * lthread_actor_id: current actor
|
||||
// * lthread_place_id: current place
|
||||
// * lthread_use_ppool: true if we should use the player ID pool.
|
||||
// * lthread_prints_: a stringstream which will collect 'print' statements.
|
||||
//
|
||||
// As soon as the lua code stops executing, these variables are
|
||||
// cleared.
|
||||
//
|
||||
void set_lthread_state(int64_t actor_id, int64_t place_id, bool ppool);
|
||||
void clear_lthread_state();
|
||||
void open_lthread_state(int64_t actor_id, int64_t place_id, bool ppool, bool prints);
|
||||
void close_lthread_state();
|
||||
|
||||
std::ostream *lthread_print_stream() const;
|
||||
|
||||
// Allocate a single ID.
|
||||
//
|
||||
@@ -448,6 +457,7 @@ private:
|
||||
int64_t lthread_actor_id_;
|
||||
int64_t lthread_place_id_;
|
||||
int64_t lthread_use_ppool_;
|
||||
std::unique_ptr<std::ostringstream> lthread_prints_;
|
||||
|
||||
friend class Tangible;
|
||||
friend int lfn_tangible_animate(lua_State *L);
|
||||
|
||||
Reference in New Issue
Block a user