World model is now operational
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "animqueue.hpp"
|
||||
#include "luastack.hpp"
|
||||
#include <limits>
|
||||
|
||||
|
||||
@@ -16,7 +17,7 @@ AnimQueue::AnimQueue(int size_limit) {
|
||||
init.xyz_ = util::XYZ(0,0,0);
|
||||
init.graphic_ = "nothing";
|
||||
init.plane_ = "nowhere";
|
||||
init.bits_ = 0;
|
||||
init.bits_ = AnimStep::HAS_EVERYTHING;
|
||||
}
|
||||
|
||||
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();
|
||||
init.id_ = 0;
|
||||
init.action_ = "";
|
||||
init.bits_ = 0;
|
||||
init.bits_ = AnimStep::HAS_EVERYTHING;
|
||||
}
|
||||
|
||||
void AnimQueue::set_facing(float f) {
|
||||
@@ -59,3 +60,64 @@ void AnimQueue::set_plane(const std::string &p) {
|
||||
last.bits_ |= AnimStep::HAS_PLANE;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
HAS_XYZ = 2,
|
||||
HAS_GRAPHIC = 4,
|
||||
HAS_PLANE = 8,
|
||||
HAS_EVERYTHING = 15,
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -85,6 +86,10 @@ public:
|
||||
void set_xyz(util::XYZ xyz);
|
||||
void set_graphic(const std::string &g);
|
||||
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
|
||||
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
public:
|
||||
// Construct a player pool.
|
||||
// The Player pool stores a pointer to the global pool.
|
||||
IdPlayerPool(IdGlobalPool *gp);
|
||||
IdPlayerPool(IdGlobalPool *igp);
|
||||
~IdPlayerPool();
|
||||
|
||||
// Refill the fifo queue of batches from the global pool.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <string>
|
||||
#include "luastack.hpp"
|
||||
#include "util.hpp"
|
||||
#include "source.hpp"
|
||||
#include "world.hpp"
|
||||
#include "traceback.hpp"
|
||||
|
||||
|
||||
@@ -174,43 +174,10 @@ static void dotty(lua_State *L)
|
||||
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 status;
|
||||
lua_State *L = lua_open();
|
||||
if (L == NULL)
|
||||
{
|
||||
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;
|
||||
LUAJIT_VERSION_SYM(); // Linker-enforced version check.
|
||||
World w;
|
||||
dotty(w.get_lua_state());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define CELL_INVALID 0
|
||||
|
||||
// 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);
|
||||
if (x < lo) return lo;
|
||||
if (x > hi) return hi;
|
||||
@@ -38,7 +38,7 @@ struct CellRange {
|
||||
// the map: in that case, returns exactly the valid cells and not the
|
||||
// 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;
|
||||
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);
|
||||
@@ -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.
|
||||
static int64_t point_cell_id(double x, double y) {
|
||||
double cellx = round(x / CELL_SCALE);
|
||||
double celly = round(y / CELL_SCALE);
|
||||
static int64_t point_cell_id(float x, float y) {
|
||||
float cellx = round(x / CELL_SCALE);
|
||||
float celly = round(y / CELL_SCALE);
|
||||
if ((cellx < -CELL_LIMIT) || (celly < -CELL_LIMIT) || (cellx > CELL_LIMIT) || (celly > CELL_LIMIT)) {
|
||||
return CELL_INVALID;
|
||||
}
|
||||
@@ -101,9 +101,9 @@ void PlaneMap::insert(const std::string &plane, int64_t cellid, PlaneItem *clien
|
||||
l.push_back(client);
|
||||
}
|
||||
|
||||
void PlaneItem::set_pos(const std::string &plane, double x, double y, double z) {
|
||||
int64_t old_cell = point_cell_id(x_, y_);
|
||||
int64_t new_cell = point_cell_id(x, y);
|
||||
void PlaneItem::set_pos(const std::string &plane, const util::XYZ &xyz) {
|
||||
int64_t old_cell = point_cell_id(xyz_.x, xyz_.y);
|
||||
int64_t new_cell = point_cell_id(xyz.x, xyz.y);
|
||||
|
||||
// Update the grid.
|
||||
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.
|
||||
plane_ = plane;
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
z_ = z;
|
||||
xyz_ = xyz;
|
||||
}
|
||||
|
||||
void PlaneItem::untrack() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -176,13 +174,13 @@ int PlaneMap::total_cells() const {
|
||||
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;
|
||||
auto piter = planes_.find(plane);
|
||||
if (piter != planes_.end()) {
|
||||
const Plane &p = piter->second;
|
||||
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 cx = range.xlo; cx <= range.xhi; cx++) {
|
||||
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") {
|
||||
double SC = CELL_SCALE;
|
||||
double E = CELL_SCALE * 0.4;
|
||||
float SC = CELL_SCALE;
|
||||
float E = CELL_SCALE * 0.4;
|
||||
int LO = -CELL_LIMIT;
|
||||
int HI = CELL_LIMIT;
|
||||
PlaneMap pm;
|
||||
@@ -314,5 +312,15 @@ LuaDefine(unittests_planemap, "c") {
|
||||
elts = pm.scan_radius("bar", 1000.0, 1000.0, 100.0);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -74,8 +74,10 @@
|
||||
#define PLANEMAP_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.hpp"
|
||||
|
||||
class PlaneMap;
|
||||
|
||||
@@ -85,20 +87,38 @@ class PlaneItem {
|
||||
private:
|
||||
PlaneMap *pmap_;
|
||||
std::string plane_;
|
||||
double x_, y_, z_;
|
||||
util::XYZ xyz_;
|
||||
|
||||
public:
|
||||
PlaneItem();
|
||||
~PlaneItem();
|
||||
|
||||
const std::string &plane() const { return plane_; }
|
||||
const double x() const { return x_; }
|
||||
const double y() const { return y_; }
|
||||
const double z() const { return z_; }
|
||||
const util::XYZ &xyz() const { return xyz_; }
|
||||
const float x() const { return xyz_.x; }
|
||||
const float y() const { return xyz_.y; }
|
||||
const float z() const { return xyz_.z; }
|
||||
|
||||
void untrack();
|
||||
void set_pos(const std::string &plane, double x, double y, double z);
|
||||
void set_xyz(double x, double y, double z) { set_pos(plane_, x, y, z); }
|
||||
void set_pos(const std::string &plane, const util::XYZ &xyz);
|
||||
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 {
|
||||
@@ -114,7 +134,7 @@ public:
|
||||
PlaneMap();
|
||||
~PlaneMap();
|
||||
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:
|
||||
// unit testing stuff.
|
||||
|
||||
@@ -64,7 +64,7 @@ static void load_builtin(lua_State *L, const char *name, lua_CFunction func) {
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
|
||||
LuaDefine(source_install_builtins, "") {
|
||||
static void source_install_builtins(lua_State *L) {
|
||||
LuaStack LS(L);
|
||||
load_builtin(L, "base", luaopen_base);
|
||||
load_builtin(L, "table", luaopen_table);
|
||||
@@ -72,11 +72,10 @@ LuaDefine(source_install_builtins, "") {
|
||||
load_builtin(L, "math", luaopen_math);
|
||||
load_builtin(L, "bit", luaopen_math);
|
||||
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;
|
||||
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);
|
||||
return LS.result();
|
||||
LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(source_updatefile, "") {
|
||||
static int source_updatefile(lua_State *L) {
|
||||
LuaArg source, fn;
|
||||
LuaRet info;
|
||||
LuaVar fingerprint, null;
|
||||
@@ -127,7 +126,7 @@ LuaDefine(source_updatefile, "") {
|
||||
if (LS.isstring(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);
|
||||
LS.set(null, LuaNil);
|
||||
if ((old_fingerprint == "") || (old_fingerprint != new_fingerprint)) {
|
||||
@@ -147,7 +146,8 @@ LuaDefine(source_updatefile, "") {
|
||||
return LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(source_update, "c") {
|
||||
void SourceDB::update() {
|
||||
lua_State *L = lua_state_;
|
||||
LuaVar sourcedb, newdb, info, fn, seq;
|
||||
LuaStack LS(L, newdb, sourcedb, info, fn, seq);
|
||||
|
||||
@@ -180,13 +180,13 @@ LuaDefine(source_update, "c") {
|
||||
|
||||
// Store the new source db.
|
||||
LS.setfield(LuaRegistry, "sourcedb", newdb);
|
||||
return LS.result();
|
||||
LS.result();
|
||||
}
|
||||
|
||||
// Delete everything from the global environment except
|
||||
// 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;
|
||||
LuaStack LS(L, classname, classtab, action, key);
|
||||
|
||||
@@ -209,12 +209,12 @@ LuaDefine(source_clear_globals, "") {
|
||||
}
|
||||
}
|
||||
LS.setfield(LuaGlobals, "_G", LuaGlobals);
|
||||
return LS.result();
|
||||
LS.result();
|
||||
}
|
||||
|
||||
// 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;
|
||||
LuaStack LS(L, snapshot, key, value, skey, svalue, subglobal);
|
||||
|
||||
@@ -229,12 +229,12 @@ LuaDefine(source_restore_builtins, "") {
|
||||
LS.rawset(subglobal, skey, svalue);
|
||||
}
|
||||
}
|
||||
return LS.result();
|
||||
LS.result();
|
||||
}
|
||||
|
||||
// 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();
|
||||
for (const LuaFunctionReg *r : regs) {
|
||||
const std::string &name = r->get_name();
|
||||
@@ -260,12 +260,11 @@ LuaDefine(source_load_cfunctions, "") {
|
||||
lua_setglobal(L, funcname.c_str());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run all the closures from the source database.
|
||||
//
|
||||
LuaDefine(source_load_lfunctions, "") {
|
||||
static void source_load_lfunctions(lua_State *L) {
|
||||
LuaRet errors;
|
||||
LuaVar sourcedb, 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());
|
||||
return LS.result();
|
||||
LS.result();
|
||||
}
|
||||
|
||||
LuaDefine(source_rebuild, "c") {
|
||||
void SourceDB::rebuild() {
|
||||
lua_State *L = lua_state_;
|
||||
LuaVar errs;
|
||||
LuaStack LS(L, errs);
|
||||
source_clear_globals(L);
|
||||
@@ -318,13 +318,13 @@ LuaDefine(source_rebuild, "c") {
|
||||
lua_replace(L, errs.index());
|
||||
std::string errstr = LS.ckstring(errs);
|
||||
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;
|
||||
LuaRet rescode;
|
||||
LuaStack LS(L, unittests, name, func, err, rescode);
|
||||
LuaStack LS(L, unittests, name, func, err);
|
||||
|
||||
LS.getfield(unittests, LuaGlobals, "unittests");
|
||||
|
||||
@@ -351,8 +351,9 @@ LuaDefine(source_run_unittests, "c") {
|
||||
}
|
||||
}
|
||||
|
||||
// Return 1 if any errors.
|
||||
LS.set(rescode, any ? 1 : 0);
|
||||
return LS.result();
|
||||
if (any) {
|
||||
exit(1);
|
||||
}
|
||||
LS.result();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SOURCE
|
||||
// SOURCEDB
|
||||
//
|
||||
// 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
|
||||
@@ -9,7 +9,6 @@
|
||||
// that should be there. That way, if you delete something from a lua source
|
||||
// file, it gets removed from the lua global environment.
|
||||
//
|
||||
//
|
||||
// THE MAKECLASS OPERATOR
|
||||
//
|
||||
// This module provides a new lua 'builtin' operator: "makeclass". This creates
|
||||
@@ -31,12 +30,15 @@
|
||||
//
|
||||
// THE LUA SOURCE DATABASE
|
||||
//
|
||||
// The function 'source_update' loads the lua source code from disk, and stores
|
||||
// it in the "source database." The source database is a table inside the lua
|
||||
// registry.
|
||||
// Class SourceDB only contains a single pointer to the lua environment. That's
|
||||
// because all the data for SourceDB is stored in the lua registry.
|
||||
// Specifically, the registry contains these keys:
|
||||
//
|
||||
// The source database is a lua table where the keys are filenames, and the
|
||||
// values are information about that file:
|
||||
// 1. The source database proper (registry key "sourcedb")
|
||||
// 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" : {
|
||||
// "name": "foo.lua",
|
||||
@@ -55,23 +57,24 @@
|
||||
// error message. Finally, "sequence" indicates the order in which the source
|
||||
// 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
|
||||
// model, we don't call source_update - instead, we update the source database
|
||||
// by difference transmission.
|
||||
// model, we don't call SourceDB::update - instead, we update the source
|
||||
// database by difference transmission.
|
||||
//
|
||||
// Note that updating the source database has *no effect* on the lua global
|
||||
// variables (or lua function definitions). The source_update operation calls
|
||||
// lua's "load" on the code, but all that does is return a loaded closure.
|
||||
// variables (or lua function definitions). The SourceDB::update operation
|
||||
// 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.
|
||||
// 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
|
||||
//
|
||||
// The function source_rebuild clears and then rebuilds the entire contents of
|
||||
// the global environment. The reason to clear the environment is that if we
|
||||
// didn't clear it, then removing a function from the lua source would not
|
||||
// The function SourceDB::rebuild clears and then rebuilds the entire contents
|
||||
// of the lua global environment. The reason to clear the environment is that
|
||||
// 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
|
||||
// multi-step process:
|
||||
//
|
||||
@@ -83,7 +86,7 @@
|
||||
//
|
||||
// * 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.
|
||||
//
|
||||
@@ -102,15 +105,15 @@
|
||||
// UNITTESTS
|
||||
//
|
||||
// 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
|
||||
// separate unit tests from the rest of the code - they're compiled right
|
||||
// into the main binary.
|
||||
// function placed into this class is considered a unit test. We don't separate
|
||||
// unit tests from the rest of the code - they're compiled right into the main
|
||||
// binary.
|
||||
//
|
||||
// Unit tests can be either lua functions, or Lua-registered C functions.
|
||||
// Unit tests are executed by calling 'source_run_unittests'.
|
||||
// Unit tests can be either lua functions, or Lua-registered C functions. Unit
|
||||
// tests are executed by calling 'source_run_unittests'.
|
||||
//
|
||||
// Each unit test is run in a protected 'pcall' environment. Any errors
|
||||
// are printed out to console. (At least for now).
|
||||
// Each unit test is run in a protected 'pcall' environment. Any errors are
|
||||
// printed out to console. (At least for now).
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -119,6 +122,46 @@
|
||||
|
||||
#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.
|
||||
//
|
||||
// Creates a table in the global environment with the specified name.
|
||||
@@ -128,41 +171,6 @@
|
||||
//
|
||||
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
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace util {
|
||||
|
||||
@@ -48,6 +49,7 @@ struct XYZ {
|
||||
float x, y, z;
|
||||
XYZ() { x=0; y=0; z=0; }
|
||||
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
|
||||
|
||||
@@ -1,17 +1,41 @@
|
||||
|
||||
#include "world.hpp"
|
||||
#include "idalloc.hpp"
|
||||
#include <iostream>
|
||||
|
||||
LuaDefineType(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;
|
||||
LuaStack LS(L, world);
|
||||
LS.newpointer(world, new World, false);
|
||||
LuaStack LS(lua_state_, world);
|
||||
|
||||
// Put the world pointer into the lua registry.
|
||||
LS.newpointer(world, this, false);
|
||||
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) {
|
||||
@@ -23,23 +47,3 @@ World *World::fetch(lua_State *L) {
|
||||
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();
|
||||
};
|
||||
@@ -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
|
||||
#define WORLD_HPP
|
||||
|
||||
#include "luastack.hpp"
|
||||
#include "planemap.hpp"
|
||||
#include "idalloc.hpp"
|
||||
#include "animqueue.hpp"
|
||||
#include "source.hpp"
|
||||
#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 {
|
||||
public:
|
||||
int id_;
|
||||
std::unique_ptr<IdGlobalPool> id_pool_;
|
||||
// A pointer to the lua State.
|
||||
//
|
||||
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();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user