summaryrefslogtreecommitdiff
path: root/src/scripting
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2013-09-19 15:43:18 +0200
committerThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2013-09-19 16:54:32 +0200
commitcae44328f1f3ca9f7f13f9252d279231e3c8ef2a (patch)
tree5b31fecb2b3a76578d151fe7b6595eb8cb57deb4 /src/scripting
parentdf8e8de0e0850d54992ae4fc8727cbe17527ccb5 (diff)
downloadmanaserv-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.cpp2
-rw-r--r--src/scripting/luautil.cpp111
-rw-r--r--src/scripting/luautil.h51
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;