Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/wesnoth/wesnoth
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeck88 committed Nov 11, 2014
2 parents 27145f7 + ec60376 commit 30bc486
Show file tree
Hide file tree
Showing 13 changed files with 590 additions and 496 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -954,6 +954,7 @@ set(wesnoth-main_SRC
scripting/lua_game_launcher.cpp
scripting/lua_kernel_base.cpp
scripting/lua_types.cpp
scripting/mapgen_lua_kernel.cpp
settings.cpp
side_filter.cpp
game_initialization/singleplayer.cpp
Expand Down
1 change: 1 addition & 0 deletions src/SConscript
Expand Up @@ -527,6 +527,7 @@ wesnoth_sources = Split("""
scripting/lua_game_launcher.cpp
scripting/lua_kernel_base.cpp
scripting/lua_types.cpp
scripting/mapgen_lua_kernel.cpp
settings.cpp
side_filter.cpp
game_initialization/singleplayer.cpp
Expand Down
8 changes: 8 additions & 0 deletions src/game_errors.hpp
Expand Up @@ -47,6 +47,14 @@ struct game_error : public error {
game_error(const std::string& msg) : error("game_error: " + msg) {}
};

/**
* Error used to report an error in a lua script or in the lua interpreter.
*/
struct lua_error : public error {
lua_error(const std::string& msg) : error("lua_error: " + msg) {}
lua_error(const std::string& msg, const std::string& context) : error(context + ": " + msg) {}
};

/**
* Exception used to signal that the user has decided to abort a game,
* and to load another game instead.
Expand Down
2 changes: 2 additions & 0 deletions src/game_events/action_wml.cpp
Expand Up @@ -643,6 +643,8 @@ static void on_replay_error(const std::string& message, bool /*b*/)
// This allows to perform scripting in WML that will use the same code path as player actions, for example.
WML_HANDLER_FUNCTION(do_command, /*event_info*/, cfg)
{
//TODO: don't allow this if we are in a whiteboard applied context.

static const std::set<std::string> allowed_tags = boost::assign::list_of("attack")("move")("recruit")("recall")("disband")("fire_event")("lua_ai");

const bool is_too_early = resources::gamedata->phase() != game_data::START && resources::gamedata->phase() != game_data::PLAY;
Expand Down
229 changes: 14 additions & 215 deletions src/generators/lua_map_generator.cpp
Expand Up @@ -15,154 +15,20 @@
#include "lua_map_generator.hpp"

#include "config.hpp"
#include "log.hpp"

#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "lua/lualib.h"

#include "mt_rng.hpp"

#ifdef DEBUG_LUA
#include "scripting/debug_lua.hpp"
#endif

#include "scripting/lua_api.hpp"
#include "game_errors.hpp"
#include "scripting/mapgen_lua_kernel.hpp"

#include <string>

#include <boost/foreach.hpp>

static lg::log_domain log_mapgen("mapgen");
#define ERR_NG LOG_STREAM(err, log_mapgen)
#define LOG_NG LOG_STREAM(info, log_mapgen)
#define DBG_NG LOG_STREAM(debug, log_mapgen)

// Add compiler directive suppressing unused variable warning
#if defined(__GNUC__) || defined(__clang__) || defined(__MINGW32__)
#define ATTR_UNUSED( x ) __attribute__((unused)) x
#else
#define ATTR_UNUSED( x ) x
#endif

// Begin lua rng bindings

using rand_rng::mt_rng;

static const char * Rng = "Rng";

static int impl_rng_create(lua_State* L);
static int impl_rng_destroy(lua_State* L);
static int impl_rng_seed(lua_State* L);
static int impl_rng_draw(lua_State* L);

static void initialize_lua_state(lua_State * L)
{
// Open safe libraries.
// Debug and OS are not, but most of their functions will be disabled below.
static const luaL_Reg safe_libs[] = {
{ "", luaopen_base },
{ "table", luaopen_table },
{ "string", luaopen_string },
{ "math", luaopen_math },
{ "debug", luaopen_debug },
{ "os", luaopen_os },
{ NULL, NULL }
};
for (luaL_Reg const *lib = safe_libs; lib->func; ++lib)
{
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
}

// Disable functions from os which we don't want.
lua_getglobal(L, "os");
lua_pushnil(L);
while(lua_next(L, -2) != 0) {
lua_pop(L, 1);
char const* function = lua_tostring(L, -1);
if(strcmp(function, "clock") == 0 || strcmp(function, "date") == 0
|| strcmp(function, "time") == 0 || strcmp(function, "difftime") == 0) continue;
lua_pushnil(L);
lua_setfield(L, -3, function);
}
lua_pop(L, 1);

// Disable functions from debug which we don't want.
lua_getglobal(L, "debug");
lua_pushnil(L);
while(lua_next(L, -2) != 0) {
lua_pop(L, 1);
char const* function = lua_tostring(L, -1);
if(strcmp(function, "traceback") == 0) continue;
lua_pushnil(L);
lua_setfield(L, -3, function);
}
lua_pop(L, 1);

lua_settop(L, 0);

// Add mersenne twister rng wrapper

luaL_newmetatable(L, Rng);

static luaL_Reg const callbacks[] = {
{ "create", &impl_rng_create},
{ "__gc", &impl_rng_destroy},
{ "seed", &impl_rng_seed},
{ "draw", &impl_rng_draw},
{ NULL, NULL }
};
luaL_setfuncs(L, callbacks, 0);

lua_pushvalue(L, -1); //make a copy of this table, set it to be its own __index table
lua_setfield(L, -2, "__index");

lua_setglobal(L, Rng);
}

int impl_rng_create(lua_State* L)
{
mt_rng * ATTR_UNUSED(rng) = new ( lua_newuserdata(L, sizeof(mt_rng)) ) mt_rng();
luaL_setmetatable(L, Rng);

return 1;
}
int impl_rng_destroy(lua_State* L)
{
mt_rng * d = static_cast< mt_rng *> (luaL_testudata(L, 1, Rng));
if (d == NULL) {
ERR_NG << "rng_destroy called on data of type: " << lua_typename( L, lua_type( L, 1 ) ) << std::endl;
ERR_NG << "This may indicate a memory leak, please report at bugs.wesnoth.org" << std::endl;
} else {
d->~mt_rng();
}
return 0;
}
int impl_rng_seed(lua_State* L)
{
mt_rng * rng = static_cast<mt_rng *>(luaL_checkudata(L, 1, Rng));
std::string seed = luaL_checkstring(L, 2);

rng->seed_random(seed);
return 0;
}
int impl_rng_draw(lua_State* L)
{
mt_rng * rng = static_cast<mt_rng *>(luaL_checkudata(L, 1, Rng));

lua_pushnumber(L, rng->get_next_random());
return 1;
}

// End Lua Rng bindings

lua_map_generator::lua_map_generator(const config & cfg)
: id_(cfg["id"])
, config_name_(cfg["config_name"])
, create_map_(cfg["create_map"])
, create_scenario_(cfg["create_scenario"])
, mState_(luaL_newstate())
, lk_()
, generator_data_(cfg)
{
const char* required[] = {"id", "config_name", "create_map"};
Expand All @@ -174,59 +40,18 @@ lua_map_generator::lua_map_generator(const config & cfg)
throw mapgen_exception(msg);
}
}

initialize_lua_state(mState_);
}

lua_map_generator::~lua_map_generator()
{
lua_close(mState_);
}

std::string lua_map_generator::create_map()
{
{
int errcode = luaL_loadstring(mState_, create_map_.c_str());
if (errcode != LUA_OK) {
std::string msg = "Error when running lua_map_generator create_map.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += "Error when parsing create_map function. ";
if (errcode == LUA_ERRSYNTAX) {
msg += "There was a syntax error:\n";
} else {
msg += "There was a memory error:\n";
}
msg += lua_tostring(mState_, -1);
throw mapgen_exception(msg);
}
}
{
luaW_pushconfig(mState_, generator_data_);
int errcode = lua_pcall(mState_, 1, 1, 0);
if (errcode != LUA_OK) {
std::string msg = "Error when running lua_map_generator create_map.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += "Error when running create_map function. ";
if (errcode == LUA_ERRRUN) {
msg += "There was a runtime error:\n";
} else if (errcode == LUA_ERRERR) {
msg += "There was an error with the attached debugger:\n";
} else {
msg += "There was a memory or garbage collection error:\n";
}
msg += lua_tostring(mState_, -1);
throw mapgen_exception(msg);
}
}
if (!lua_isstring(mState_,-1)) {
try {
return lk_.create_map(create_map_.c_str(), generator_data_);
} catch (game::lua_error & e) {
std::string msg = "Error when running lua_map_generator create_map.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += "create_map did not return a string, instead it returned '";
msg += lua_typename(mState_, lua_type(mState_, -1));
msg += "'";
msg += e.what();
throw mapgen_exception(msg);
}
return lua_tostring(mState_, -1);
}

config lua_map_generator::create_scenario()
Expand All @@ -235,38 +60,12 @@ config lua_map_generator::create_scenario()
return map_generator::create_scenario();
}

{
int errcode = luaL_loadstring(mState_, create_scenario_.c_str());
if (errcode != LUA_OK) {
std::string msg = "Error when running lua_map_generator create_scenario.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += "Error when parsing create_scenario function. ";
if (errcode == LUA_ERRSYNTAX) {
msg += "There was a syntax error:\n";
} else {
msg += "There was a memory error:\n";
}
msg += lua_tostring(mState_, -1);
throw mapgen_exception(msg);
}
}
{
luaW_pushconfig(mState_, generator_data_);
int errcode = lua_pcall(mState_, 1, 1, 0);
if (errcode != LUA_OK) {
std::string msg = "Error when running lua_map_generator create_scenario.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += "Error when running create_scenario function. ";
if (errcode == LUA_ERRRUN) {
msg += "There was a runtime error:\n";
} else if (errcode == LUA_ERRERR) {
msg += "There was an error with the attached debugger:\n";
} else {
msg += "There was a memory or garbage collection error:\n";
}
msg += lua_tostring(mState_, -1);
throw mapgen_exception(msg);
}
try {
return lk_.create_scenario(create_scenario_.c_str(), generator_data_);
} catch (game::lua_error & e) {
std::string msg = "Error when running lua_map_generator create_scenario.\n";
msg += "The generator was: " + config_name_ + "\n";
msg += e.what();
throw mapgen_exception(msg);
}
return luaW_checkconfig(mState_, -1);
}
6 changes: 3 additions & 3 deletions src/generators/lua_map_generator.hpp
Expand Up @@ -18,6 +18,8 @@
#include "config.hpp"
#include "map_generator.hpp"

#include "scripting/mapgen_lua_kernel.hpp"

#include <string>

struct lua_State;
Expand All @@ -30,8 +32,6 @@ class lua_map_generator : public map_generator {
public:
lua_map_generator(const config & cfg);

~lua_map_generator();

bool allow_user_config() const { return false; }

std::string name() const { return "lua"; }
Expand All @@ -49,7 +49,7 @@ class lua_map_generator : public map_generator {
std::string create_map_;
std::string create_scenario_;

lua_State * mState_;
mapgen_lua_kernel lk_;

config generator_data_;
};
Expand Down
3 changes: 1 addition & 2 deletions src/scripting/application_lua_kernel.cpp
Expand Up @@ -104,8 +104,7 @@ void application_lua_kernel::call_script(const config & event_cfg) {

luaW_pushconfig(L, event_cfg); //push the config as an argument

pcall_fcn_ptr pcall = pcall_fcn();
if (!pcall(L, 1, 0)) //call the script from protected mode, there is one argument and we expect no return values.
if (!luaW_pcall(L, 1, 0)) //call the script from protected mode, there is one argument and we expect no return values.
{
WRN_LUA << "Got an error when executing script:\n" << lua_tostring(L,-1) << std::endl;
}
Expand Down

0 comments on commit 30bc486

Please sign in to comment.