Created
June 20, 2017 06:44
-
-
Save Vavius/6ba9274e8b817cf7dcee00fcb98d6970 to your computer and use it in GitHub Desktop.
Entityx moai bindings
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
//----------------------------------------------------------------// | |
// 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 |
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
//----------------------------------------------------------------// | |
// 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