Skip to content

Instantly share code, notes, and snippets.

@shakesoda
Created April 18, 2017 06:52
Show Gist options
  • Save shakesoda/bf2484483b536aaaf4536e48beafb093 to your computer and use it in GitHub Desktop.
Save shakesoda/bf2484483b536aaaf4536e48beafb093 to your computer and use it in GitHub Desktop.
basic binding of PECS to lua, using kaguya.
#include <lua.hpp>
#include "kaguya.hpp"
#include "pecs.hpp"
using namespace pecs;
using namespace std;
enum {
// NB: component 0 can't be used.
COMPONENT_NONE = ~0,
COMPONENT_PLAYER = 1 << 1
};
template <typename T>
static void resize(vector<T> &components, uint32_t id) {
size_t c = components.capacity();
while (c <= id) {
c = max<size_t>(c, 1);
c = c << 1;
}
if (components.size() <= id) {
components.reserve(c);
components.resize(id+1);
}
}
#define GENERATE_COMPONENT(ENUM, TYPE, NAME) \
vector<TYPE> NAME##s; \
void assign(entity_t *entity, TYPE component) { \
entity->mask |= ENUM ; \
resize(this->NAME##s, entity->id); \
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); \
}
struct LuaSystem : system_t {
kaguya::LuaFunction luaProcess;
kaguya::LuaFunction luaUpdate;
LuaSystem(int priority, uint64_t mask, kaguya::LuaFunction process_fn, kaguya::LuaFunction update_fn);
void update(double dt);
};
// WRYYYYYYYYYYYYYYYYYY
struct za_warudo : world_t {
// GENERATE_COMPONENT(COMPONENT_PLAYER, component_player_t, player);
void add_lua_system(kaguya::LuaTable params);
void add_entity(entity_t ent);
// fixes lua binding.
entity_t get_entity() {
return world_t::get_entity();
}
};
#undef GENERATE_COMPONENT
LuaSystem::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;
}
static lua_State *s_lua = nullptr;
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_RENDER, drawable);
#undef PUSH_COMPONENT
this->luaProcess(dt, entity, components);
}
}
void za_warudo::add_lua_system(kaguya::LuaTable params) {
int priority = params["priority"];
uint64_t mask = 0;
bool valid;
auto values = params["components"].get<vector<uint64_t>>(valid, true);
for (uint64_t v : values) {
mask |= v;
}
if (mask == 0) {
mask = COMPONENT_NONE;
}
kaguya::LuaFunction fn1 = params["process"];
kaguya::LuaFunction fn2 = params["update"];
if (fn1.isNilref()) {
fn1 = kaguya::LuaFunction();
}
if (fn2.isNilref()) {
fn2 = kaguya::LuaFunction();
}
auto sys = new LuaSystem(priority, mask, fn1, fn2);
this->add(sys);
}
void za_warudo::add_entity(entity_t ent) {
this->add(ent);
}
extern "C" int luaopen_ldex(lua_State *L) {
s_lua = L;
kaguya::State lua(L);
kaguya::LuaTable module = lua.newTable();
// lua["Player"].setClass(kaguya::UserdataMetatable<component_player_t>()
// .setConstructors<component_player_t()>()
// .addProperty("index", &component_player_t::index)
// );
auto mt = kaguya::UserdataMetatable<za_warudo, world_t>()
.addFunction("add_system", &za_warudo::add_lua_system)
.addFunction("new_entity", &za_warudo::get_entity)
.addFunction("add_entity", &za_warudo::add_entity)
// .addFunction("add_player", &za_warudo::add_player)
;
module["World"].setClass(mt);
#define LSET(NAME) module[#NAME] = NAME
LSET(COMPONENT_NONE);
#undef LSET
return module.push();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment