diff options
author | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2013-09-19 15:43:18 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2013-09-19 16:54:32 +0200 |
commit | cae44328f1f3ca9f7f13f9252d279231e3c8ef2a (patch) | |
tree | 5b31fecb2b3a76578d151fe7b6595eb8cb57deb4 /src/scripting | |
parent | df8e8de0e0850d54992ae4fc8727cbe17527ccb5 (diff) | |
download | manaserv-cae44328f1f3ca9f7f13f9252d279231e3c8ef2a.tar.gz manaserv-cae44328f1f3ca9f7f13f9252d279231e3c8ef2a.tar.bz2 manaserv-cae44328f1f3ca9f7f13f9252d279231e3c8ef2a.tar.xz manaserv-cae44328f1f3ca9f7f13f9252d279231e3c8ef2a.zip |
Have Lua use entity IDs instead of direct pointers
Allows to report access to removed entities instead of crashing.
Diffstat (limited to 'src/scripting')
-rw-r--r-- | src/scripting/lua.cpp | 2 | ||||
-rw-r--r-- | src/scripting/luautil.cpp | 111 | ||||
-rw-r--r-- | src/scripting/luautil.h | 51 |
3 files changed, 125 insertions, 39 deletions
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index a999744e..a84fe92d 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -3609,7 +3609,7 @@ LuaScript::LuaScript(): { nullptr, nullptr} }; - LuaEntity::registerType(mRootState, "Entity", members_Entity); + LuaEntity::registerType(mRootState, members_Entity); LuaItemClass::registerType(mRootState, "ItemClass", members_ItemClass); LuaMapObject::registerType(mRootState, "MapObject", members_MapObject); LuaMonsterClass::registerType(mRootState, "MonsterClass", members_MonsterClass); diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp index 4607c8dd..1408eb63 100644 --- a/src/scripting/luautil.cpp +++ b/src/scripting/luautil.cpp @@ -42,17 +42,15 @@ void raiseWarning(lua_State *, const char *format, ...) vsprintf(message, format, args); va_end( args ); - LOG_WARN("Lua script error: "<< message); + LOG_WARN("Lua script error: " << message); } -char UserDataCache::mRegistryKey; - -bool UserDataCache::retrieve(lua_State *s, void *object) +bool UserDataCache::retrieve(lua_State *s) { // Retrieve the cache table - lua_pushlightuserdata(s, &mRegistryKey); // key - lua_rawget(s, LUA_REGISTRYINDEX); // Cache? + lua_pushlightuserdata(s, &mRegistryKey); // object_key, key + lua_rawget(s, LUA_REGISTRYINDEX); // object_key, Cache? if (lua_isnil(s, -1)) { @@ -60,47 +58,110 @@ bool UserDataCache::retrieve(lua_State *s, void *object) return false; } - lua_pushlightuserdata(s, object); // Cache, object - lua_rawget(s, -2); // Cache, UD? + lua_pushvalue(s, -2); // object_key, Cache, object_key + lua_rawget(s, -2); // object_key, Cache, UD? if (lua_isnil(s, -1)) { - lua_pop(s, 2); // ... + lua_pop(s, 2); // object_key return false; } - lua_replace(s, -2); // UD + lua_replace(s, -3); // UD, Cache + lua_pop(s, 1); // UD return true; } -void UserDataCache::insert(lua_State *s, void *object) +void UserDataCache::insert(lua_State *s) { // Retrieve the cache table - lua_pushlightuserdata(s, &mRegistryKey); // UD, key - lua_rawget(s, LUA_REGISTRYINDEX); // UD, Cache? + lua_pushlightuserdata(s, &mRegistryKey); // object_key, UD, key + lua_rawget(s, LUA_REGISTRYINDEX); // object_key, UD, Cache? // Create the cache when it doesn't exist yet if (lua_isnil(s, -1)) { - lua_pop(s, 1); // UD - lua_newtable(s); // UD, Cache + lua_pop(s, 1); // object_key, UD + lua_newtable(s); // object_key, UD, Cache // The metatable that makes the values in the table above weak - lua_newtable(s); // UD, Cache, {} + lua_createtable(s, 0, 1); // object_key, UD, Cache, {} lua_pushliteral(s, "__mode"); lua_pushliteral(s, "v"); - lua_rawset(s, -3); // UD, Cache, { __mode = "v" } - lua_setmetatable(s, -2); // UD, Cache + lua_rawset(s, -3); // object_key, UD, Cache, { __mode = "v" } + lua_setmetatable(s, -2); // object_key, UD, Cache - lua_pushlightuserdata(s, &mRegistryKey);// UD, Cache, key - lua_pushvalue(s, -2); // UD, Cache, key, Cache - lua_rawset(s, LUA_REGISTRYINDEX); // UD, Cache + lua_pushlightuserdata(s, &mRegistryKey);// object_key, UD, Cache, key + lua_pushvalue(s, -2); // object_key, UD, Cache, key, Cache + lua_rawset(s, LUA_REGISTRYINDEX); // object_key, UD, Cache } - lua_pushlightuserdata(s, object); // UD, Cache, object - lua_pushvalue(s, -3); // UD, Cache, object, UD - lua_rawset(s, -3); // UD, Cache { object = UD } - lua_pop(s, 1); // UD + lua_pushvalue(s, -3); // object_key, UD, Cache, object_key + lua_pushvalue(s, -3); // object_key, UD, Cache, object_key, UD + lua_rawset(s, -3); // object_key, UD, Cache { object_key = UD } + lua_pop(s, 1); // object_key, UD + lua_replace(s, -2); // UD +} + + +UserDataCache LuaUserData<Entity>::mUserDataCache; + +void LuaUserData<Entity>::registerType(lua_State *s, const luaL_Reg *members) +{ + luaL_newmetatable(s, "Entity"); // metatable + lua_pushliteral(s, "__index"); // metatable, "__index" + lua_createtable(s, 0, 0); // metatable, "__index", {} +#if LUA_VERSION_NUM < 502 + luaL_register(s, nullptr, members); +#else + luaL_setfuncs(s, members, 0); +#endif + + // Make the functions table available as a global + lua_pushvalue(s, -1); // metatable, "__index", {}, {} + lua_setglobal(s, "Entity"); // metatable, "__index", {} + + lua_rawset(s, -3); // metatable + lua_pop(s, 1); // -empty- +} + +void LuaUserData<Entity>::push(lua_State *s, Entity *entity) +{ + if (!entity) + { + lua_pushnil(s); + } + else + { +#if LUA_VERSION_NUM < 502 + lua_pushnumber(s, entity->getId()); +#else + lua_pushunsigned(s, entity->getId()); +#endif + + if (!mUserDataCache.retrieve(s)) + { + void *userData = lua_newuserdata(s, sizeof(unsigned)); + * static_cast<unsigned*>(userData) = entity->getId(); + +#if LUA_VERSION_NUM < 502 + luaL_newmetatable(s, "Entity"); + lua_setmetatable(s, -2); +#else + luaL_setmetatable(s, "Entity"); +#endif + + mUserDataCache.insert(s); + } + } +} + +Entity *LuaUserData<Entity>::check(lua_State *L, int narg) +{ + void *userData = luaL_checkudata(L, narg, "Entity"); + Entity *entity = findEntity(*(static_cast<unsigned*>(userData))); + luaL_argcheck(L, entity, narg, "invalid entity"); + return entity; } diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h index fb4793a0..e38b01c8 100644 --- a/src/scripting/luautil.h +++ b/src/scripting/luautil.h @@ -62,21 +62,23 @@ class UserDataCache { public: /** - * Attempts to retrieve a userdata associated with the given object from - * the cache and pushes it on the stack when available. + * Attempts to retrieve a userdata associated with the key at the top of + * the stack from the cache and pushes it on the stack when available. + * When no userdata is found, the key is left on the stack. * * Returns whether a userdata was pushed. */ - static bool retrieve(lua_State *s, void *object); + bool retrieve(lua_State *s); /** * Inserts the userdata at the top of the stack in the cache using - * the given object as the key. Leaves the userdata on the stack. + * the key that is just below the top of the stack. Leaves the userdata on + * the stack. */ - static void insert(lua_State *s, void *object); + void insert(lua_State *s); private: - static char mRegistryKey; + char mRegistryKey; }; @@ -127,19 +129,24 @@ public: { lua_pushnil(s); } - else if (!UserDataCache::retrieve(s, object)) + else { - void *userData = lua_newuserdata(s, sizeof(T*)); - * static_cast<T**>(userData) = object; + lua_pushlightuserdata(s, object); + + if (!mUserDataCache.retrieve(s)) + { + void *userData = lua_newuserdata(s, sizeof(T*)); + * static_cast<T**>(userData) = object; #if LUA_VERSION_NUM < 502 - luaL_newmetatable(s, mTypeName); - lua_setmetatable(s, -2); + luaL_newmetatable(s, mTypeName); + lua_setmetatable(s, -2); #else - luaL_setmetatable(s, mTypeName); + luaL_setmetatable(s, mTypeName); #endif - UserDataCache::insert(s, object); + mUserDataCache.insert(s); + } } } @@ -155,9 +162,27 @@ public: private: static const char *mTypeName; + static UserDataCache mUserDataCache; }; template <typename T> const char * LuaUserData<T>::mTypeName; +template <typename T> UserDataCache LuaUserData<T>::mUserDataCache; + +/** + * Template specialization for entities, to allow their userdata to refer to + * the entity ID. + */ +template <> +class LuaUserData <Entity> +{ +public: + static void registerType(lua_State *s, const luaL_Reg *members); + static void push(lua_State *s, Entity *entity); + static Entity *check(lua_State *L, int narg); + +private: + static UserDataCache mUserDataCache; +}; typedef LuaUserData<Entity> LuaEntity; typedef LuaUserData<ItemClass> LuaItemClass; |