Last active
April 18, 2017 07:26
-
-
Save shakesoda/cb09229d69a1144901a23a7d8f82d10f to your computer and use it in GitHub Desktop.
basic binding of PECS to lua, using kaguya.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <lua.hpp> | |
#include <cstdint> | |
#include <vector> | |
#include "kaguya.hpp" | |
#include "pecs.hpp" | |
using namespace std; | |
using namespace pecs; | |
#define GENERATE_COMPONENT(ENUM, TYPE, NAME) \ | |
vector<TYPE> NAME##s; \ | |
void assign(entity_t *entity, TYPE component) { \ | |
entity->mask |= ENUM ; \ | |
size_t c = this->NAME##s.capacity(); \ | |
while (c <= entity->id) { \ | |
c = max<size_t>(c, 1); \ | |
c = c << 1; \ | |
} \ | |
if (this->NAME##s.size() <= entity->id) { \ | |
this->NAME##s.reserve(c); \ | |
this->NAME##s.resize(entity->id+1); \ | |
} \ | |
this->NAME##s[entity->id] = component; \ | |
} \ | |
TYPE & get_##NAME (int id) { \ | |
return NAME##s[id]; \ | |
} \ | |
void add_##NAME (entity_t *entity, TYPE comp) { \ | |
this->assign(entity, comp); \ | |
} | |
enum { | |
// NB: component 0 can't be used. | |
COMPONENT_NONE = ~0, | |
COMPONENT_THING = 1 << 1 | |
}; | |
static lua_State *s_lua = nullptr; | |
struct LuaSystem : system_t { | |
kaguya::LuaFunction luaProcess; | |
kaguya::LuaFunction luaUpdate; | |
LuaSystem(int priority, uint64_t mask, kaguya::LuaFunction process_fn, kaguya::LuaFunction update_fn): | |
luaProcess(process_fn), | |
luaUpdate(update_fn) | |
{ | |
this->priority = priority; | |
this->mask = mask; | |
} | |
// depends on za_warudo, so define later. | |
void update(double dt); | |
}; | |
struct component_thing { | |
int thing() { | |
return 1; | |
} | |
int thang = 5; | |
}; | |
struct za_warudo : world_t { | |
GENERATE_COMPONENT(COMPONENT_THING, component_thing, thing); | |
// expects table such as: | |
// { | |
// priority = int, | |
// components = { COMPONENT_FOO, ... } (optional), | |
// update = function(dt) end (optional), | |
// process = function(dt, e, c) end (optional) | |
// } | |
void add_lua_system(kaguya::LuaTable params) { | |
int priority = params["priority"].get<int>(); | |
bool valid; | |
auto values = params["components"].get<vector<uint64_t>>(valid, true); | |
uint64_t mask = 0; | |
for (uint64_t v : values) { | |
mask |= v; | |
} | |
kaguya::LuaFunction fn1 = params["process"]; | |
kaguya::LuaFunction fn2 = params["update"]; | |
if (mask == 0) mask = COMPONENT_NONE; | |
if (fn1.isNilref()) fn1 = kaguya::LuaFunction(); | |
if (fn2.isNilref()) fn2 = kaguya::LuaFunction(); | |
auto sys = new LuaSystem(priority, mask, fn1, fn2); | |
this->add(sys); | |
} | |
// these fix lua binding | |
void add_entity(entity_t ent) { this->add(ent); } | |
entity_t get_entity() { return world_t::get_entity(); } | |
void update(double dt) { world_t::update(dt); } | |
}; | |
// calls system.update(dt) and system.process(dt, entity, components = {}) | |
void LuaSystem::update(double dt) { | |
za_warudo *world = (za_warudo*)this->world; | |
kaguya::State lua(s_lua); | |
this->luaUpdate(dt); | |
for (auto &entity : world->entities) { | |
PECS_SKIP_INVALID_ENTITY; | |
auto components = lua.newTable(); | |
#define PUSH_COMPONENT(MASK, NAME) if ((this->mask & MASK) == MASK) { components[#NAME] = &world->get_##NAME(entity.id); } | |
PUSH_COMPONENT(COMPONENT_THING, thing); | |
#undef PUSH_COMPONENT | |
this->luaProcess(dt, entity, components); | |
} | |
} | |
extern "C" int luaopen_ldex(lua_State *L) { | |
s_lua = L; | |
kaguya::State lua(L); | |
kaguya::LuaTable module = lua.newTable(); | |
module["Thing"].setClass(kaguya::UserdataMetatable<component_thing>() | |
.setConstructors<component_thing()>() | |
.addFunction("thing", &component_thing::thing) | |
.addProperty("thang", &component_thing::thang) | |
); | |
module["World"].setClass(kaguya::UserdataMetatable<za_warudo, world_t>() | |
.setConstructors<za_warudo()>() | |
.addFunction("add_system", &za_warudo::add_lua_system) | |
.addFunction("new_entity", &za_warudo::get_entity) | |
.addFunction("add_entity", &za_warudo::add_entity) | |
.addFunction("add_thing", &za_warudo::add_thing) | |
.addFunction("update", &za_warudo::update) | |
); | |
#define LSET(NAME) module[#NAME] = NAME | |
LSET(COMPONENT_NONE); | |
LSET(COMPONENT_THING); | |
#undef LSET | |
return module.push(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment