mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-08 21:54:19 +00:00
Merge pull request #82 from gfgtdf/split-lua
put functions declared in lua_api.hpp in a new file lua_api.cpp
This commit is contained in:
commit
6ebf28bd30
2
.gitignore
vendored
2
.gitignore
vendored
@ -67,3 +67,5 @@ uninstall.vcproj
|
||||
Project.ncb
|
||||
Project.suo
|
||||
*.vcproj.*.user
|
||||
projectfiles/VC10
|
||||
*Neuer Ordner*
|
||||
|
@ -804,6 +804,8 @@ set(wesnoth-main_SRC
|
||||
savegame.cpp
|
||||
scripting/debug_lua.cpp
|
||||
scripting/lua.cpp
|
||||
scripting/lua_api.cpp
|
||||
scripting/lua_types.cpp
|
||||
settings.cpp
|
||||
sha1.cpp
|
||||
side_filter.cpp
|
||||
|
@ -471,6 +471,8 @@ wesnoth_sources = Split("""
|
||||
savegame.cpp
|
||||
scripting/debug_lua.cpp
|
||||
scripting/lua.cpp
|
||||
scripting/lua_api.cpp
|
||||
scripting/lua_types.cpp
|
||||
settings.cpp
|
||||
sha1.cpp
|
||||
side_filter.cpp
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
#include "scripting/lua.hpp"
|
||||
#include "scripting/lua_api.hpp"
|
||||
#include "scripting/lua_types.hpp"
|
||||
|
||||
|
||||
#include "actions/attack.hpp"
|
||||
#include "ai/manager.hpp"
|
||||
@ -130,457 +132,6 @@ namespace {
|
||||
("_from_lua", map_location(), map_location(), config());
|
||||
}//unnamed namespace for queued_event_context
|
||||
|
||||
/* Dummy pointer for getting unique keys for Lua's registry. */
|
||||
static char const dlgclbkKey = 0;
|
||||
static char const executeKey = 0;
|
||||
static char const getsideKey = 0;
|
||||
static char const gettextKey = 0;
|
||||
static char const gettypeKey = 0;
|
||||
static char const getraceKey = 0;
|
||||
static char const getunitKey = 0;
|
||||
static char const tstringKey = 0;
|
||||
static char const unitvarKey = 0;
|
||||
static char const ustatusKey = 0;
|
||||
static char const vconfigKey = 0;
|
||||
|
||||
/**
|
||||
* Displays a message in the chat window.
|
||||
*/
|
||||
static void chat_message(std::string const &caption, std::string const &msg)
|
||||
{
|
||||
resources::screen->add_chat_message(time(NULL), caption, 0, msg,
|
||||
events::chat_handler::MESSAGE_PUBLIC, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a vconfig on the top of the stack.
|
||||
*/
|
||||
static void luaW_pushvconfig(lua_State *L, vconfig const &cfg)
|
||||
{
|
||||
new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&vconfigKey)));
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a t_string on the top of the stack.
|
||||
*/
|
||||
static void luaW_pushtstring(lua_State *L, t_string const &v)
|
||||
{
|
||||
new(lua_newuserdata(L, sizeof(t_string))) t_string(v);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&tstringKey)));
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct luaW_pushscalar_visitor : boost::static_visitor<>
|
||||
{
|
||||
lua_State *L;
|
||||
luaW_pushscalar_visitor(lua_State *l): L(l) {}
|
||||
|
||||
void operator()(boost::blank const &) const
|
||||
{ lua_pushnil(L); }
|
||||
void operator()(bool b) const
|
||||
{ lua_pushboolean(L, b); }
|
||||
void operator()(int i) const
|
||||
{ lua_pushinteger(L, i); }
|
||||
void operator()(unsigned long long ull) const
|
||||
{ lua_pushnumber(L, ull); }
|
||||
void operator()(double d) const
|
||||
{ lua_pushnumber(L, d); }
|
||||
void operator()(std::string const &s) const
|
||||
{ lua_pushstring(L, s.c_str()); }
|
||||
void operator()(t_string const &s) const
|
||||
{ luaW_pushtstring(L, s); }
|
||||
};
|
||||
}//unnamed namespace for luaW_pushscalar_visitor
|
||||
|
||||
/**
|
||||
* Converts a string into a Lua object pushed at the top of the stack.
|
||||
*/
|
||||
static void luaW_pushscalar(lua_State *L, config::attribute_value const &v)
|
||||
{
|
||||
v.apply_visitor(luaW_pushscalar_visitor(L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the metatable of the object is the one found in the registry.
|
||||
*/
|
||||
static bool luaW_hasmetatable(lua_State *L
|
||||
, int index
|
||||
, char const &key)
|
||||
{
|
||||
if (!lua_getmetatable(L, index))
|
||||
return false;
|
||||
lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&key)));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
bool ok = lua_rawequal(L, -1, -2);
|
||||
lua_pop(L, 2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a scalar to a translatable string.
|
||||
*/
|
||||
static bool luaW_totstring(lua_State *L, int index, t_string &str)
|
||||
{
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TBOOLEAN:
|
||||
str = lua_toboolean(L, index) ? "yes" : "no";
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
str = lua_tostring(L, index);
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, tstringKey)) return false;
|
||||
str = *static_cast<t_string *>(lua_touserdata(L, index));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a scalar to a translatable string.
|
||||
*/
|
||||
static t_string luaW_checktstring(lua_State *L, int index)
|
||||
{
|
||||
t_string result;
|
||||
if (!luaW_totstring(L, index, result))
|
||||
luaL_typerror(L, index, "translatable string");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a config object to a Lua table.
|
||||
* The destination table should be at the top of the stack on entry. It is
|
||||
* still at the top on exit.
|
||||
*/
|
||||
static void luaW_filltable(lua_State *L, config const &cfg)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return;
|
||||
|
||||
int k = 1;
|
||||
BOOST_FOREACH(const config::any_child &ch, cfg.all_children_range())
|
||||
{
|
||||
lua_createtable(L, 2, 0);
|
||||
lua_pushstring(L, ch.key.c_str());
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_newtable(L);
|
||||
luaW_filltable(L, ch.cfg);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_rawseti(L, -2, k++);
|
||||
}
|
||||
BOOST_FOREACH(const config::attribute &attr, cfg.attribute_range())
|
||||
{
|
||||
luaW_pushscalar(L, attr.second);
|
||||
lua_setfield(L, -2, attr.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a config object to a Lua table pushed at the top of the stack.
|
||||
*/
|
||||
void luaW_pushconfig(lua_State *L, config const &cfg)
|
||||
{
|
||||
lua_newtable(L);
|
||||
luaW_filltable(L, cfg);
|
||||
}
|
||||
|
||||
#define return_misformed() \
|
||||
do { lua_settop(L, initial_top); return false; } while (0)
|
||||
|
||||
/**
|
||||
* Converts an optional table or vconfig to a config object.
|
||||
* @param tstring_meta absolute stack position of t_string's metatable, or 0 if none.
|
||||
* @return false if some attributes had not the proper type.
|
||||
* @note If the table has holes in the integer keys or floating-point keys,
|
||||
* some keys will be ignored and the error will go undetected.
|
||||
*/
|
||||
bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return false;
|
||||
|
||||
// Get the absolute index of the table.
|
||||
int initial_top = lua_gettop(L);
|
||||
if (-initial_top <= index && index <= -1)
|
||||
index = initial_top + index + 1;
|
||||
|
||||
switch (lua_type(L, index))
|
||||
{
|
||||
case LUA_TTABLE:
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, vconfigKey))
|
||||
return false;
|
||||
cfg = static_cast<vconfig *>(lua_touserdata(L, index))->get_parsed_config();
|
||||
return true;
|
||||
}
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get t_string's metatable, so that it can be used later to detect t_string object.
|
||||
if (!tstring_meta) {
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&tstringKey)));
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
tstring_meta = initial_top + 1;
|
||||
}
|
||||
|
||||
// First convert the children (integer indices).
|
||||
for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
|
||||
{
|
||||
lua_rawgeti(L, index, i);
|
||||
if (!lua_istable(L, -1)) return_misformed();
|
||||
lua_rawgeti(L, -1, 1);
|
||||
char const *m = lua_tostring(L, -1);
|
||||
if (!m) return_misformed();
|
||||
lua_rawgeti(L, -2, 2);
|
||||
if (!luaW_toconfig(L, -1, cfg.add_child(m), tstring_meta))
|
||||
return_misformed();
|
||||
lua_pop(L, 3);
|
||||
}
|
||||
|
||||
// Then convert the attributes (string indices).
|
||||
for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
|
||||
{
|
||||
if (lua_isnumber(L, -2)) continue;
|
||||
if (!lua_isstring(L, -2)) return_misformed();
|
||||
config::attribute_value &v = cfg[lua_tostring(L, -2)];
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TBOOLEAN:
|
||||
v = bool(lua_toboolean(L, -1));
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
v = lua_tonumber(L, -1);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
v = lua_tostring(L, -1);
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!lua_getmetatable(L, -1)) return_misformed();
|
||||
bool tstr = lua_rawequal(L, -1, tstring_meta) != 0;
|
||||
lua_pop(L, 1);
|
||||
if (!tstr) return_misformed();
|
||||
v = *static_cast<t_string *>(lua_touserdata(L, -1));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return_misformed();
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, initial_top);
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef return_misformed
|
||||
|
||||
/**
|
||||
* Converts an optional table or vconfig to a config object.
|
||||
*/
|
||||
static config luaW_checkconfig(lua_State *L, int index)
|
||||
{
|
||||
config result;
|
||||
if (!luaW_toconfig(L, index, result))
|
||||
luaL_typerror(L, index, "WML table");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an optional vconfig from either a table or a userdata.
|
||||
* @return false in case of failure.
|
||||
*/
|
||||
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
|
||||
{
|
||||
switch (lua_type(L, index))
|
||||
{
|
||||
case LUA_TTABLE:
|
||||
{
|
||||
config cfg;
|
||||
bool ok = luaW_toconfig(L, index, cfg);
|
||||
if (!ok) return false;
|
||||
vcfg = vconfig(cfg, true);
|
||||
break;
|
||||
}
|
||||
case LUA_TUSERDATA:
|
||||
if (!luaW_hasmetatable(L, index, vconfigKey))
|
||||
return false;
|
||||
vcfg = *static_cast<vconfig *>(lua_touserdata(L, index));
|
||||
break;
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an optional vconfig from either a table or a userdata.
|
||||
* @param allow_missing true if missing values are allowed; the function
|
||||
* then returns an unconstructed vconfig.
|
||||
*/
|
||||
static vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false)
|
||||
{
|
||||
vconfig result = vconfig::unconstructed_vconfig();
|
||||
if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
|
||||
luaL_typerror(L, index, "WML table");
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4706)
|
||||
#endif
|
||||
/**
|
||||
* Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
|
||||
* @param nRets LUA_MULTRET for unbounded return values.
|
||||
* @return true if the call was successful and @a nRets return values are available.
|
||||
*/
|
||||
bool luaW_pcall(lua_State *L
|
||||
, int nArgs, int nRets, bool allow_wml_error)
|
||||
{
|
||||
// Load the error handler before the function and its arguments.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&executeKey)));
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_insert(L, -2 - nArgs);
|
||||
|
||||
int error_handler_index = lua_gettop(L) - nArgs - 1;
|
||||
|
||||
// Call the function.
|
||||
int res = lua_pcall(L, nArgs, nRets, -2 - nArgs);
|
||||
tlua_jailbreak_exception::rethrow();
|
||||
|
||||
if (res)
|
||||
{
|
||||
/*
|
||||
* When an exception is thrown which doesn't derive from
|
||||
* std::exception m will be NULL pointer.
|
||||
*/
|
||||
char const *m = lua_tostring(L, -1);
|
||||
if(m) {
|
||||
if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
|
||||
m += 5;
|
||||
char const *e = strstr(m, "stack traceback");
|
||||
lg::wml_error << std::string(m, e ? e - m : strlen(m));
|
||||
} else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
|
||||
m += 5;
|
||||
char const *e = NULL, *em = m;
|
||||
while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
e = em;
|
||||
chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
|
||||
} else {
|
||||
ERR_LUA << m << '\n';
|
||||
chat_message("Lua error", m);
|
||||
}
|
||||
} else {
|
||||
chat_message("Lua caught unknown exception", "");
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the error handler.
|
||||
lua_remove(L, error_handler_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the value found by following the variadic names (char *), if the
|
||||
* value is not nil.
|
||||
* @return true if an element was pushed.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
__attribute__((sentinel))
|
||||
#endif
|
||||
static bool luaW_getglobal(lua_State *L, ...)
|
||||
{
|
||||
lua_pushglobaltable(L);
|
||||
va_list ap;
|
||||
va_start(ap, L);
|
||||
while (const char *s = va_arg(ap, const char *))
|
||||
{
|
||||
if (!lua_istable(L, -1)) goto discard;
|
||||
lua_pushstring(L, s);
|
||||
lua_rawget(L, -2);
|
||||
lua_remove(L, -2);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (lua_isnil(L, -1)) {
|
||||
discard:
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
lua_unit::~lua_unit()
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
unit *lua_unit::get()
|
||||
{
|
||||
if (ptr) return ptr;
|
||||
if (side) {
|
||||
BOOST_FOREACH(unit &u, (*resources::teams)[side - 1].recall_list()) {
|
||||
if (u.underlying_id() == uid) return &u;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
unit_map::unit_iterator ui = resources::units->find(uid);
|
||||
if (!ui.valid()) return NULL;
|
||||
return &*ui;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map)
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, getunitKey)) return NULL;
|
||||
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
|
||||
if (only_on_map && !lu->on_map()) return NULL;
|
||||
return lu->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
static unit *luaW_checkunit(lua_State *L, int index, bool only_on_map = false)
|
||||
{
|
||||
unit *u = luaW_tounit(L, index, only_on_map);
|
||||
if (!u) luaL_typerror(L, index, "unit");
|
||||
return u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a t_string object (__call metamethod).
|
||||
@ -609,7 +160,7 @@ static int intf_textdomain(lua_State *L)
|
||||
void *p = lua_newuserdata(L, l + 1);
|
||||
memcpy(p, m, l + 1);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&gettextKey)));
|
||||
, gettextKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
@ -651,7 +202,7 @@ static int impl_tstring_concat(lua_State *L)
|
||||
t_string *t = new(lua_newuserdata(L, sizeof(t_string))) t_string;
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&tstringKey)));
|
||||
, tstringKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
@ -705,7 +256,7 @@ static int impl_vconfig_get(lua_State *L)
|
||||
lua_rawseti(L, -2, 1);
|
||||
new(lua_newuserdata(L, sizeof(vconfig))) vconfig(i.get_child());
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&vconfigKey)));
|
||||
, vconfigKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
@ -1023,7 +574,7 @@ static int impl_unit_get(lua_State *L)
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&ustatusKey)));
|
||||
, ustatusKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -1033,7 +584,7 @@ static int impl_unit_get(lua_State *L)
|
||||
lua_pushvalue(L, 1);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&unitvarKey)));
|
||||
, unitvarKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -1209,7 +760,7 @@ static int intf_get_unit(lua_State *L)
|
||||
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -1230,7 +781,7 @@ static int intf_get_displayed_unit(lua_State *L)
|
||||
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -1250,7 +801,7 @@ static int intf_get_units(lua_State *L)
|
||||
// 1: metatable, 2: return table, 3: userdata, 4: metatable copy
|
||||
lua_settop(L, 0);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_newtable(L);
|
||||
int i = 1;
|
||||
@ -1317,7 +868,7 @@ static int intf_get_recall_units(lua_State *L)
|
||||
// 1: metatable, 2: return table, 3: userdata, 4: metatable copy
|
||||
lua_settop(L, 0);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_newtable(L);
|
||||
int i = 1, s = 1;
|
||||
@ -2726,7 +2277,7 @@ static int intf_create_unit(lua_State *L)
|
||||
unit *u = new unit(cfg, true, resources::state_of_game);
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -2742,7 +2293,7 @@ static int intf_copy_unit(lua_State *L)
|
||||
unit const *u = luaW_checkunit(L, 1);
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(new unit(*u));
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
@ -3112,7 +2663,7 @@ namespace {
|
||||
: L(l), prev(current), window(w), callbacks()
|
||||
{
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
|
||||
, dlgclbkKey);
|
||||
lua_createtable(L, 1, 0);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
@ -3126,7 +2677,7 @@ namespace {
|
||||
delete window;
|
||||
current = prev;
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
|
||||
, dlgclbkKey);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_rawgeti(L, -1, 1);
|
||||
@ -3340,7 +2891,7 @@ namespace { // helpers of intf_set_dialog_callback()
|
||||
}
|
||||
lua_State *L = scoped_dialog::current->L;
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
|
||||
, dlgclbkKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_rawgeti(L, -1, cb);
|
||||
lua_remove(L, -2);
|
||||
@ -3372,7 +2923,7 @@ static int intf_set_dialog_callback(lua_State *L)
|
||||
if (i != m.end())
|
||||
{
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
|
||||
, dlgclbkKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, -2, i->second);
|
||||
@ -3409,7 +2960,7 @@ static int intf_set_dialog_callback(lua_State *L)
|
||||
return luaL_argerror(L, lua_gettop(L), "unsupported widget");
|
||||
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&dlgclbkKey)));
|
||||
, dlgclbkKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
int n = lua_rawlen(L, -1) + 1;
|
||||
m[w] = n;
|
||||
@ -3585,7 +3136,7 @@ static int intf_get_sides(lua_State* L)
|
||||
|
||||
lua_settop(L, 0);
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void*>(const_cast<char *>(&getsideKey)));
|
||||
, getsideKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_createtable(L, sides.size(), 0);
|
||||
unsigned index = 1;
|
||||
@ -4066,7 +3617,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the getside metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getsideKey)));
|
||||
, getsideKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushcfunction(L, impl_side_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
@ -4078,7 +3629,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the gettext metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&gettextKey)));
|
||||
, gettextKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, impl_gettext);
|
||||
lua_setfield(L, -2, "__call");
|
||||
@ -4088,7 +3639,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the gettype metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&gettypeKey)));
|
||||
, gettypeKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, impl_unit_type_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
@ -4098,7 +3649,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
//Create the getrace metatable
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getraceKey)));
|
||||
, getraceKey);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushcfunction(L, impl_race_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
@ -4108,7 +3659,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the getunit metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_createtable(L, 0, 5);
|
||||
lua_pushcfunction(L, impl_unit_collect);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
@ -4124,7 +3675,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the tstring metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&tstringKey)));
|
||||
, tstringKey);
|
||||
lua_createtable(L, 0, 4);
|
||||
lua_pushcfunction(L, impl_tstring_concat);
|
||||
lua_setfield(L, -2, "__concat");
|
||||
@ -4138,7 +3689,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the unit status metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&ustatusKey)));
|
||||
, ustatusKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushcfunction(L, impl_unit_status_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
@ -4150,7 +3701,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the unit variables metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&unitvarKey)));
|
||||
, unitvarKey);
|
||||
lua_createtable(L, 0, 3);
|
||||
lua_pushcfunction(L, impl_unit_variables_get);
|
||||
lua_setfield(L, -2, "__index");
|
||||
@ -4162,7 +3713,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Create the vconfig metatable.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&vconfigKey)));
|
||||
, vconfigKey);
|
||||
lua_createtable(L, 0, 4);
|
||||
lua_pushcfunction(L, impl_vconfig_collect);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
@ -4241,7 +3792,7 @@ LuaKernel::LuaKernel(const config &cfg)
|
||||
|
||||
// Store the error handler.
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&executeKey)));
|
||||
, executeKey);
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
lua_remove(L, -2);
|
||||
@ -4286,7 +3837,7 @@ void LuaKernel::initialize()
|
||||
lua_getglobal(L, "wesnoth");
|
||||
std::vector<team> &teams = *resources::teams;
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getsideKey)));
|
||||
, getsideKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_createtable(L, teams.size(), 0);
|
||||
for (unsigned i = 0; i != teams.size(); ++i)
|
||||
@ -4304,7 +3855,7 @@ void LuaKernel::initialize()
|
||||
// Create the unit_types table.
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&gettypeKey)));
|
||||
, gettypeKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_newtable(L);
|
||||
BOOST_FOREACH(const unit_type_data::unit_type_map::value_type &ut, unit_types.types())
|
||||
@ -4322,7 +3873,7 @@ void LuaKernel::initialize()
|
||||
//Create the races table.
|
||||
lua_getglobal(L, "wesnoth");
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getraceKey)));
|
||||
, getraceKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
const race_map& races = unit_types.races();
|
||||
lua_createtable(L, 0, races.size());
|
||||
@ -4533,7 +4084,7 @@ bool LuaKernel::run_filter(char const *name, unit const &u)
|
||||
// Pass the unit as argument.
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
|
||||
lua_pushlightuserdata(L
|
||||
, static_cast<void *>(const_cast<char *>(&getunitKey)));
|
||||
, getunitKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
|
418
src/scripting/lua_api.cpp
Normal file
418
src/scripting/lua_api.cpp
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
Copyright (C) 2009 - 2013 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "lua_api.hpp"
|
||||
#include "lua_types.hpp"
|
||||
|
||||
#include "lua/lualib.h"
|
||||
#include "lua/lauxlib.h"
|
||||
|
||||
#include "variable.hpp"
|
||||
#include "tstring.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "game_display.hpp"
|
||||
#include "log.hpp"
|
||||
#include "config.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
static lg::log_domain log_scripting_lua("scripting/lua");
|
||||
#define LOG_LUA LOG_STREAM(info, log_scripting_lua)
|
||||
#define ERR_LUA LOG_STREAM(err, log_scripting_lua)
|
||||
|
||||
void chat_message(std::string const &caption, std::string const &msg)
|
||||
{
|
||||
resources::screen->add_chat_message(time(NULL), caption, 0, msg,
|
||||
events::chat_handler::MESSAGE_PUBLIC, false);
|
||||
}
|
||||
|
||||
void luaW_pushvconfig(lua_State *L, vconfig const &cfg)
|
||||
{
|
||||
new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg);
|
||||
lua_pushlightuserdata(L
|
||||
, vconfigKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
void luaW_pushtstring(lua_State *L, t_string const &v)
|
||||
{
|
||||
new(lua_newuserdata(L, sizeof(t_string))) t_string(v);
|
||||
lua_pushlightuserdata(L
|
||||
, tstringKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
struct luaW_pushscalar_visitor : boost::static_visitor<>
|
||||
{
|
||||
lua_State *L;
|
||||
luaW_pushscalar_visitor(lua_State *l): L(l) {}
|
||||
|
||||
void operator()(boost::blank const &) const
|
||||
{ lua_pushnil(L); }
|
||||
void operator()(bool b) const
|
||||
{ lua_pushboolean(L, b); }
|
||||
void operator()(int i) const
|
||||
{ lua_pushinteger(L, i); }
|
||||
void operator()(unsigned long long ull) const
|
||||
{ lua_pushnumber(L, ull); }
|
||||
void operator()(double d) const
|
||||
{ lua_pushnumber(L, d); }
|
||||
void operator()(std::string const &s) const
|
||||
{ lua_pushstring(L, s.c_str()); }
|
||||
void operator()(t_string const &s) const
|
||||
{ luaW_pushtstring(L, s); }
|
||||
};
|
||||
}//unnamed namespace for luaW_pushscalar_visitor
|
||||
|
||||
void luaW_pushscalar(lua_State *L, config::attribute_value const &v)
|
||||
{
|
||||
v.apply_visitor(luaW_pushscalar_visitor(L));
|
||||
}
|
||||
|
||||
bool luaW_hasmetatable(lua_State *L
|
||||
, int index
|
||||
, luatypekey key)
|
||||
{
|
||||
if (!lua_getmetatable(L, index))
|
||||
return false;
|
||||
lua_pushlightuserdata(L, key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
bool ok = lua_rawequal(L, -1, -2);
|
||||
lua_pop(L, 2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool luaW_totstring(lua_State *L, int index, t_string &str)
|
||||
{
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TBOOLEAN:
|
||||
str = lua_toboolean(L, index) ? "yes" : "no";
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
str = lua_tostring(L, index);
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, tstringKey)) return false;
|
||||
str = *static_cast<t_string *>(lua_touserdata(L, index));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
t_string luaW_checktstring(lua_State *L, int index)
|
||||
{
|
||||
t_string result;
|
||||
if (!luaW_totstring(L, index, result))
|
||||
luaL_typerror(L, index, "translatable string");
|
||||
return result;
|
||||
}
|
||||
|
||||
void luaW_filltable(lua_State *L, config const &cfg)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return;
|
||||
|
||||
int k = 1;
|
||||
BOOST_FOREACH(const config::any_child &ch, cfg.all_children_range())
|
||||
{
|
||||
lua_createtable(L, 2, 0);
|
||||
lua_pushstring(L, ch.key.c_str());
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_newtable(L);
|
||||
luaW_filltable(L, ch.cfg);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_rawseti(L, -2, k++);
|
||||
}
|
||||
BOOST_FOREACH(const config::attribute &attr, cfg.attribute_range())
|
||||
{
|
||||
luaW_pushscalar(L, attr.second);
|
||||
lua_setfield(L, -2, attr.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void luaW_pushconfig(lua_State *L, config const &cfg)
|
||||
{
|
||||
lua_newtable(L);
|
||||
luaW_filltable(L, cfg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define return_misformed() \
|
||||
do { lua_settop(L, initial_top); return false; } while (0)
|
||||
|
||||
bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return false;
|
||||
|
||||
// Get the absolute index of the table.
|
||||
int initial_top = lua_gettop(L);
|
||||
if (-initial_top <= index && index <= -1)
|
||||
index = initial_top + index + 1;
|
||||
|
||||
switch (lua_type(L, index))
|
||||
{
|
||||
case LUA_TTABLE:
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, vconfigKey))
|
||||
return false;
|
||||
cfg = static_cast<vconfig *>(lua_touserdata(L, index))->get_parsed_config();
|
||||
return true;
|
||||
}
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get t_string's metatable, so that it can be used later to detect t_string object.
|
||||
if (!tstring_meta) {
|
||||
lua_pushlightuserdata(L
|
||||
, tstringKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
tstring_meta = initial_top + 1;
|
||||
}
|
||||
|
||||
// First convert the children (integer indices).
|
||||
for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
|
||||
{
|
||||
lua_rawgeti(L, index, i);
|
||||
if (!lua_istable(L, -1)) return_misformed();
|
||||
lua_rawgeti(L, -1, 1);
|
||||
char const *m = lua_tostring(L, -1);
|
||||
if (!m) return_misformed();
|
||||
lua_rawgeti(L, -2, 2);
|
||||
if (!luaW_toconfig(L, -1, cfg.add_child(m), tstring_meta))
|
||||
return_misformed();
|
||||
lua_pop(L, 3);
|
||||
}
|
||||
|
||||
// Then convert the attributes (string indices).
|
||||
for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
|
||||
{
|
||||
if (lua_isnumber(L, -2)) continue;
|
||||
if (!lua_isstring(L, -2)) return_misformed();
|
||||
config::attribute_value &v = cfg[lua_tostring(L, -2)];
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TBOOLEAN:
|
||||
v = bool(lua_toboolean(L, -1));
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
v = lua_tonumber(L, -1);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
v = lua_tostring(L, -1);
|
||||
break;
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
if (!lua_getmetatable(L, -1)) return_misformed();
|
||||
bool tstr = lua_rawequal(L, -1, tstring_meta) != 0;
|
||||
lua_pop(L, 1);
|
||||
if (!tstr) return_misformed();
|
||||
v = *static_cast<t_string *>(lua_touserdata(L, -1));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return_misformed();
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, initial_top);
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef return_misformed
|
||||
|
||||
|
||||
config luaW_checkconfig(lua_State *L, int index)
|
||||
{
|
||||
config result;
|
||||
if (!luaW_toconfig(L, index, result))
|
||||
luaL_typerror(L, index, "WML table");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
|
||||
{
|
||||
switch (lua_type(L, index))
|
||||
{
|
||||
case LUA_TTABLE:
|
||||
{
|
||||
config cfg;
|
||||
bool ok = luaW_toconfig(L, index, cfg);
|
||||
if (!ok) return false;
|
||||
vcfg = vconfig(cfg, true);
|
||||
break;
|
||||
}
|
||||
case LUA_TUSERDATA:
|
||||
if (!luaW_hasmetatable(L, index, vconfigKey))
|
||||
return false;
|
||||
vcfg = *static_cast<vconfig *>(lua_touserdata(L, index));
|
||||
break;
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing)
|
||||
{
|
||||
vconfig result = vconfig::unconstructed_vconfig();
|
||||
if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
|
||||
luaL_typerror(L, index, "WML table");
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4706)
|
||||
#endif
|
||||
bool luaW_pcall(lua_State *L
|
||||
, int nArgs, int nRets, bool allow_wml_error)
|
||||
{
|
||||
// Load the error handler before the function and its arguments.
|
||||
lua_pushlightuserdata(L
|
||||
, executeKey);
|
||||
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_insert(L, -2 - nArgs);
|
||||
|
||||
int error_handler_index = lua_gettop(L) - nArgs - 1;
|
||||
|
||||
// Call the function.
|
||||
int res = lua_pcall(L, nArgs, nRets, -2 - nArgs);
|
||||
tlua_jailbreak_exception::rethrow();
|
||||
|
||||
if (res)
|
||||
{
|
||||
/*
|
||||
* When an exception is thrown which doesn't derive from
|
||||
* std::exception m will be NULL pointer.
|
||||
*/
|
||||
char const *m = lua_tostring(L, -1);
|
||||
if(m) {
|
||||
if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
|
||||
m += 5;
|
||||
char const *e = strstr(m, "stack traceback");
|
||||
lg::wml_error << std::string(m, e ? e - m : strlen(m));
|
||||
} else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
|
||||
m += 5;
|
||||
char const *e = NULL, *em = m;
|
||||
while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
e = em;
|
||||
chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
|
||||
} else {
|
||||
ERR_LUA << m << '\n';
|
||||
chat_message("Lua error", m);
|
||||
}
|
||||
} else {
|
||||
chat_message("Lua caught unknown exception", "");
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the error handler.
|
||||
lua_remove(L, error_handler_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((sentinel))
|
||||
#endif
|
||||
bool luaW_getglobal(lua_State *L, ...)
|
||||
{
|
||||
lua_pushglobaltable(L);
|
||||
va_list ap;
|
||||
va_start(ap, L);
|
||||
while (const char *s = va_arg(ap, const char *))
|
||||
{
|
||||
if (!lua_istable(L, -1)) goto discard;
|
||||
lua_pushstring(L, s);
|
||||
lua_rawget(L, -2);
|
||||
lua_remove(L, -2);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (lua_isnil(L, -1)) {
|
||||
discard:
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
lua_unit::~lua_unit()
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
unit *lua_unit::get()
|
||||
{
|
||||
if (ptr) return ptr;
|
||||
if (side) {
|
||||
BOOST_FOREACH(unit &u, (*resources::teams)[side - 1].recall_list()) {
|
||||
if (u.underlying_id() == uid) return &u;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
unit_map::unit_iterator ui = resources::units->find(uid);
|
||||
if (!ui.valid()) return NULL;
|
||||
return &*ui;
|
||||
}
|
||||
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map)
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, getunitKey)) return NULL;
|
||||
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
|
||||
if (only_on_map && !lu->on_map()) return NULL;
|
||||
return lu->get();
|
||||
}
|
||||
|
||||
unit *luaW_checkunit(lua_State *L, int index, bool only_on_map)
|
||||
{
|
||||
unit *u = luaW_tounit(L, index, only_on_map);
|
||||
if (!u) luaL_typerror(L, index, "unit");
|
||||
return u;
|
||||
}
|
@ -16,18 +16,120 @@
|
||||
#define SCRIPTING_LUA_API_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
#include "config.hpp" // forward declaration of the nested type config::attribute_value is not possible
|
||||
#include "lua_types.hpp" // the luatype typedef
|
||||
struct lua_State;
|
||||
class config;
|
||||
class t_string;
|
||||
class vconfig;
|
||||
class unit;
|
||||
|
||||
bool luaW_pcall(lua_State *L , int nArgs, int nRets, bool allow_wml_error = false);
|
||||
|
||||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map = false);
|
||||
|
||||
/**
|
||||
* Displays a message in the chat window.
|
||||
*/
|
||||
void chat_message(std::string const &caption, std::string const &msg);
|
||||
|
||||
/**
|
||||
* Pushes a vconfig on the top of the stack.
|
||||
*/
|
||||
void luaW_pushvconfig(lua_State *L, vconfig const &cfg);
|
||||
|
||||
/**
|
||||
* Pushes a t_string on the top of the stack.
|
||||
*/
|
||||
void luaW_pushtstring(lua_State *L, t_string const &v);
|
||||
|
||||
/**
|
||||
* Converts a string into a Lua object pushed at the top of the stack.
|
||||
*/
|
||||
void luaW_pushscalar(lua_State *L, config::attribute_value const &v);
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the metatable of the object is the one found in the registry.
|
||||
*/
|
||||
bool luaW_hasmetatable(lua_State *L, int index, luatypekey key);
|
||||
|
||||
/**
|
||||
* Converts a scalar to a translatable string.
|
||||
*/
|
||||
bool luaW_totstring(lua_State *L, int index, t_string &str);
|
||||
|
||||
/**
|
||||
* Converts a scalar to a translatable string.
|
||||
*/
|
||||
t_string luaW_checktstring(lua_State *L, int index);
|
||||
|
||||
/**
|
||||
* Converts a config object to a Lua table.
|
||||
* The destination table should be at the top of the stack on entry. It is
|
||||
* still at the top on exit.
|
||||
*/
|
||||
void luaW_filltable(lua_State *L, config const &cfg);
|
||||
|
||||
/**
|
||||
* Converts a config object to a Lua table pushed at the top of the stack.
|
||||
*/
|
||||
void luaW_pushconfig(lua_State *L, config const &cfg);
|
||||
|
||||
/**
|
||||
* Converts an optional table or vconfig to a config object.
|
||||
* @param tstring_meta absolute stack position of t_string's metatable, or 0 if none.
|
||||
* @return false if some attributes had not the proper type.
|
||||
* @note If the table has holes in the integer keys or floating-point keys,
|
||||
* some keys will be ignored and the error will go undetected.
|
||||
*/
|
||||
bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta = 0);
|
||||
|
||||
/**
|
||||
* Converts an optional table or vconfig to a config object.
|
||||
*/
|
||||
config luaW_checkconfig(lua_State *L, int index);
|
||||
|
||||
/**
|
||||
* Gets an optional vconfig from either a table or a userdata.
|
||||
* @return false in case of failure.
|
||||
*/
|
||||
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg);
|
||||
|
||||
/**
|
||||
* Gets an optional vconfig from either a table or a userdata.
|
||||
* @param allow_missing true if missing values are allowed; the function
|
||||
* then returns an unconstructed vconfig.
|
||||
*/
|
||||
vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false);
|
||||
|
||||
/**
|
||||
* Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
|
||||
* @param nRets LUA_MULTRET for unbounded return values.
|
||||
* @return true if the call was successful and @a nRets return values are available.
|
||||
*/
|
||||
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
|
||||
|
||||
|
||||
/**
|
||||
* Pushes the value found by following the variadic names (char *), if the
|
||||
* value is not nil.
|
||||
* @return true if an element was pushed.
|
||||
*/
|
||||
bool luaW_getglobal(lua_State *L, ...);
|
||||
|
||||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map);
|
||||
|
||||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
unit *luaW_checkunit(lua_State *L, int index, bool only_on_map = false);
|
||||
|
||||
/**
|
||||
* Storage for a unit, either owned by the Lua code (#ptr != 0), on a
|
||||
* recall list (#side != 0), or on the map. Shared units are represented
|
||||
|
40
src/scripting/lua_types.cpp
Normal file
40
src/scripting/lua_types.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "lua_types.hpp"
|
||||
|
||||
/* Dummy pointer for getting unique keys for Lua's registry. */
|
||||
static char const v_dlgclbkKey = 0;
|
||||
static char const v_executeKey = 0;
|
||||
static char const v_getsideKey = 0;
|
||||
static char const v_gettextKey = 0;
|
||||
static char const v_gettypeKey = 0;
|
||||
static char const v_getraceKey = 0;
|
||||
static char const v_getunitKey = 0;
|
||||
static char const v_tstringKey = 0;
|
||||
static char const v_unitvarKey = 0;
|
||||
static char const v_ustatusKey = 0;
|
||||
static char const v_vconfigKey = 0;
|
||||
|
||||
|
||||
luatypekey const dlgclbkKey = static_cast<void *>(const_cast<char *>(&v_dlgclbkKey));
|
||||
luatypekey const executeKey = static_cast<void *>(const_cast<char *>(&v_executeKey));
|
||||
luatypekey const getsideKey = static_cast<void *>(const_cast<char *>(&v_getsideKey));
|
||||
luatypekey const gettextKey = static_cast<void *>(const_cast<char *>(&v_gettextKey));
|
||||
luatypekey const gettypeKey = static_cast<void *>(const_cast<char *>(&v_gettypeKey));
|
||||
luatypekey const getraceKey = static_cast<void *>(const_cast<char *>(&v_getraceKey));
|
||||
luatypekey const getunitKey = static_cast<void *>(const_cast<char *>(&v_getunitKey));
|
||||
luatypekey const tstringKey = static_cast<void *>(const_cast<char *>(&v_tstringKey));
|
||||
luatypekey const unitvarKey = static_cast<void *>(const_cast<char *>(&v_unitvarKey));
|
||||
luatypekey const ustatusKey = static_cast<void *>(const_cast<char *>(&v_ustatusKey));
|
||||
luatypekey const vconfigKey = static_cast<void *>(const_cast<char *>(&v_vconfigKey));
|
28
src/scripting/lua_types.hpp
Normal file
28
src/scripting/lua_types.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
typedef void* luatypekey;
|
||||
|
||||
// i dont want to cast to void* each time ....
|
||||
// a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time).
|
||||
extern luatypekey const dlgclbkKey;
|
||||
extern luatypekey const executeKey;
|
||||
extern luatypekey const getsideKey;
|
||||
extern luatypekey const gettextKey;
|
||||
extern luatypekey const gettypeKey;
|
||||
extern luatypekey const getraceKey;
|
||||
extern luatypekey const getunitKey;
|
||||
extern luatypekey const tstringKey;
|
||||
extern luatypekey const unitvarKey;
|
||||
extern luatypekey const ustatusKey;
|
||||
extern luatypekey const vconfigKey;
|
Loading…
x
Reference in New Issue
Block a user