Skip to content

Instantly share code, notes, and snippets.

@Vavius
Created June 20, 2017 06:44
Show Gist options
  • Save Vavius/6ba9274e8b817cf7dcee00fcb98d6970 to your computer and use it in GitHub Desktop.
Save Vavius/6ba9274e8b817cf7dcee00fcb98d6970 to your computer and use it in GitHub Desktop.
Entityx moai bindings
//----------------------------------------------------------------//
// Copyright (c) 2016 CloudTeam, Inc
// All Rights Reserved.
//----------------------------------------------------------------//
#ifndef DOBA_DOBA_COMPONENT_BASE_IMPL_H
#define DOBA_DOBA_COMPONENT_BASE_IMPL_H
#include <components/DOBAComponentBase.h>
#include <doba-util/DOBAGetSetHelper.h>
//================================================================//
// ComponentHelper
//================================================================//
/* Borrowed from entityx_lua
*/
template < typename C >
class DOBAComponentHelper {
public:
using ptr = entityx::ComponentHandle < C >;
//----------------------------------------------------------------//
template < typename T >
static ptrdiff_t Offset ( T ptr ) {
C c;
return static_cast < char* >( static_cast < void* >( &( c.*ptr ))) - static_cast < char* >( static_cast < void* >( &c ));
}
//----------------------------------------------------------------//
template < typename T >
static T& Get ( C* c, ptrdiff_t offset ) {
return *static_cast < T* >( static_cast < void* >( static_cast < char* >( static_cast < void* >( c )) + offset ));
}
};
//================================================================//
// Lua
//================================================================//
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_add ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase < C >, "UN" )
if ( !self->mEntityMgr ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: attempt to use component wrapper without valid DOBASim. Use :setSim() first \n" );
return 0;
}
entityx::Entity entity;
DOBAGetSetHelper::GetValue ( state, 2, self->mEntityMgr, entity );
if ( !entity ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: invalid entity id \n" );
return 0;
}
entityx::ComponentHandle < C > component = entity.replace < C >();
self->SetComponent ( component );
return 0;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_get ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase < C >, "UN" )
if ( !self->mEntityMgr ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: attempt to use component wrapper without valid DOBASim. Use :setSim() first \n" );
return 0;
}
entityx::Entity entity;
DOBAGetSetHelper::GetValue ( state, 2, self->mEntityMgr, entity );
if ( !entity ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: invalid entity id \n" );
return 0;
}
entityx::ComponentHandle < C > component = entity.component < C >();
self->SetComponent ( component );
state.Push ( component.valid ());
return 1;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_has ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase, "UN" )
if ( !self->mEntityMgr ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: attempt to use component wrapper without valid DOBASim. Use :setSim() first \n" );
return 0;
}
entityx::Entity entity;
DOBAGetSetHelper::GetValue ( state, 2, self->mEntityMgr, entity );
if ( entity ) {
state.Push ( entity.has_component < C >());
return 1;
}
return 0;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_remove ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase, "UN" )
if ( !self->mEntityMgr ) {
MOAILogF ( state, ZLLog::LOG_ERROR, "DOBA component: attempt to use component wrapper without valid DOBASim. Use :setSim() first \n" );
return 0;
}
entityx::Entity entity;
DOBAGetSetHelper::GetValue ( state, 2, self->mEntityMgr, entity );
if ( entity ) {
entity.remove < C >();
}
return 0;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_setSim ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase < C >, "U" )
DOBASim* sim = state.GetLuaObject < DOBASim >( 2, false );
self->SetSim ( sim );
return 0;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_valid ( lua_State* L ) {
MOAI_LUA_SETUP ( DOBAComponentBase < C >, "U" )
state.Push ( self->mHandle.valid ());
return 1;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_index ( lua_State* L ) {
MOAILuaState state ( L );
// stack:
// 1: self
// 2: key
DOBAComponentBase < C >* self = state.GetLuaObject < DOBAComponentBase < C > >( 1, false );
cc8* key = state.GetValue < cc8* >( 2, 0 );
// push property register table
lua_pushvalue ( state, lua_upvalueindex ( 1 ));
if ( state.GetFieldWithType ( -1, key, LUA_TFUNCTION )) {
// stack:
// -4: self
// -3: key
// -2: properties
// -1: getset function
// pop the properties table
lua_remove ( state, -2 );
// stack:
// -3: self
// -2: key
// -1: getset function
// copy userdata to top
lua_pushvalue ( state, -3 );
lua_pushnil ( state );
lua_call ( state, 2, 1 );
return 1;
}
// fallback to member table
lua_pop ( state, 1 );
self->PushMemberTable ( state );
lua_getfield ( state, -1, key );
// stack:
// 1: self
// 2: key
// 3: member table
// 4: return value
// pop the member table
lua_remove ( state, -2 );
return 1;
}
//----------------------------------------------------------------//
template < typename C >
int DOBAComponentBase < C >::_newIndex ( lua_State* L ) {
MOAILuaState state ( L );
// stack:
// 1: self
// 2: key
// 3: value
// DOBAComponentBase < C >* self = state.GetLuaObject < DOBAComponentBase < C > >( 1, false );
cc8* key = state.GetValue < cc8* >( 2, 0 );
// push property register table
lua_pushvalue ( state, lua_upvalueindex ( 1 ));
if ( state.GetFieldWithType ( -1, key, LUA_TFUNCTION )) {
// stack:
// -5: self
// -4: key
// -3: value
// -2: properties
// -1: getset function
// pop the properties table
lua_remove ( state, -2 );
// stack:
// -4: self
// -3: key
// -2: value
// -1: getset function
// copy userdata to top
lua_pushvalue ( state, -4 );
// copy value to top
lua_pushvalue ( state, -3 );
lua_call ( state, 2, 0 );
}
// TODO: allow storing user values in member table or report error?
return 0;
}
//================================================================//
// DOBAComponentBase
//================================================================//
//----------------------------------------------------------------//
template < typename C >
DOBAComponentBase < C >::DOBAComponentBase ():
mMetatableInstalled ( false ) {
RTTI_BEGIN
RTTI_EXTEND ( MOAILuaObject )
RTTI_END
}
//----------------------------------------------------------------//
template < typename C >
DOBAComponentBase < C >::~DOBAComponentBase () {
this->mSim.Set ( *this, 0 );
}
//----------------------------------------------------------------//
template < typename C >
void DOBAComponentBase < C >::RegisterLuaFuncs ( MOAILuaState& state ) {
luaL_Reg regTable [] = {
{ "add", _add },
{ "get", _get },
{ "has", _has },
{ "remove", _remove },
{ "setSim", _setSim },
{ "valid", _valid },
{ NULL, NULL }
};
luaL_register ( state, 0, regTable );
int top = lua_gettop ( state );
// push property register table
//
// Property register is indexed by property name
// keys are getset functions (getter and setter is the same function)
// offset is stored as upvalue
lua_newtable ( state );
this->RegisterProperties ( state );
// store property register in the interface table
lua_setfield ( state, -2, "_properties" );
lua_settop ( state, top );
}
//----------------------------------------------------------------//
template < typename C >
template < typename T >
void DOBAComponentBase < C >::RegisterProperty ( cc8* name, T C::*ptr, MOAILuaState& state ) {
// stack:
// -1: property register table
ptrdiff_t offset = DOBAComponentHelper < C >::Offset ( ptr );
lua_pushinteger ( state, offset );
lua_pushcclosure ( state, []( lua_State* L ) -> int {
MOAILuaState cState ( L );
// stack:
// -1: value to set or nil
// -2: userdata
ptrdiff_t cOffset = lua_tointeger ( L, lua_upvalueindex ( 1 ));
DOBAComponentBase < C >* component = cState.GetLuaObject < DOBAComponentBase < C > >( -2, false );
C* handle = component->mHandle.get ();
T& value = DOBAComponentHelper < C >::template Get < T > ( handle, cOffset );
if ( lua_isnil ( L, -1 )) {
DOBAGetSetHelper::Push ( cState, value );
return 1;
}
else {
DOBAGetSetHelper::GetValue ( cState, -1, value );
return 0;
}
}, 1);
lua_setfield ( state, -2, name );
}
//----------------------------------------------------------------//
template < typename C >
void DOBAComponentBase < C >::RegisterProperty ( cc8* name, entityx::Entity C::*ptr, MOAILuaState& state ) {
// stack:
// -1: property register table
ptrdiff_t offset = DOBAComponentHelper < C >::Offset ( ptr );
lua_pushinteger ( state, offset );
lua_pushcclosure ( state, []( lua_State* L ) -> int {
MOAILuaState cState ( L );
// stack:
// -1: value to set or nil
// -2: userdata
ptrdiff_t cOffset = lua_tointeger ( L, lua_upvalueindex ( 1 ));
DOBAComponentBase < C >* component = cState.GetLuaObject < DOBAComponentBase < C > >( -2, false );
C* handle = component->mHandle.get ();
entityx::Entity& value = DOBAComponentHelper < C >::template Get < entityx::Entity > ( handle, cOffset );
if ( lua_isnil ( L, -1 )) {
uint64_t entID = value.id (). id ();
DOBAGetSetHelper::Push ( cState, entID );
return 1;
}
else {
entityx::Entity ent;
entityx::EntityManager* em = component->mHandle.manager ();
DOBAGetSetHelper::GetValue ( cState, -1, em, ent );
if ( ent.valid ()) {
value = ent;
}
return 0;
}
}, 1);
lua_setfield ( state, -2, name );
}
//----------------------------------------------------------------//
template < typename C >
void DOBAComponentBase < C >::SetComponent ( entityx::ComponentHandle < C > handle ) {
this->mHandle = handle;
if ( !this->mMetatableInstalled ) {
MOAIScopedLuaState state = MOAILuaRuntime::Get ().State ();
if ( this->PushRefTable ( state )) {
this->PushMemberTable ( state );
lua_getmetatable ( state, -1 );
// stack:
// 1: ref table
// 2: member table
// 3: interface table
lua_pushstring ( state, "_properties" );
lua_rawget ( state, -2 );
// stack:
// 1: ref table
// 2: member table
// 3: interface table
// 4: property register table
lua_remove ( state, -3 );
lua_remove ( state, -2 );
if ( state.IsType ( -1, LUA_TTABLE )) {
// duplicate register table. It will become upvalue for both __index and __newindex
lua_pushvalue ( state, -1 );
lua_pushcclosure ( state, DOBAComponentBase < C >::_index, 1 );
// stack:
// 1: ref
// 2: register
// 3: closure
lua_setfield ( state, -3, "__index" );
lua_pushcclosure ( state, DOBAComponentBase < C >::_newIndex, 1 );
lua_setfield ( state, -2, "__newindex" );
this->mMetatableInstalled = true;
}
}
}
}
//----------------------------------------------------------------//
template < typename C >
void DOBAComponentBase < C >::SetSim ( DOBASim* sim ) {
this->mSim.Set ( *this, sim );
if ( sim ) {
this->mEntityMgr = &sim->GetEntityMgr ();
}
else {
this->mEntityMgr = 0;
}
}
#endif
//----------------------------------------------------------------//
// Copyright (c) 2016 CloudTeam, Inc
// All Rights Reserved.
//----------------------------------------------------------------//
#ifndef DOBA_DOBA_COMPONENT_BASE_CPP
#define DOBA_DOBA_COMPONENT_BASE_CPP
#define DOBA_DECL_FIELD(__comp__, __field__) this->RegisterProperty ( #__field__, &__comp__::__field__, state );
#include <DOBASim.h>
//================================================================//
// DOBAComponentBase
//================================================================//
template < typename C >
class DOBAComponentBase :
public MOAILuaObject {
private:
using Handle = entityx::ComponentHandle < C >;
bool mMetatableInstalled;
MOAILuaSharedPtr < DOBASim > mSim;
entityx::EntityManager* mEntityMgr;
//----------------------------------------------------------------//
static int _index ( lua_State* L );
static int _newIndex ( lua_State* L );
//----------------------------------------------------------------//
static int _add ( lua_State* L );
static int _get ( lua_State* L );
static int _has ( lua_State* L );
static int _remove ( lua_State* L );
static int _setSim ( lua_State* L );
static int _valid ( lua_State* L );
protected:
Handle mHandle;
virtual void RegisterProperties ( MOAILuaState& state ) = 0;
template < typename T >
void RegisterProperty ( cc8* name, T C::*ptr, MOAILuaState& state );
// Overloading templated function, hmm. This one should have priority over templated variant.
void RegisterProperty ( cc8* name, entityx::Entity C::*ptr, MOAILuaState& state );
public:
DOBAComponentBase ();
virtual ~DOBAComponentBase ();
void RegisterLuaFuncs ( MOAILuaState& state );
void SetComponent ( Handle handle );
void SetSim ( DOBASim* sim );
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment