From 827a11475240ac779300b7d9f90e89fcfe78209a Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Fri, 22 Jan 2021 19:10:47 -0500 Subject: [PATCH] Created AnimViewMap --- luprex/build.bat | 2 +- luprex/syscpp/animqueue.cpp | 37 ++++++++ luprex/syscpp/animqueue.hpp | 55 ++++++++--- luprex/syscpp/main.cpp | 181 +----------------------------------- luprex/syscpp/textgame.cpp | 172 ++++++++++++++++++++++++++++++++++ luprex/syscpp/textgame.hpp | 15 +++ luprex/syscpp/viewer.cpp | 55 ----------- luprex/syscpp/viewer.hpp | 19 ++-- luprex/syscpp/world.cpp | 25 ++++- luprex/syscpp/world.hpp | 7 +- 10 files changed, 302 insertions(+), 266 deletions(-) create mode 100644 luprex/syscpp/textgame.cpp create mode 100644 luprex/syscpp/textgame.hpp diff --git a/luprex/build.bat b/luprex/build.bat index d92e9382..a502b553 100644 --- a/luprex/build.bat +++ b/luprex/build.bat @@ -1,2 +1,2 @@ clear -g++ -std=c++17 -Wall -g -o main syscpp/util.cpp syscpp/viewer.cpp syscpp/main.cpp syscpp/animqueue.cpp syscpp/planemap.cpp syscpp/world.cpp syscpp/traceback.cpp syscpp/luastack.cpp syscpp/source.cpp syscpp/table.cpp syscpp/idalloc.cpp syscpp/globaldb.cpp -Iinc -Llib lib/libluajit-dbg.a -Isyscpp +g++ -std=c++17 -Wall -g -o main syscpp/util.cpp syscpp/viewer.cpp syscpp/main.cpp syscpp/textgame.cpp syscpp/animqueue.cpp syscpp/planemap.cpp syscpp/world.cpp syscpp/traceback.cpp syscpp/luastack.cpp syscpp/source.cpp syscpp/table.cpp syscpp/idalloc.cpp syscpp/globaldb.cpp -Iinc -Llib lib/libluajit-dbg.a -Isyscpp diff --git a/luprex/syscpp/animqueue.cpp b/luprex/syscpp/animqueue.cpp index 1171f9b0..41a8aa5b 100644 --- a/luprex/syscpp/animqueue.cpp +++ b/luprex/syscpp/animqueue.cpp @@ -80,6 +80,43 @@ const util::XYZ &AnimQueue::get_xyz() const { return last.xyz_; } +void AnimView::update_from(const AnimQueue &queue) { + id_ = queue.get_id(); + graphic_ = queue.get_graphic(); + plane_ = queue.get_plane(); + xyz_ = queue.get_xyz(); + updated_ = true; +} + +AnimView *AnimViewMap::get_one(int64_t id) { + auto iter = view_map_.find(id); + if (iter == view_map_.end()) { + return nullptr; + } else { + return &iter->second; + } +} + +void AnimViewMap::clear_updated_bits() { + for (auto pair : view_map_) { + pair.second.updated_ = false; + } +} + +void AnimViewMap::delete_non_updated() { + for (auto iter = view_map_.begin(); iter != view_map_.end(); ) { + if (iter->second.updated_) { + iter++; + } else { + iter = view_map_.erase(iter); + } + } +} + +void AnimViewMap::update_one(const AnimQueue &queue) { + view_map_[queue.get_id()].update_from(queue); +} + LuaDefine(unittests_animqueue, "c") { // Check initial state. AnimQueue aq; diff --git a/luprex/syscpp/animqueue.hpp b/luprex/syscpp/animqueue.hpp index df586aa2..26ac52bc 100644 --- a/luprex/syscpp/animqueue.hpp +++ b/luprex/syscpp/animqueue.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "util.hpp" @@ -73,10 +74,13 @@ public: class AnimQueue { private: + int64_t id_; int size_limit_; std::deque steps_; public: AnimQueue(); + int64_t get_id() const { return id_; } + void set_id(int64_t id) { id_ = id; } const AnimStep &nth(int n) const { return steps_[n]; } int size() const { return steps_.size(); } @@ -97,25 +101,52 @@ public: }; class AnimView { + friend class AnimViewMap; private: + int64_t id_; std::string graphic_; std::string plane_; util::XYZ xyz_; - bool updated_; + bool updated_; // Used by AnimViewMap. public: - const std::string &get_graphic() { return graphic_; } - const std::string &get_plane() { return plane_; } - const util::XYZ &get_xyz() { return xyz_; } - bool updated() { return updated_; } + AnimView() : id_(0), updated_(true) {} - void update_from(const AnimQueue &queue) { - graphic_ = queue.get_graphic(); - plane_ = queue.get_plane(); - xyz_ = queue.get_xyz(); - updated_ = true; - } + int64_t get_id() const { return id_; } + const std::string &get_graphic() const { return graphic_; } + const std::string &get_plane() const { return plane_; } + const util::XYZ &get_xyz() const { return xyz_; } - void set_updated(bool u) { updated_ = u; } + void update_from(const AnimQueue &queue); +}; + +// AnimViewMap: basically just a map from tangible ID to AnimView. +// +// Also provides a simple garbage collector to get rid of AnimViews +// that haven't been updated recently. +// +class AnimViewMap { +public: + using ViewMap = std::unordered_map; +private: + ViewMap view_map_; +public: + AnimViewMap() {} + ~AnimViewMap() {} + + // Get the entire view map for iterating over. + ViewMap &get_map() { return view_map_; } + + // Get one entry from the view map, if it exists. + AnimView *get_one(int64_t id); + + // Clear the updated bits on all the AnimViews. + void clear_updated_bits(); + + // Delete any AnimViews whose updated bits are not set. + void delete_non_updated(); + + // Update one AnimView, and set its updated bit. + void update_one(const AnimQueue &queue); }; #endif // ANIMQUEUE_HPP diff --git a/luprex/syscpp/main.cpp b/luprex/syscpp/main.cpp index eed2e186..0ecdd19c 100644 --- a/luprex/syscpp/main.cpp +++ b/luprex/syscpp/main.cpp @@ -1,183 +1,8 @@ -/* -** LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc. -** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h -** -** Major portions taken verbatim or adapted from the Lua interpreter. -** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h -*/ -#include -#include -#include -#include -#include -#include -#include "luastack.hpp" -#include "util.hpp" -#include "viewer.hpp" -#include "traceback.hpp" - - -// Add another error status. -#define LUA_PARTIAL (LUA_ERRERR + 10) -#define LUA_EOF (LUA_ERRERR + 11) - -static lua_State *globalL = NULL; - - -static void lstop(lua_State *L, lua_Debug *ar) -{ - (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); - /* Avoid luaL_error -- a C hook doesn't add an extra frame. */ - luaL_where(L, 0); - lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1)); - lua_error(L); -} - -static void laction(int i) -{ - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ - lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); -} - -static void l_message(const char *msg) -{ - fputs(msg, stderr); - fputc('\n', stderr); - fflush(stderr); -} - -static int report(lua_State *L, int status) -{ - if (status && !lua_isnil(L, -1)) - { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) - msg = "(error object is not a string)"; - l_message(msg); - lua_pop(L, 1); - } - return status; -} - -static int docall(lua_State *L, int narg, int nret) -{ - signal(SIGINT, laction); - int status = traceback_pcall(L, narg, nret); - signal(SIGINT, SIG_DFL); - /* force a complete garbage collection in case of errors */ - if (status != LUA_OK) - lua_gc(L, LUA_GCCOLLECT, 0); - return status; -} - -// Print a prompt, read a line of text, and push it on the stack. -// If it's the first line, translate "=" to "return" -// -static int pushline(lua_State *L, int firstline) -{ - const int MAXINPUT = 1000; - char buf[MAXINPUT]; - fputs(firstline ? "> " : ">> ", stdout); - fflush(stdout); - if (fgets(buf, MAXINPUT, stdin)) - { - size_t len = strlen(buf); - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - if (firstline && buf[0] == '=') - lua_pushfstring(L, "return %s", buf + 1); - else - lua_pushstring(L, buf); - return 1; - } - return 0; -} - -// Same as lua_loadbuffer, except: if the form passed in -// is a partial form, returns LUA_PARTIAL. -// -static int loadbuffer_partial(lua_State *L, const char *s, int len, const char *fn) -{ - const char *eof = "''"; - int status = luaL_loadbuffer(L, s, len, fn); - if (status != LUA_ERRSYNTAX) - { - return status; - } - size_t lmsg; - const char *msg = lua_tolstring(L, -1, &lmsg); - const char *tp = msg + lmsg - (sizeof(eof) - 1); - if (strstr(msg, eof) == tp) - { - return LUA_PARTIAL; - } - else - { - return status; - } -} - -// Read an entire form. On success, returns a closure. On EOF, -// returns just the LUA_EOF status code. On failure, returns an -// error message and a status code. -static int read_and_load(lua_State *L) -{ - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) - return LUA_EOF; /* no input */ - for (;;) - { /* repeat until gets a complete line */ - status = loadbuffer_partial(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (status != LUA_PARTIAL) - break; - lua_pop(L, 1); /* pop the error message */ - if (!pushline(L, 0)) /* no more input? */ - return LUA_EOF; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_remove(L, 1); /* remove line */ - return status; -} - -static void dotty(lua_State *L) -{ - while (1) - { - int status = read_and_load(L); - if (status == LUA_EOF) break; - if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); - report(L, status); - if (status == LUA_OK && lua_gettop(L) > 0) - { /* any result to print? */ - lua_getglobal(L, "pprint"); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - lua_getglobal(L, "print"); - } - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) - { - l_message( - lua_pushfstring(L, "error calling 'print' (%s)", - lua_tostring(L, -1))); - } - } - } - lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); - fflush(stdout); -} +#include "textgame.hpp" int main(int argc, char **argv) { - LUAJIT_VERSION_SYM(); // Linker-enforced version check. - Viewer v; - dotty(v.get_lua_state()); - return 0; + TextGame tg; + tg.run(); } diff --git a/luprex/syscpp/textgame.cpp b/luprex/syscpp/textgame.cpp new file mode 100644 index 00000000..29823057 --- /dev/null +++ b/luprex/syscpp/textgame.cpp @@ -0,0 +1,172 @@ + +#include +#include +#include +#include +#include +#include +#include "luastack.hpp" +#include "util.hpp" +#include "viewer.hpp" +#include "traceback.hpp" +#include "textgame.hpp" + +// Add another error status. + +static lua_State *globalL = NULL; + + +static void lstop(lua_State *L, lua_Debug *ar) +{ + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); + /* Avoid luaL_error -- a C hook doesn't add an extra frame. */ + luaL_where(L, 0); + lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1)); + lua_error(L); +} + +static void laction(int i) +{ + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + +static void l_message(const char *msg) +{ + fputs(msg, stderr); + fputc('\n', stderr); + fflush(stderr); +} + +static int report(lua_State *L, int status) +{ + if (status && !lua_isnil(L, -1)) + { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) + msg = "(error object is not a string)"; + l_message(msg); + lua_pop(L, 1); + } + return status; +} + +static int docall(lua_State *L, int narg, int nret) +{ + signal(SIGINT, laction); + int status = traceback_pcall(L, narg, nret); + signal(SIGINT, SIG_DFL); + /* force a complete garbage collection in case of errors */ + if (status != LUA_OK) + lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + +// Print a prompt, read a line of text, and push it on the stack. +// If it's the first line, translate "=" to "return" +// +static int pushline(lua_State *L, int firstline) +{ + const int MAXINPUT = 1000; + char buf[MAXINPUT]; + fputs(firstline ? "> " : ">> ", stdout); + fflush(stdout); + if (fgets(buf, MAXINPUT, stdin)) + { + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + if (firstline && buf[0] == '=') + lua_pushfstring(L, "return %s", buf + 1); + else + lua_pushstring(L, buf); + return 1; + } + return 0; +} + +// Same as lua_loadbuffer, except: if the form passed in +// is a partial form, returns LUA_ERRPARTIAL. +// +static int loadbuffer_partial(lua_State *L, const char *s, int len, const char *fn) +{ + const char *eof = "''"; + int status = luaL_loadbuffer(L, s, len, fn); + if (status != LUA_ERRSYNTAX) + { + return status; + } + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(eof) - 1); + if (strstr(msg, eof) == tp) + { + return LUA_ERRPARTIAL; + } + else + { + return status; + } +} + +// Read an entire form. On success, returns a closure. On EOF, +// returns just the LUA_ERREOF status code. On failure, returns an +// error message and a status code. +static int read_and_load(lua_State *L) +{ + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return LUA_ERREOF; /* no input */ + for (;;) + { /* repeat until gets a complete line */ + status = loadbuffer_partial(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (status != LUA_ERRPARTIAL) + break; + lua_pop(L, 1); /* pop the error message */ + if (!pushline(L, 0)) /* no more input? */ + return LUA_ERREOF; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_remove(L, 1); /* remove line */ + return status; +} + +static void dotty(lua_State *L) +{ + while (1) + { + int status = read_and_load(L); + if (status == LUA_ERREOF) break; + if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); + report(L, status); + if (status == LUA_OK && lua_gettop(L) > 0) + { /* any result to print? */ + lua_getglobal(L, "pprint"); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_getglobal(L, "print"); + } + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) + { + l_message( + lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); +} + +void TextGame::run() +{ + dotty(viewer_.get_lua_state()); +} + diff --git a/luprex/syscpp/textgame.hpp b/luprex/syscpp/textgame.hpp new file mode 100644 index 00000000..86421902 --- /dev/null +++ b/luprex/syscpp/textgame.hpp @@ -0,0 +1,15 @@ + +#ifndef TEXTGAME_HPP +#define TEXTGAME_HPP + +#include "viewer.hpp" + +class TextGame { +private: + Viewer viewer_; +public: + void run(); +}; + +#endif // TEXTGAME_HPP + diff --git a/luprex/syscpp/viewer.cpp b/luprex/syscpp/viewer.cpp index b21ace75..267c81b1 100644 --- a/luprex/syscpp/viewer.cpp +++ b/luprex/syscpp/viewer.cpp @@ -13,61 +13,6 @@ int64_t Viewer::get_player_id() { return 1; } - -void Viewer::update_view() { - // Get ready to delete views that aren't in use. - // - for (auto pair : anim_view_) { - pair.second.set_updated(false); - } - - // Update the player's AnimView first. - // - Tangible *player = world_->tangible_get(1); - AnimView *player_view = &anim_view_[1]; - player_view->update_from(player->anim_queue_); - - // Find out where's the center of the world. - // - std::string plane = player_view->get_plane(); - util::XYZ xyz = player_view->get_xyz(); - - // Get a list of everything near the player. - // - tangibles_ = world_->scan_radius(plane, xyz.x, xyz.y, 100.0); - - // Update AnimViews for every tangible near the player. - // - for (int64_t id : tangibles_) { - Tangible *tan = world_->tangible_get(id); - assert (tan != nullptr); - anim_view_[id].update_from(tan->anim_queue_); - } - - // Delete any AnimView that was not updated. - // - for (auto iter = anim_view_.begin(); iter != anim_view_.end(); ) { - if (iter->second.updated()) { - iter++; - } else { - iter = anim_view_.erase(iter); - } - } -} - -const std::vector &Viewer::get_tangibles_near_player() { - return tangibles_; -} - -AnimView *Viewer::get_animation_view(int64_t id) { - auto iter = anim_view_.find(id); - if (iter == anim_view_.end()) { - return nullptr; - } else { - return &iter->second; - } -} - // Get the menu of the specified tangible. // std::vector Viewer::get_menu(int64_t id) { diff --git a/luprex/syscpp/viewer.hpp b/luprex/syscpp/viewer.hpp index fe80b427..111857b0 100644 --- a/luprex/syscpp/viewer.hpp +++ b/luprex/syscpp/viewer.hpp @@ -5,15 +5,12 @@ #include "animqueue.hpp" #include #include -#include #include class Viewer { private: std::unique_ptr world_; - std::vector tangibles_; - std::unordered_map anim_view_; - + AnimViewMap view_map_; public: Viewer(); @@ -22,22 +19,18 @@ public: // Get the lua state for interaction. // lua_State *get_lua_state() { return world_->get_lua_state(); } - + // Get the player ID of the current player. // int64_t get_player_id(); - // Update the view. + // Update the view map. // - void update_view(); + void update_view_map() { world_->update_view_map(&view_map_, 1, 100); } - // Get a list of the tangibles in viewing radius of the player. + // Get the view map. // - const std::vector &get_tangibles_near_player(); - - // Get the animation viewer of the specified tangible. - // - AnimView *get_animation_view(int64_t id); + const AnimViewMap &get_view_map() { return view_map_; } // Get the menu of the specified tangible. // diff --git a/luprex/syscpp/world.cpp b/luprex/syscpp/world.cpp index 04ca3adb..e0f04d03 100644 --- a/luprex/syscpp/world.cpp +++ b/luprex/syscpp/world.cpp @@ -1,6 +1,7 @@ #include "world.hpp" #include "idalloc.hpp" +#include "animqueue.hpp" #include LuaDefineType(World); @@ -60,10 +61,6 @@ void World::init_standalone() { player->be_a_player(); } -std::vector World::scan_radius(const std::string &plane, float x, float y, float radius) { - return plane_map_.scan_radius(plane, x, y, radius); -} - Tangible *World::tangible_get(int64_t id) { auto iter = tangibles_.find(id); if (iter == tangibles_.end()) { @@ -73,6 +70,25 @@ Tangible *World::tangible_get(int64_t id) { } } +void World::update_view_map(AnimViewMap *vm, int64_t player_id, float radius) { + vm->clear_updated_bits(); + + // Update the player's AnimView first. + vm->update_one(tangible_get(player_id)->anim_queue_); + const AnimView *player_view = vm->get_one(player_id); + + // Find out where's the center of the world. + std::string plane = player_view->get_plane(); + util::XYZ xyz = player_view->get_xyz(); + + // Update AnimViews for every tangible near the player. + for (int64_t id : plane_map_.scan_radius(plane, xyz.x, xyz.y, 100.0)) { + vm->update_one(tangible_get(id)->anim_queue_); + } + + vm->delete_non_updated(); +} + Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { LuaVar tangibles, metatab; LuaRet database; @@ -86,6 +102,7 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { assert(t->world_ == nullptr); t->world_ = this; t->plane_item_.set_id(id); + t->anim_queue_.set_id(id); plane_map_.track(&t->plane_item_); // Create the tangible's database and metatable. diff --git a/luprex/syscpp/world.hpp b/luprex/syscpp/world.hpp index 61f4035e..495d034b 100644 --- a/luprex/syscpp/world.hpp +++ b/luprex/syscpp/world.hpp @@ -82,11 +82,12 @@ public: // lua_State *get_lua_state() { return lua_state_; } - // scan_near + // update_view_map // - // Get a list of the tangibles near the specified player ID. + // Update the view map with information about all the tangibles near + // the specified player. // - std::vector scan_radius(const std::string &plane, float x, float y, float radius); + void update_view_map(AnimViewMap *vm, int64_t player_id, float radius); // Make a tangible. //