World model is now operational

This commit is contained in:
2021-01-16 01:24:33 -05:00
parent d7d633bd96
commit 313e78067a
11 changed files with 313 additions and 188 deletions

View File

@@ -1,5 +1,6 @@
#include "animqueue.hpp" #include "animqueue.hpp"
#include "luastack.hpp"
#include <limits> #include <limits>
@@ -16,7 +17,7 @@ AnimQueue::AnimQueue(int size_limit) {
init.xyz_ = util::XYZ(0,0,0); init.xyz_ = util::XYZ(0,0,0);
init.graphic_ = "nothing"; init.graphic_ = "nothing";
init.plane_ = "nowhere"; init.plane_ = "nowhere";
init.bits_ = 0; init.bits_ = AnimStep::HAS_EVERYTHING;
} }
void AnimQueue::add(int64_t id, const std::string &action) { void AnimQueue::add(int64_t id, const std::string &action) {
@@ -33,7 +34,7 @@ void AnimQueue::add(int64_t id, const std::string &action) {
AnimStep &init = steps_.front(); AnimStep &init = steps_.front();
init.id_ = 0; init.id_ = 0;
init.action_ = ""; init.action_ = "";
init.bits_ = 0; init.bits_ = AnimStep::HAS_EVERYTHING;
} }
void AnimQueue::set_facing(float f) { void AnimQueue::set_facing(float f) {
@@ -59,3 +60,64 @@ void AnimQueue::set_plane(const std::string &p) {
last.bits_ |= AnimStep::HAS_PLANE; last.bits_ |= AnimStep::HAS_PLANE;
last.plane_ = p; last.plane_ = p;
} }
const std::string &AnimQueue::get_plane() const {
const AnimStep &last = steps_.back();
return last.plane_;
}
const util::XYZ &AnimQueue::get_xyz() const {
const AnimStep &last = steps_.back();
return last.xyz_;
}
LuaDefine(unittests_animqueue, "c") {
// Check initial state.
AnimQueue aq(3);
LuaAssert(L, aq.size() == 1);
const AnimStep *st = &aq.nth(0);
LuaAssert(L, st->id() == 0);
LuaAssert(L, st->action() == "");
LuaAssert(L, st->bits() == AnimStep::HAS_EVERYTHING);
LuaAssert(L, st->facing() == 0.0);
LuaAssert(L, st->xyz() == util::XYZ(0,0,0));
LuaAssert(L, st->graphic() == "nothing");
LuaAssert(L, st->plane() == "nowhere");
// Add a step.
aq.add(12345, "walk");
LuaAssert(L, aq.size() == 2);
st = &aq.nth(1);
LuaAssert(L, st->id() == 12345);
LuaAssert(L, st->action() == "walk");
LuaAssert(L, st->bits() == 0);
LuaAssert(L, st->facing() == 0.0);
LuaAssert(L, st->xyz() == util::XYZ(0,0,0));
LuaAssert(L, st->graphic() == "nothing");
LuaAssert(L, st->plane() == "nowhere");
// Test the setters.
aq.set_facing(180);
LuaAssert(L, st->facing() == 180);
LuaAssert(L, st->bits() == AnimStep::HAS_FACING);
aq.set_xyz(util::XYZ(3,4,5));
LuaAssert(L, st->xyz() == util::XYZ(3, 4, 5));
LuaAssert(L, st->bits() == (AnimStep::HAS_FACING | AnimStep::HAS_XYZ));
aq.set_plane("somewhere");
LuaAssert(L, st->plane() == "somewhere");
LuaAssert(L, st->bits() == (AnimStep::HAS_FACING | AnimStep::HAS_XYZ | AnimStep::HAS_PLANE));
aq.set_graphic("something");
LuaAssert(L, st->graphic() == "something");
LuaAssert(L, st->bits() == (AnimStep::HAS_FACING | AnimStep::HAS_XYZ | AnimStep::HAS_PLANE | AnimStep::HAS_GRAPHIC));
// Exceed the length limit, dropping first element.
aq.add(12346, "walk");
aq.add(12347, "walk");
LuaAssert(L, aq.size() == 3);
LuaAssert(L, aq.nth(0).id() == 0);
LuaAssert(L, aq.nth(0).action() == "");
LuaAssert(L, aq.nth(0).bits() == AnimStep::HAS_EVERYTHING);
LuaAssert(L, aq.nth(1).id() == 12346);
LuaAssert(L, aq.nth(2).id() == 12347);
return 0;
}

View File

@@ -39,6 +39,7 @@ public:
HAS_XYZ = 2, HAS_XYZ = 2,
HAS_GRAPHIC = 4, HAS_GRAPHIC = 4,
HAS_PLANE = 8, HAS_PLANE = 8,
HAS_EVERYTHING = 15,
}; };
private: private:
@@ -85,6 +86,10 @@ public:
void set_xyz(util::XYZ xyz); void set_xyz(util::XYZ xyz);
void set_graphic(const std::string &g); void set_graphic(const std::string &g);
void set_plane(const std::string &p); void set_plane(const std::string &p);
// Get the final resting place.
const std::string &get_plane() const;
const util::XYZ &get_xyz() const;
}; };
#endif // ANIMQUEUE_HPP #endif // ANIMQUEUE_HPP

View File

@@ -129,7 +129,7 @@ private:
public: public:
// Construct a player pool. // Construct a player pool.
// The Player pool stores a pointer to the global pool. // The Player pool stores a pointer to the global pool.
IdPlayerPool(IdGlobalPool *gp); IdPlayerPool(IdGlobalPool *igp);
~IdPlayerPool(); ~IdPlayerPool();
// Refill the fifo queue of batches from the global pool. // Refill the fifo queue of batches from the global pool.

View File

@@ -14,7 +14,7 @@
#include <string> #include <string>
#include "luastack.hpp" #include "luastack.hpp"
#include "util.hpp" #include "util.hpp"
#include "source.hpp" #include "world.hpp"
#include "traceback.hpp" #include "traceback.hpp"
@@ -174,43 +174,10 @@ static void dotty(lua_State *L)
fflush(stdout); fflush(stdout);
} }
static int pmain(lua_State *L)
{
globalL = L;
LUAJIT_VERSION_SYM(); /* Linker-enforced version check. */
LuaStack::register_all_userdata(L);
// Initialize the builtins, then copy a snapshot of the
// builtins to the registry. The snapshot will allow us to restore
// the builtins during source_rebuild operations.
source_install_and_snapshot_builtins(L);
// Load the lua source.
source_update(L);
// Rebuild the global environment.
source_rebuild(L);
// Run unit tests.
source_run_unittests(L);
dotty(L);
return 0;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int status; LUAJIT_VERSION_SYM(); // Linker-enforced version check.
lua_State *L = lua_open(); World w;
if (L == NULL) dotty(w.get_lua_state());
{ return 0;
l_message("cannot create state: not enough memory");
return -1;
}
status = lua_cpcall(L, pmain, NULL);
report(L, status);
lua_close(L);
return status ? -1 : 0;
} }

View File

@@ -13,7 +13,7 @@
#define CELL_INVALID 0 #define CELL_INVALID 0
// Round a float and return as integer. Clamp result to the specified range. // Round a float and return as integer. Clamp result to the specified range.
static int round_and_clamp(double x, int lo, int hi) { static int round_and_clamp(float x, int lo, int hi) {
x = round(x); x = round(x);
if (x < lo) return lo; if (x < lo) return lo;
if (x > hi) return hi; if (x > hi) return hi;
@@ -38,7 +38,7 @@ struct CellRange {
// the map: in that case, returns exactly the valid cells and not the // the map: in that case, returns exactly the valid cells and not the
// invalid ones. // invalid ones.
// //
static CellRange rect_cell_range(double x1, double y1, double x2, double y2) { static CellRange rect_cell_range(float x1, float y1, float x2, float y2) {
CellRange result; CellRange result;
result.xlo = round_and_clamp(x1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1); result.xlo = round_and_clamp(x1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1);
result.ylo = round_and_clamp(y1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1); result.ylo = round_and_clamp(y1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT + 1);
@@ -54,9 +54,9 @@ static int64_t cell_id(int64_t cellx, int64_t celly) {
} }
// Get the cell ID of the specified point, or CELL_INVALID if the point is off the map. // Get the cell ID of the specified point, or CELL_INVALID if the point is off the map.
static int64_t point_cell_id(double x, double y) { static int64_t point_cell_id(float x, float y) {
double cellx = round(x / CELL_SCALE); float cellx = round(x / CELL_SCALE);
double celly = round(y / CELL_SCALE); float celly = round(y / CELL_SCALE);
if ((cellx < -CELL_LIMIT) || (celly < -CELL_LIMIT) || (cellx > CELL_LIMIT) || (celly > CELL_LIMIT)) { if ((cellx < -CELL_LIMIT) || (celly < -CELL_LIMIT) || (cellx > CELL_LIMIT) || (celly > CELL_LIMIT)) {
return CELL_INVALID; return CELL_INVALID;
} }
@@ -101,9 +101,9 @@ void PlaneMap::insert(const std::string &plane, int64_t cellid, PlaneItem *clien
l.push_back(client); l.push_back(client);
} }
void PlaneItem::set_pos(const std::string &plane, double x, double y, double z) { void PlaneItem::set_pos(const std::string &plane, const util::XYZ &xyz) {
int64_t old_cell = point_cell_id(x_, y_); int64_t old_cell = point_cell_id(xyz_.x, xyz_.y);
int64_t new_cell = point_cell_id(x, y); int64_t new_cell = point_cell_id(xyz.x, xyz.y);
// Update the grid. // Update the grid.
if (pmap_ != 0) { if (pmap_ != 0) {
@@ -115,14 +115,12 @@ void PlaneItem::set_pos(const std::string &plane, double x, double y, double z)
// Update the client position. // Update the client position.
plane_ = plane; plane_ = plane;
x_ = x; xyz_ = xyz;
y_ = y;
z_ = z;
} }
void PlaneItem::untrack() { void PlaneItem::untrack() {
if (pmap_ != 0) { if (pmap_ != 0) {
pmap_->remove(plane_, point_cell_id(x_, y_), this); pmap_->remove(plane_, point_cell_id(xyz_.x, xyz_.y), this);
pmap_ = 0; pmap_ = 0;
} }
} }
@@ -135,7 +133,7 @@ void PlaneMap::track(PlaneItem *item) {
} }
} }
PlaneItem::PlaneItem() : pmap_(NULL), x_(0.0), y_(0.0), z_(0.0) { PlaneItem::PlaneItem() : pmap_(NULL), xyz_(0,0,0) {
} }
PlaneMap::PlaneMap() { PlaneMap::PlaneMap() {
@@ -176,13 +174,13 @@ int PlaneMap::total_cells() const {
return total; return total;
} }
PlaneMap::EltVec PlaneMap::scan_radius(const std::string &plane, double x, double y, double radius) const { PlaneMap::EltVec PlaneMap::scan_radius(const std::string &plane, float x, float y, float radius) const {
PlaneMap::EltVec result; PlaneMap::EltVec result;
auto piter = planes_.find(plane); auto piter = planes_.find(plane);
if (piter != planes_.end()) { if (piter != planes_.end()) {
const Plane &p = piter->second; const Plane &p = piter->second;
CellRange range = rect_cell_range(x - radius, y - radius, x + radius, y + radius); CellRange range = rect_cell_range(x - radius, y - radius, x + radius, y + radius);
double radsq = radius*radius; float radsq = radius*radius;
for (int cy = range.ylo; cy <= range.yhi; cy++) { for (int cy = range.ylo; cy <= range.yhi; cy++) {
for (int cx = range.xlo; cx <= range.xhi; cx++) { for (int cx = range.xlo; cx <= range.xhi; cx++) {
auto liter = p.find(cell_id(cx, cy)); auto liter = p.find(cell_id(cx, cy));
@@ -200,8 +198,8 @@ PlaneMap::EltVec PlaneMap::scan_radius(const std::string &plane, double x, doubl
} }
LuaDefine(unittests_planemap, "c") { LuaDefine(unittests_planemap, "c") {
double SC = CELL_SCALE; float SC = CELL_SCALE;
double E = CELL_SCALE * 0.4; float E = CELL_SCALE * 0.4;
int LO = -CELL_LIMIT; int LO = -CELL_LIMIT;
int HI = CELL_LIMIT; int HI = CELL_LIMIT;
PlaneMap pm; PlaneMap pm;
@@ -314,5 +312,15 @@ LuaDefine(unittests_planemap, "c") {
elts = pm.scan_radius("bar", 1000.0, 1000.0, 100.0); elts = pm.scan_radius("bar", 1000.0, 1000.0, 100.0);
LuaAssert(L, elts.size() == 2); LuaAssert(L, elts.size() == 2);
// Test static_field_cast.
struct MyTangible {
int x, y, z;
PlaneItem plane_item_;
};
MyTangible tan;
PlaneItem *pip = &tan.plane_item_;
MyTangible *tanp = pip->static_field_cast<MyTangible>();
LuaAssert(L, tanp == &tan);
return 0; return 0;
} }

View File

@@ -74,8 +74,10 @@
#define PLANEMAP_HPP #define PLANEMAP_HPP
#include <cstdint> #include <cstdint>
#include <cstddef>
#include <vector> #include <vector>
#include <map> #include <map>
#include "util.hpp"
class PlaneMap; class PlaneMap;
@@ -85,20 +87,38 @@ class PlaneItem {
private: private:
PlaneMap *pmap_; PlaneMap *pmap_;
std::string plane_; std::string plane_;
double x_, y_, z_; util::XYZ xyz_;
public: public:
PlaneItem(); PlaneItem();
~PlaneItem(); ~PlaneItem();
const std::string &plane() const { return plane_; } const std::string &plane() const { return plane_; }
const double x() const { return x_; } const util::XYZ &xyz() const { return xyz_; }
const double y() const { return y_; } const float x() const { return xyz_.x; }
const double z() const { return z_; } const float y() const { return xyz_.y; }
const float z() const { return xyz_.z; }
void untrack(); void untrack();
void set_pos(const std::string &plane, double x, double y, double z); void set_pos(const std::string &plane, const util::XYZ &xyz);
void set_xyz(double x, double y, double z) { set_pos(plane_, x, y, z); } void set_pos(const std::string &plane, float x, float y, float z) { set_pos(plane, util::XYZ(x,y,z)); }
void set_xyz(const util::XYZ &xyz) { set_pos(plane_, xyz); }
void set_xyz(float x, float y, float z) { set_pos(plane_, util::XYZ(x, y, z)); }
// Assume that some other object has methods 'get_plane' and 'get_xyz'.
// Get the plane and XYZ from that object and store it in this PlaneItem.
template<class T>
void set_pos_from(const T &obj) {
set_pos(obj.get_plane(), obj.get_xyz());
}
// Assume that the PlaneItem is a field in an object of class T.
// Static cast the PlaneItem pointer to a type T pointer.
template<class T>
T *static_field_cast() {
const std::size_t offset = offsetof(T, plane_item_);
return reinterpret_cast<T*>(reinterpret_cast<char*>(this) - offset);
}
}; };
class PlaneMap { class PlaneMap {
@@ -114,7 +134,7 @@ public:
PlaneMap(); PlaneMap();
~PlaneMap(); ~PlaneMap();
void track(PlaneItem *item); void track(PlaneItem *item);
EltVec scan_radius(const std::string &plane, double x, double y, double radius) const; EltVec scan_radius(const std::string &plane, float x, float y, float radius) const;
private: private:
// unit testing stuff. // unit testing stuff.

View File

@@ -64,7 +64,7 @@ static void load_builtin(lua_State *L, const char *name, lua_CFunction func) {
lua_call(L, 1, 0); lua_call(L, 1, 0);
} }
LuaDefine(source_install_builtins, "") { static void source_install_builtins(lua_State *L) {
LuaStack LS(L); LuaStack LS(L);
load_builtin(L, "base", luaopen_base); load_builtin(L, "base", luaopen_base);
load_builtin(L, "table", luaopen_table); load_builtin(L, "table", luaopen_table);
@@ -72,11 +72,10 @@ LuaDefine(source_install_builtins, "") {
load_builtin(L, "math", luaopen_math); load_builtin(L, "math", luaopen_math);
load_builtin(L, "bit", luaopen_math); load_builtin(L, "bit", luaopen_math);
load_builtin(L, "debug", luaopen_debug); load_builtin(L, "debug", luaopen_debug);
// Do not load: package, io, os, debug, jit
return 0;
} }
LuaDefine(source_install_and_snapshot_builtins, "") { void SourceDB::initialize(lua_State *L) {
lua_state_ = L;
LuaVar key, value, skey, svalue, snapshot, ssnapshot; LuaVar key, value, skey, svalue, snapshot, ssnapshot;
LuaStack LS(L, snapshot, key, value, skey, svalue, ssnapshot); LuaStack LS(L, snapshot, key, value, skey, svalue, ssnapshot);
@@ -99,10 +98,10 @@ LuaDefine(source_install_and_snapshot_builtins, "") {
} }
} }
LS.setfield(LuaRegistry, "source_snapshot_builtins", snapshot); LS.setfield(LuaRegistry, "source_snapshot_builtins", snapshot);
return LS.result(); LS.result();
} }
LuaDefine(source_updatefile, "") { static int source_updatefile(lua_State *L) {
LuaArg source, fn; LuaArg source, fn;
LuaRet info; LuaRet info;
LuaVar fingerprint, null; LuaVar fingerprint, null;
@@ -127,7 +126,7 @@ LuaDefine(source_updatefile, "") {
if (LS.isstring(fingerprint)) { if (LS.isstring(fingerprint)) {
old_fingerprint = LS.ckstring(fingerprint); old_fingerprint = LS.ckstring(fingerprint);
} }
std::cerr << "Probing " << cfn << std::endl; // std::cerr << "Probing " << cfn << std::endl;
std::string new_fingerprint = util::get_file_fingerprint("syslua/" + cfn); std::string new_fingerprint = util::get_file_fingerprint("syslua/" + cfn);
LS.set(null, LuaNil); LS.set(null, LuaNil);
if ((old_fingerprint == "") || (old_fingerprint != new_fingerprint)) { if ((old_fingerprint == "") || (old_fingerprint != new_fingerprint)) {
@@ -147,7 +146,8 @@ LuaDefine(source_updatefile, "") {
return LS.result(); return LS.result();
} }
LuaDefine(source_update, "c") { void SourceDB::update() {
lua_State *L = lua_state_;
LuaVar sourcedb, newdb, info, fn, seq; LuaVar sourcedb, newdb, info, fn, seq;
LuaStack LS(L, newdb, sourcedb, info, fn, seq); LuaStack LS(L, newdb, sourcedb, info, fn, seq);
@@ -180,13 +180,13 @@ LuaDefine(source_update, "c") {
// Store the new source db. // Store the new source db.
LS.setfield(LuaRegistry, "sourcedb", newdb); LS.setfield(LuaRegistry, "sourcedb", newdb);
return LS.result(); LS.result();
} }
// Delete everything from the global environment except // Delete everything from the global environment except
// the class tables and the class action tables. // the class tables and the class action tables.
// //
LuaDefine(source_clear_globals, "") { static void source_clear_globals(lua_State *L) {
LuaVar classname, classtab, action, key; LuaVar classname, classtab, action, key;
LuaStack LS(L, classname, classtab, action, key); LuaStack LS(L, classname, classtab, action, key);
@@ -209,12 +209,12 @@ LuaDefine(source_clear_globals, "") {
} }
} }
LS.setfield(LuaGlobals, "_G", LuaGlobals); LS.setfield(LuaGlobals, "_G", LuaGlobals);
return LS.result(); LS.result();
} }
// Restore the lua builtins from the backup snapshot. // Restore the lua builtins from the backup snapshot.
// //
LuaDefine(source_restore_builtins, "") { static void source_restore_builtins(lua_State *L) {
LuaVar snapshot, key, value, skey, svalue, subglobal; LuaVar snapshot, key, value, skey, svalue, subglobal;
LuaStack LS(L, snapshot, key, value, skey, svalue, subglobal); LuaStack LS(L, snapshot, key, value, skey, svalue, subglobal);
@@ -229,12 +229,12 @@ LuaDefine(source_restore_builtins, "") {
LS.rawset(subglobal, skey, svalue); LS.rawset(subglobal, skey, svalue);
} }
} }
return LS.result(); LS.result();
} }
// Load all the 'LuaDefine' C functions into the lua state. // Load all the 'LuaDefine' C functions into the lua state.
// //
LuaDefine(source_load_cfunctions, "") { static void source_load_cfunctions(lua_State *L) {
auto regs = LuaFunctionReg::all(); auto regs = LuaFunctionReg::all();
for (const LuaFunctionReg *r : regs) { for (const LuaFunctionReg *r : regs) {
const std::string &name = r->get_name(); const std::string &name = r->get_name();
@@ -260,12 +260,11 @@ LuaDefine(source_load_cfunctions, "") {
lua_setglobal(L, funcname.c_str()); lua_setglobal(L, funcname.c_str());
} }
} }
return 0;
} }
// Run all the closures from the source database. // Run all the closures from the source database.
// //
LuaDefine(source_load_lfunctions, "") { static void source_load_lfunctions(lua_State *L) {
LuaRet errors; LuaRet errors;
LuaVar sourcedb, key, info, seq, closure, err; LuaVar sourcedb, key, info, seq, closure, err;
LuaStack LS(L, sourcedb, errors, key, info, seq, closure, err); LuaStack LS(L, sourcedb, errors, key, info, seq, closure, err);
@@ -305,10 +304,11 @@ LuaDefine(source_load_lfunctions, "") {
} }
} }
LS.set(errors, errss.str()); LS.set(errors, errss.str());
return LS.result(); LS.result();
} }
LuaDefine(source_rebuild, "c") { void SourceDB::rebuild() {
lua_State *L = lua_state_;
LuaVar errs; LuaVar errs;
LuaStack LS(L, errs); LuaStack LS(L, errs);
source_clear_globals(L); source_clear_globals(L);
@@ -318,13 +318,13 @@ LuaDefine(source_rebuild, "c") {
lua_replace(L, errs.index()); lua_replace(L, errs.index());
std::string errstr = LS.ckstring(errs); std::string errstr = LS.ckstring(errs);
std::cerr << errstr; std::cerr << errstr;
return LS.result(); LS.result();
} }
LuaDefine(source_run_unittests, "c") { void SourceDB::run_unittests() {
lua_State *L = lua_state_;
LuaVar unittests, name, func, err; LuaVar unittests, name, func, err;
LuaRet rescode; LuaStack LS(L, unittests, name, func, err);
LuaStack LS(L, unittests, name, func, err, rescode);
LS.getfield(unittests, LuaGlobals, "unittests"); LS.getfield(unittests, LuaGlobals, "unittests");
@@ -351,8 +351,9 @@ LuaDefine(source_run_unittests, "c") {
} }
} }
// Return 1 if any errors. if (any) {
LS.set(rescode, any ? 1 : 0); exit(1);
return LS.result(); }
LS.result();
} }

View File

@@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// SOURCE // SOURCEDB
// //
// This module manages the loading of lua source files into the Lua environment. // This module manages the loading of lua source files into the Lua environment.
// Since the source files can be reloaded over and over, this module doesn't // Since the source files can be reloaded over and over, this module doesn't
@@ -9,7 +9,6 @@
// that should be there. That way, if you delete something from a lua source // that should be there. That way, if you delete something from a lua source
// file, it gets removed from the lua global environment. // file, it gets removed from the lua global environment.
// //
//
// THE MAKECLASS OPERATOR // THE MAKECLASS OPERATOR
// //
// This module provides a new lua 'builtin' operator: "makeclass". This creates // This module provides a new lua 'builtin' operator: "makeclass". This creates
@@ -31,12 +30,15 @@
// //
// THE LUA SOURCE DATABASE // THE LUA SOURCE DATABASE
// //
// The function 'source_update' loads the lua source code from disk, and stores // Class SourceDB only contains a single pointer to the lua environment. That's
// it in the "source database." The source database is a table inside the lua // because all the data for SourceDB is stored in the lua registry.
// registry. // Specifically, the registry contains these keys:
// //
// The source database is a lua table where the keys are filenames, and the // 1. The source database proper (registry key "sourcedb")
// values are information about that file: // 2. The snapshot of builtins (registry key "source_snapshot_builtins")
//
// The source database proper is a table where the keys are filenames, and the
// values are records containing information about that file:
// //
// "foo.lua" : { // "foo.lua" : {
// "name": "foo.lua", // "name": "foo.lua",
@@ -55,23 +57,24 @@
// error message. Finally, "sequence" indicates the order in which the source // error message. Finally, "sequence" indicates the order in which the source
// files are meant to be loaded. // files are meant to be loaded.
// //
// The operation "source_update" refreshes the source database from disk. It // The operation SourceDB::update refreshes the source database from disk. It
// doesn't reread files whose fingerprints have not changed. In a synchronous // doesn't reread files whose fingerprints have not changed. In a synchronous
// model, we don't call source_update - instead, we update the source database // model, we don't call SourceDB::update - instead, we update the source
// by difference transmission. // database by difference transmission.
// //
// Note that updating the source database has *no effect* on the lua global // Note that updating the source database has *no effect* on the lua global
// variables (or lua function definitions). The source_update operation calls // variables (or lua function definitions). The SourceDB::update operation
// lua's "load" on the code, but all that does is return a loaded closure. // calls lua's "load" on the code, but all that does is return a loaded closure.
// Nothing happens to the lua invironment until you *invoke* the loaded closure. // Nothing happens to the lua invironment until you *invoke* the loaded closure.
// That doesn't happen until you do a source_rebuild operation, described below. // That doesn't happen until you do a SourceDB::rebuild operation, described
// below.
// //
// //
// SOURCE REBUILDS, IN DEPTH // SOURCE REBUILDS, IN DEPTH
// //
// The function source_rebuild clears and then rebuilds the entire contents of // The function SourceDB::rebuild clears and then rebuilds the entire contents
// the global environment. The reason to clear the environment is that if we // of the lua global environment. The reason to clear the environment is that
// didn't clear it, then removing a function from the lua source would not // if we didn't clear it, then removing a function from the lua source would not
// remove it from the lua environment. Rebuilding the lua environment is a // remove it from the lua environment. Rebuilding the lua environment is a
// multi-step process: // multi-step process:
// //
@@ -83,7 +86,7 @@
// //
// * Lua Builtin functions are reinstalled in the global environment. // * Lua Builtin functions are reinstalled in the global environment.
// //
// - To make this possible, a snapshot of these builtins is kept. // - To make this possible, the snapshot of builtins is used.
// //
// * C++ functions registered with "LuaDefine" are reinstalled. // * C++ functions registered with "LuaDefine" are reinstalled.
// //
@@ -102,15 +105,15 @@
// UNITTESTS // UNITTESTS
// //
// We reserve the lua class name 'unittests' for storing unit tests. Any // We reserve the lua class name 'unittests' for storing unit tests. Any
// function placed into this class is considered a unit test. We don't // function placed into this class is considered a unit test. We don't separate
// separate unit tests from the rest of the code - they're compiled right // unit tests from the rest of the code - they're compiled right into the main
// into the main binary. // binary.
// //
// Unit tests can be either lua functions, or Lua-registered C functions. // Unit tests can be either lua functions, or Lua-registered C functions. Unit
// Unit tests are executed by calling 'source_run_unittests'. // tests are executed by calling 'source_run_unittests'.
// //
// Each unit test is run in a protected 'pcall' environment. Any errors // Each unit test is run in a protected 'pcall' environment. Any errors are
// are printed out to console. (At least for now). // printed out to console. (At least for now).
// //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@@ -119,6 +122,46 @@
#include "luastack.hpp" #include "luastack.hpp"
class SourceDB {
private:
lua_State *lua_state_;
public:
// Initialize
//
// This must be called while the lua state is still pristine.
// This will install the builtin operators into the lua state
// and will snapshot those builtins to the registry.
//
void initialize(lua_State *L);
// Update
//
// Read all the lua source files from disk and store them in the
// source database. Also compiles these files using lua's "load"
// function. Efficient: if a source file is already in the database
// and hasn't been modified, it is not reloaded.
//
void update();
// Rebuild
//
// Rebuild the lua environment: clear it out, then reinstall all the
// functions that should be there. See above for more information.
// If an error exists in any of the source files, or when loading any
// of the closures, the error is (currently) printed. We'll come up
// with better error handling later.
//
void rebuild();
// run_unittests
//
// Run all the unit tests. Print any errors to console. If there
// are any errors, exits the program.
//
void run_unittests();
};
// The Lua 'makeclass' operator. // The Lua 'makeclass' operator.
// //
// Creates a table in the global environment with the specified name. // Creates a table in the global environment with the specified name.
@@ -128,41 +171,6 @@
// //
int source_makeclass(lua_State *L); int source_makeclass(lua_State *L);
// source_install_and_snapshot_builtins.
//
// Install the lua builtins into a brand new lua state, and then create the
// snapshot of the builtins (in the registry). This uses lua_openlibs, which
// only works if the lua environment is brand new. Do not try to use
// source_snapshot_builtins unless the lua environment has just been created
// using lua_newstate!
//
int source_install_and_snapshot_builtins(lua_State *L);
// source_update
//
// Read all the lua source files from disk and store them in the
// source database. Also compiles these files using lua's "load"
// function. Efficient: if a source file is already in the database
// and hasn't been modified, it is not reloaded.
//
int source_update(lua_State *L);
// source_rebuild
//
// Rebuild the lua environment: clear it out, then reinstall all the
// functions that should be there. See above for more information.
// If an error exists in any of the source files, or when loading any
// of the closures, the error is (currently) printed. We'll come up
// with better error handling later.
//
int source_rebuild(lua_State *L);
// source_run_unittests
//
// Run all the unit tests. Print any errors to console. Pushes zero
// onto the lua stack if there are no errors, or one if there are.
//
int source_run_unittests(lua_State *L);
#endif // SOURCE_HPP #endif // SOURCE_HPP

View File

@@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
#include <tuple> #include <tuple>
#include <utility>
namespace util { namespace util {
@@ -48,6 +49,7 @@ struct XYZ {
float x, y, z; float x, y, z;
XYZ() { x=0; y=0; z=0; } XYZ() { x=0; y=0; z=0; }
XYZ(float ix, float iy, float iz) { x=ix; y=iy; z=iz; } XYZ(float ix, float iy, float iz) { x=ix; y=iy; z=iz; }
bool operator ==(const XYZ &o) { return x==o.x && y == o.y && z==o.z; }
}; };
} // namespace util } // namespace util

View File

@@ -1,17 +1,41 @@
#include "world.hpp" #include "world.hpp"
#include "idalloc.hpp" #include "idalloc.hpp"
#include <iostream>
LuaDefineType(World); LuaDefineType(World);
World::~World() { World::~World() {
} }
void World::init(lua_State *L) { World::World() {
// Create the lua state.
lua_state_ = lua_open();
if (lua_state_ == nullptr) {
std::cerr << "Cannot create lua state." << std::endl;
exit(1);
}
// Initialize the userdata metatables.
LuaStack::register_all_userdata(lua_state_);
// Prepare to manipulate the lua state.
LuaVar world; LuaVar world;
LuaStack LS(L, world); LuaStack LS(lua_state_, world);
LS.newpointer(world, new World, false);
// Put the world pointer into the lua registry.
LS.newpointer(world, this, false);
LS.setfield(LuaRegistry, "world", world); LS.setfield(LuaRegistry, "world", world);
// Initialize the SourceDB
source_db_.initialize(lua_state_);
// Do an initial lua source update and then environment rebuild.
source_db_.update();
source_db_.rebuild();
// Run unit tests.
source_db_.run_unittests();
} }
World *World::fetch(lua_State *L) { World *World::fetch(lua_State *L) {
@@ -23,23 +47,3 @@ World *World::fetch(lua_State *L) {
return w; return w;
} }
LuaDefine(world_init, "c") {
World::init(L);
return 0;
}
LuaDefine(world_setid, "c") {
LuaArg id;
LuaStack LS(L, id);
World *w = World::fetch(L);
w->id_ = LS.ckinteger(id);
return LS.result();
}
LuaDefine(world_getid, "c") {
LuaRet id;
LuaStack LS(L, id);
World *w = World::fetch(L);
LS.set(id, w->id_);
return LS.result();
};

View File

@@ -1,30 +1,78 @@
// Note about header file dependencies:
//
// world.hpp contains a lot of forward declarations.
// That's because it is at the bottom of the dependency stack:
// everyone includes world.hpp.
//
// However, world.cpp is at the top of the dependency stack,
// it includes everyone else.
//
#ifndef WORLD_HPP #ifndef WORLD_HPP
#define WORLD_HPP #define WORLD_HPP
#include "luastack.hpp" #include "luastack.hpp"
#include "planemap.hpp"
#include "idalloc.hpp"
#include "animqueue.hpp"
#include "source.hpp"
#include <memory> #include <memory>
#include <unordered_map>
class IdGlobalPool; class World;
class Tangible {
public:
// Always points back to the world model.
World *world_;
// Animation queue and plane item.
//
// To update the position of this tangible, first add an animation in which
// the tangible moves, then call plane_item.set_pos_from(anim_queue_).
PlaneItem plane_item_;
AnimQueue anim_queue_;
// Player ID pool
//
// Note: this is only allocated if this Tangible is a player.
std::unique_ptr<IdPlayerPool> id_player_pool_;
};
class World { class World {
public: public:
int id_; // A pointer to the lua State.
std::unique_ptr<IdGlobalPool> id_pool_; //
lua_State *lua_state_;
World() : id_(0) {}; // The Global ID Pool.
//
IdGlobalPool id_global_pool_;
// Source Database.
//
SourceDB source_db_;
PlaneMap plane_map_;
std::unordered_map<int64_t, Tangible> tangibles_;
public:
// Constructor.
//
// The constructor also calls 'lua_open' to create a new
// lua interpreter for this world model. The lua interpreter
// is stored in world::lua_state_. A significant amount of
// initial setup is done by this constructor.
//
World();
// Destructor.
//
// Not currently functional.
//
~World(); ~World();
static void init(lua_State *L); // get_lua_state
//
// Get the lua interpreter associated with this world model.
//
lua_State *get_lua_state() { return lua_state_; }
// fetch
//
// Given a lua state, fetch the world model associated with
// that lua state.
//
static World *fetch(lua_State *L); static World *fetch(lua_State *L);
}; };