lock unit_map while running filter or applying effects
This specially prevents lua form removing the unit that is currently filtered or that currently gets effects, which would cause crashes otherwise.
This commit is contained in:
parent
43275cd9ba
commit
ff5a37a064
2 changed files with 38 additions and 1 deletions
|
@ -149,6 +149,20 @@ static lg::log_domain log_scripting_lua("scripting/lua");
|
|||
std::vector<config> game_lua_kernel::preload_scripts;
|
||||
config game_lua_kernel::preload_config;
|
||||
|
||||
struct map_locker
|
||||
{
|
||||
map_locker(game_lua_kernel* kernel) : kernel_(kernel)
|
||||
{
|
||||
++kernel_->map_locked_;
|
||||
}
|
||||
~map_locker()
|
||||
{
|
||||
--kernel_->map_locked_;
|
||||
}
|
||||
game_lua_kernel* kernel_;
|
||||
};
|
||||
|
||||
|
||||
void game_lua_kernel::extract_preload_scripts(config const &game_config)
|
||||
{
|
||||
game_lua_kernel::preload_scripts.clear();
|
||||
|
@ -2285,6 +2299,9 @@ int game_lua_kernel::intf_print(lua_State *L) {
|
|||
*/
|
||||
int game_lua_kernel::intf_put_unit(lua_State *L)
|
||||
{
|
||||
if(map_locked_) {
|
||||
return luaL_error(L, "Attempted to move a unit while the map is locked");
|
||||
}
|
||||
int unit_arg = 1;
|
||||
int fire_event_arg = 4;
|
||||
|
||||
|
@ -2372,6 +2389,9 @@ int game_lua_kernel::intf_put_unit(lua_State *L)
|
|||
*/
|
||||
int game_lua_kernel::intf_erase_unit(lua_State *L)
|
||||
{
|
||||
if(map_locked_) {
|
||||
return luaL_error(L, "Attempted to remove a unit while the map is locked");
|
||||
}
|
||||
map_location loc;
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
|
@ -2420,6 +2440,9 @@ int game_lua_kernel::intf_erase_unit(lua_State *L)
|
|||
*/
|
||||
int game_lua_kernel::intf_put_recall_unit(lua_State *L)
|
||||
{
|
||||
if(map_locked_) {
|
||||
return luaL_error(L, "Attempted to move a unit while the map is locked");
|
||||
}
|
||||
lua_unit *lu = NULL;
|
||||
unit_ptr u = unit_ptr();
|
||||
int side = lua_tointeger(L, 2);
|
||||
|
@ -2460,6 +2483,9 @@ int game_lua_kernel::intf_put_recall_unit(lua_State *L)
|
|||
*/
|
||||
int game_lua_kernel::intf_extract_unit(lua_State *L)
|
||||
{
|
||||
if(map_locked_) {
|
||||
return luaL_error(L, "Attempted to remove a unit while the map is locked");
|
||||
}
|
||||
if (!luaW_hasmetatable(L, 1, getunitKey))
|
||||
return luaL_typerror(L, 1, "unit");
|
||||
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
|
||||
|
@ -4159,6 +4185,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
|
|||
, reports_(reports_object)
|
||||
, level_lua_()
|
||||
, queued_events_()
|
||||
, map_locked_(0)
|
||||
{
|
||||
static game_events::queued_event default_queued_event("_from_lua", map_location(), map_location(), config());
|
||||
queued_events_.push(&default_queued_event);
|
||||
|
@ -4741,7 +4768,7 @@ bool game_lua_kernel::run_wml_conditional(std::string const &cmd, vconfig const
|
|||
bool game_lua_kernel::run_filter(char const *name, unit const &u)
|
||||
{
|
||||
lua_State *L = mState;
|
||||
|
||||
map_locker(this);
|
||||
unit_map::const_unit_iterator ui = units().find(u.get_location());
|
||||
if (!ui.valid()) return false;
|
||||
|
||||
|
@ -4774,6 +4801,7 @@ void game_lua_kernel::apply_effect(const std::string& name, unit& u, const confi
|
|||
if (!luaW_getglobal(L, "wesnoth", "effects", name.c_str(), NULL)) {
|
||||
return;
|
||||
}
|
||||
map_locker(this);
|
||||
// Stack: effect_func
|
||||
lua_unit* lu = luaW_pushlocalunit(L, u);
|
||||
// Stack: effect_func, unit
|
||||
|
|
|
@ -167,6 +167,15 @@ class game_lua_kernel : public lua_kernel_base
|
|||
|
||||
public:
|
||||
std::vector<team> & teams();
|
||||
/**
|
||||
A value != 0 means that the shouldn't remove any units from the map, usually because
|
||||
we are currently operating on a unit& and removing it might cause memory corruptions
|
||||
note that we don't check for the dtor of lua owned units because we assume that
|
||||
we operate on such a unit that the lua function that invoked the operation on that unit
|
||||
(like wesnoth.add_modification, wesnoth.match_unit ..) have a local copy of that
|
||||
lua_unit* userdata in its stack that prevents it from beeing collected.
|
||||
*/
|
||||
int map_locked_;
|
||||
game_lua_kernel(CVideo *, game_state &, play_controller &, reports &);
|
||||
|
||||
void set_game_display(game_display * gd);
|
||||
|
|
Loading…
Add table
Reference in a new issue