summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-01-30 22:16:40 +0100
committerThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-01-31 21:50:49 +0100
commit4cd1957231605e976c5cf001eddea80d5e49272f (patch)
tree1fd13522adeb62c408562a4ff76c98ee2e254342
parentbc291713c56a2bc27ec10cef52dd3a52a0579c7d (diff)
downloadmanaserv-4cd1957231605e976c5cf001eddea80d5e49272f.tar.gz
manaserv-4cd1957231605e976c5cf001eddea80d5e49272f.tar.bz2
manaserv-4cd1957231605e976c5cf001eddea80d5e49272f.tar.xz
manaserv-4cd1957231605e976c5cf001eddea80d5e49272f.zip
Use a full user data object for MapObject references
Based on a templated helper class, MapObject references in Lua scripts are now full user data objects. Using the '__index' member of their metatable, a library is associated with it so that member functions can be called directly on the object. Reviewed-by: Yohann Ferreira Reviewed-by: Erik Schilling
-rw-r--r--example/serverdata/scripts/npcs/merchant.lua10
-rw-r--r--src/scripting/lua.cpp66
-rw-r--r--src/scripting/luautil.cpp5
-rw-r--r--src/scripting/luautil.h66
4 files changed, 94 insertions, 53 deletions
diff --git a/example/serverdata/scripts/npcs/merchant.lua b/example/serverdata/scripts/npcs/merchant.lua
index 23035b11..c3bd36a0 100644
--- a/example/serverdata/scripts/npcs/merchant.lua
+++ b/example/serverdata/scripts/npcs/merchant.lua
@@ -48,6 +48,7 @@ function Merchant(npc, ch, buy_sell_table)
else
table.insert (choice_table, "Can you make me a price for what I have?")
end
+ table.insert (choice_table, "Tell me about the objects on this map")
table.insert (choice_table, "Nevermind...")
local v = do_choice(npc, ch, choice_table)
@@ -94,6 +95,15 @@ function Merchant(npc, ch, buy_sell_table)
end
end
+ elseif v == 3 then
+
+ local objects = mana.map_get_objects()
+ do_message(npc, ch, "There are " .. #objects .. " objects on this map, their names are:")
+ for i=1,#objects do
+ do_message(npc, ch, tostring(i) .. ": " .. objects[i]:name())
+ end
+
end
+
do_message(npc, ch, "See you later!")
end
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index c7053b3c..63149792 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -2500,31 +2500,17 @@ static int map_get_objects(lua_State *s)
static int map_object_get_property(lua_State *s)
{
const char *key = luaL_checkstring(s, 2);
- if (!lua_islightuserdata(s, 1))
- {
- raiseScriptError(s, "map_object_get_property called with invalid"
- "object handle");
- return 0;
- }
- MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
- if (obj)
+ MapObject *obj = LuaMapObject::check(s, 1);
+
+ std::string property = obj->getProperty(key);
+ if (!property.empty())
{
- std::string property = obj->getProperty(key);
- if (!property.empty())
- {
- lua_pushstring(s, property.c_str());
- return 1;
- }
- else
- {
- // scripts can check for nil
- return 0;
- }
+ lua_pushstring(s, property.c_str());
+ return 1;
}
else
{
- raiseScriptError(s, "map_object_get_property called with invalid"
- "object handle");
+ // scripts can check for nil
return 0;
}
}
@@ -2535,13 +2521,7 @@ static int map_object_get_property(lua_State *s)
*/
static int map_object_get_bounds(lua_State *s)
{
- if (!lua_islightuserdata(s, 1))
- {
- raiseScriptError(s, "map_object_get_bounds called with invalid"
- "object handle");
- return 0;
- }
- MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ MapObject *obj = LuaMapObject::check(s, 1);
const Rectangle &bounds = obj->getBounds();
lua_pushinteger(s, bounds.x);
lua_pushinteger(s, bounds.y);
@@ -2556,13 +2536,7 @@ static int map_object_get_bounds(lua_State *s)
*/
static int map_object_get_name(lua_State *s)
{
- if (!lua_islightuserdata(s, 1))
- {
- raiseScriptError(s, "map_object_get_name called with invalid"
- "object handle");
- return 0;
- }
- MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ MapObject *obj = LuaMapObject::check(s, 1);
lua_pushstring(s, obj->getName().c_str());
return 1;
}
@@ -2573,13 +2547,7 @@ static int map_object_get_name(lua_State *s)
*/
static int map_object_get_type(lua_State *s)
{
- if (!lua_islightuserdata(s, 1))
- {
- raiseScriptError(s, "map_object_get_type called with invalid"
- "object handle");
- return 0;
- }
- MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ MapObject *obj = LuaMapObject::check(s, 1);
lua_pushstring(s, obj->getType().c_str());
return 1;
}
@@ -2718,16 +2686,22 @@ LuaScript::LuaScript():
{ "log", &log },
{ "get_distance", &get_distance },
{ "map_get_objects", &map_get_objects },
- { "map_object_get_property", &map_object_get_property },
- { "map_object_get_bounds", &map_object_get_bounds },
- { "map_object_get_name", &map_object_get_name },
- { "map_object_get_type", &map_object_get_type },
{ "announce", &announce },
{ NULL, NULL }
};
luaL_register(mState, "mana", callbacks);
lua_pop(mState, 1); // pop the 'mana' table
+ static luaL_Reg const members_MapObject[] = {
+ { "property", &map_object_get_property },
+ { "bounds", &map_object_get_bounds },
+ { "name", &map_object_get_name },
+ { "type", &map_object_get_type },
+ { NULL, NULL }
+ };
+
+ LuaMapObject::registerType(mState, "MapObject", members_MapObject);
+
// Make script object available to callback functions.
lua_pushlightuserdata(mState, (void *)&registryKey);
lua_pushlightuserdata(mState, this);
diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp
index a7521426..b7680c6b 100644
--- a/src/scripting/luautil.cpp
+++ b/src/scripting/luautil.cpp
@@ -116,8 +116,3 @@ void push(lua_State *s, double val)
{
lua_pushnumber(s, val);
}
-
-void push(lua_State *s, MapObject *val)
-{
- lua_pushlightuserdata(s, val);
-}
diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h
index ee3f1142..4f456ab6 100644
--- a/src/scripting/luautil.h
+++ b/src/scripting/luautil.h
@@ -44,19 +44,81 @@ void raiseScriptError(lua_State *s, const char *format, ...);
void raiseWarning(lua_State *s, const char *format, ...);
+/**
+ * A helper class for pushing and checking custom Lua user data types.
+ */
+template <typename T>
+class LuaUserData
+{
+public:
+ /**
+ * Creates a metatable to be used for the user data associated with the
+ * type. Then, registers the \a members with a library named \a typeName,
+ * and sets the '__index' member of the metatable to this library.
+ */
+ static void registerType(lua_State *s,
+ const char *typeName,
+ const luaL_Reg *members)
+ {
+ mTypeName = typeName;
+
+ luaL_newmetatable(s, mTypeName); // metatable
+ lua_pushstring(s, "__index"); // metatable, "__index"
+ luaL_register(s, typeName, members); // metatable, "__index", {}
+ lua_rawset(s, -3); // metatable
+ lua_pop(s, 1); // -empty-
+ }
+
+ /**
+ * Pushes a userdata reference to the given object on the stack. Either by
+ * creating one, or reusing an existing one.
+ */
+ static int push(lua_State *L, T *object)
+ {
+ T **userData = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
+ *userData = object;
+
+ luaL_newmetatable(L, mTypeName);
+ lua_setmetatable(L, -2);
+
+ return 1;
+ }
+
+ /**
+ * Returns the argument at position \a narg when it is of the right type,
+ * and raises a Lua error otherwise.
+ */
+ static T *check(lua_State *L, int narg)
+ {
+ void *userData = luaL_checkudata(L, narg, mTypeName);
+ return *(static_cast<T**>(userData));
+ }
+
+private:
+ static const char *mTypeName;
+};
+
+template <typename T> const char * LuaUserData<T>::mTypeName;
+
+typedef LuaUserData<MapObject> LuaMapObject;
+
+
NPC *getNPC(lua_State *s, int p);
Character *getCharacter(lua_State *s, int p);
Monster *getMonster(lua_State *s, int p);
Being *getBeing(lua_State *s, int p);
-
/* Polymorphic wrapper for pushing variables.
Useful for templates.*/
void push(lua_State *s, int val);
void push(lua_State *s, const std::string &val);
void push(lua_State *s, Thing *val);
void push(lua_State *s, double val);
-void push(lua_State *s, MapObject *val);
+
+inline void push(lua_State *s, MapObject *val)
+{
+ LuaMapObject::push(s, val);
+}
/* Pushes an STL LIST */