Merge pull request #710 from spixi/call_events_by_id

Allow firing an event by id instead of name.
This commit is contained in:
Celtic Minstrel 2016-07-30 01:21:12 -04:00
commit dc3d22a5e4
14 changed files with 130 additions and 37 deletions

View file

@ -188,6 +188,7 @@ Version 1.13.5:
* Added new attribute "registered_users_only" to MultiplayerServerWML which indicates
that only registered users should be allowed to join the game
* wesnoth now does a stricter check for unit type ids.
* Added tag id= [fire_event], which allows raising events by id
* Lua API:
* wesnoth.match_unit can now take a location (rather than a unit) as
the optional third parameter. This will cause the filter to consider
@ -276,7 +277,9 @@ Version 1.13.5:
* [lua] tags now also support the [args] subtag outside events.
* added lua_function= attribute in location filters
* Added on_event.lua which is an eaiser to use wrapper for
wesnoth.game_events.on_event
wesnoth.game_events.on_event
* Added new functions wesnoth.fire_event_by_id and fire_event_by_name. The old
function wesnoth.fire_event is now an alias for wesnoth.fire_event_by_name
* Multiplayer:
* Hornshark Island: simplified multiplayer faction determination
* Added "Registered users only" checkbox to multiplayer configuration dialog which

View file

@ -141,7 +141,9 @@ function wml_actions.fire_event(cfg)
local w2 = helper.get_child(cfg, "secondary_attack")
if w2 then w1 = w1 or {} end
wesnoth.fire_event(cfg.name, x1, y1, x2, y2, w1, w2)
if cfg.id and cfg.id ~= "" then wesnoth.fire_event_by_id(cfg.id, x1, y1, x2, y2, w1, w2)
elseif cfg.name and cfg.name ~= "" then wesnoth.fire_event_by_name(cfg.name, x1, y1, x2, y2, w1, w2)
end
end
function wml_actions.allow_recruit(cfg)

View file

@ -216,3 +216,20 @@
{RETURN ({VARIABLE_CONDITIONAL pass_test equals 1})}
[/event]
)}
{GENERIC_UNIT_TEST "event_handlers_in_events_9" (
[event]
name=start
{VARIABLE pass_test 0}
[event]
name=foo
id=test
{VARIABLE pass_test 1}
[/event]
[fire_event]
id=test
[/fire_event]
{RETURN ({VARIABLE_CONDITIONAL pass_test equals 1})}
[/event]
)}

View file

@ -110,7 +110,7 @@ namespace {
scoped_weapon_info w1("weapon", e.data.child("first"));
scoped_weapon_info w2("second_weapon", e.data.child("second"));
game_events::queued_event q(tag, map_location(x1, y1), map_location(x2, y2), e.data);
game_events::queued_event q(tag, "", map_location(x1, y1), map_location(x2, y2), e.data);
resources::lua_kernel->run_wml_action("command", vconfig(e.commands), q);
if(u1) {

View file

@ -27,6 +27,7 @@
#include "config.hpp"
#include "utils/smart_list.hpp"
#include <memory>
#include <set>
#include <string>

View file

@ -58,6 +58,11 @@ void manager::remove_event_handler(const std::string & id)
event_handlers_->remove_event_handler(id);
}
/** Gets an event handler by id */
const handler_ptr manager::get_event_handler_by_id(const std::string & id)
{
return event_handlers_->get_event_handler_by_id(id);
}
/* ** manager ** */

View file

@ -109,6 +109,8 @@ namespace game_events {
void add_event_handler(const config & handler, bool is_menu_item=false);
/// Removes an event handler.
void remove_event_handler(const std::string & id);
/// Gets an event handler by ID
const handler_ptr get_event_handler_by_id(const std::string & id);
void add_events(const config::const_child_itors &cfgs,
const std::string& type = std::string());

View file

@ -26,7 +26,6 @@
#include "resources.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "serialization/string_utils.hpp"
#include "soundsource.hpp"
#include "util.hpp"
#include <iostream>
@ -165,4 +164,12 @@ namespace game_events {
log_handlers();
}
const handler_ptr t_event_handlers::get_event_handler_by_id(const std::string & id) {
id_map_t::iterator find_it = id_map_.find(id);
if ( find_it != id_map_.end() && !find_it->second.expired() ) {
return handler_ptr( find_it->second );
}
return handler_ptr( );
}
} // end namespace game_events

View file

@ -17,6 +17,7 @@
#include "game_events/handlers.hpp"
#include <memory>
#include <unordered_map>
namespace game_events {
@ -60,6 +61,8 @@ namespace game_events {
void add_event_handler(const config & cfg, manager & man, bool is_menu_item=false);
/// Removes an event handler, identified by its ID.
void remove_event_handler(std::string const & id);
/// Gets an event handler, identified by its ID.
const handler_ptr get_event_handler_by_id(const std::string & id);
iterator begin() { return active_.begin(); }
const_iterator begin() const { return active_.begin(); }

View file

@ -267,6 +267,8 @@ namespace { // Support functions
*/
bool t_pump::process_event(handler_ptr& handler_p, const queued_event& ev)
{
DBG_EH << "processing event " << ev.name << " with id=" << ev.id << "\n";
// We currently never pass a null pointer to this function, but to
// guard against future modifications:
if ( !handler_p )
@ -466,7 +468,18 @@ bool t_pump::fire(const std::string& event,
return (*this)();
}
bool t_pump::fire(const std::string& event,
const std::string& id,
const entity_location& loc1,
const entity_location& loc2,
const config& data)
{
raise(event,id,loc1,loc2,data);
return (*this)();
}
void t_pump::raise(const std::string& event,
const std::string& id,
const entity_location& loc1,
const entity_location& loc2,
const config& data)
@ -474,9 +487,9 @@ void t_pump::raise(const std::string& event,
if(resources::screen == nullptr)
return;
DBG_EH << "raising event: " << event << "\n";
DBG_EH << "raising event name=" << event << ", id=" << id << "\n";
impl_->events_queue.push_back(queued_event(event, loc1, loc2, data));
impl_->events_queue.push_back(queued_event(event, id, loc1, loc2, data));
}
bool t_pump::operator()()
@ -497,7 +510,7 @@ bool t_pump::operator()()
if(!lg::debug().dont_log("event_handler")) {
std::stringstream ss;
for(const queued_event& ev : impl_->events_queue) {
ss << "name=" << ev.name << "; ";
ss << "name=" << ev.name << ", " << "id=" << ev.id << "; ";
}
DBG_EH << "processing queued events: " << ss.str() << "\n";
}
@ -513,7 +526,12 @@ bool t_pump::operator()()
while ( !pump_instance.done() )
{
queued_event & ev = pump_instance.next();
if( ev.name.empty() and ev.id.empty() )
continue;
const std::string& event_name = ev.name;
const std::string& event_id = ev.id;
// Clear the unit cache, since the best clearing time is hard to figure out
// due to status changes by WML. Every event will flush the cache.
@ -525,30 +543,39 @@ bool t_pump::operator()()
++impl_->internal_wml_tracking;
}
}
// Initialize an iteration over event handlers matching this event.
assert(impl_->my_manager);
manager::iteration handler_iter(event_name, *impl_->my_manager);
// If there are any matching event handlers, initialize variables.
// Note: Initializing variables all the time would not be
// functionally wrong, merely inefficient. So we do not have
// to cache *handler_iter here.
if ( *handler_iter ) {
resources::gamedata->get_variable("x1") = ev.loc1.filter_x() + 1;
resources::gamedata->get_variable("y1") = ev.loc1.filter_y() + 1;
resources::gamedata->get_variable("x2") = ev.loc2.filter_x() + 1;
resources::gamedata->get_variable("y2") = ev.loc2.filter_y() + 1;
handler_ptr cur_handler;
resources::gamedata->get_variable("x1") = ev.loc1.filter_x() + 1;
resources::gamedata->get_variable("y1") = ev.loc1.filter_y() + 1;
resources::gamedata->get_variable("x2") = ev.loc2.filter_x() + 1;
resources::gamedata->get_variable("y2") = ev.loc2.filter_y() + 1;
if ( event_id.empty() ) {
// Initialize an iteration over event handlers matching this event.
manager::iteration handler_iter(event_name, *impl_->my_manager);
// While there is a potential handler for this event name.
while ( cur_handler = *handler_iter ) {
// Let this handler process our event.
process_event(cur_handler, ev);
// NOTE: cur_handler may be null at this point!
++handler_iter;
}
}
else {
// While there is a potential handler for this event name.
while ( handler_ptr cur_handler = *handler_iter ) {
DBG_EH << "processing event " << event_name << " with id="<<
cur_handler->get_config()["id"] << "\n";
// Let this handler process our event.
process_event(cur_handler, ev);
// NOTE: cur_handler may be null at this point!
//Get the handler directly via ID
cur_handler = impl_->my_manager->get_event_handler_by_id( event_id );
++handler_iter;
if( cur_handler ) {
process_event(cur_handler, ev);
}
}
// Flush messages when finished iterating over event_handlers.

View file

@ -33,8 +33,8 @@
#include "config.hpp"
#include<string>
#include<sstream>
#include <string>
#include <sstream>
class game_display;
class vconfig;
@ -44,14 +44,15 @@ namespace lg { class logger; }
namespace game_events
{
struct queued_event {
queued_event(const std::string& name, const entity_location& loc1,
queued_event(const std::string& name, const std::string& id, const entity_location& loc1,
const entity_location& loc2, const config& data)
: name(name), loc1(loc1), loc2(loc2), data(data)
: name(name), id(id), loc1(loc1), loc2(loc2), data(data)
{
std::replace(this->name.begin(), this->name.end(), ' ', '_');
}
std::string name;
std::string id;
entity_location loc1;
entity_location loc2;
config data;
@ -92,11 +93,25 @@ namespace game_events
const entity_location& loc2=entity_location::null_entity,
const config& data=config());
bool fire(const std::string& event,
const std::string& id,
const entity_location& loc1=entity_location::null_entity,
const entity_location& loc2=entity_location::null_entity,
const config& data=config());
void raise(const std::string& event,
const std::string& id,
const entity_location& loc1=entity_location::null_entity,
const entity_location& loc2=entity_location::null_entity,
const config& data=config());
inline void raise(const std::string& event,
const entity_location& loc1=entity_location::null_entity,
const entity_location& loc2=entity_location::null_entity,
const config& data=config()) {
raise(event,"",loc1,loc2,data);
}
bool operator()();
/**

View file

@ -144,7 +144,7 @@ void menu_handler::objectives(int side_num)
config cfg;
cfg["side"] = std::to_string(side_num);
gamestate().lua_kernel_->run_wml_action("show_objectives", vconfig(cfg),
game_events::queued_event("_from_interface", map_location(),
game_events::queued_event("_from_interface", "", map_location(),
map_location(), config()));
team &current_team = teams()[side_num - 1];
dialogs::show_objectives(pc_.get_scenario_name(), current_team.objectives());

View file

@ -1045,14 +1045,14 @@ int game_lua_kernel::intf_get_recall_units(lua_State *L)
/**
* Fires an event.
* - Arg 1: string containing the event name.
* - Arg 1: string containing the event name or id.
* - Arg 2: optional first location.
* - Arg 3: optional second location.
* - Arg 4: optional WML table used as the [weapon] tag.
* - Arg 5: optional WML table used as the [second_weapon] tag.
* - Ret 1: boolean indicating whether the event was processed or not.
*/
int game_lua_kernel::intf_fire_event(lua_State *L)
int game_lua_kernel::intf_fire_event(lua_State *L, const bool by_id)
{
char const *m = luaL_checkstring(L, 1);
@ -1076,11 +1076,19 @@ int game_lua_kernel::intf_fire_event(lua_State *L)
data.add_child("second", luaW_checkconfig(L, pos));
}
bool b = play_controller_.pump().fire(m, l1, l2, data);
bool b = false;
if (by_id) {
b = play_controller_.pump().fire("", m, l1, l2, data);
}
else {
b = play_controller_.pump().fire(m, l1, l2, data);
}
lua_pushboolean(L, b);
return 1;
}
/**
* Fires a wml menu item.
* - Arg 1: id of the item. it is not possible to fire items that don't have ids with this function.
@ -1737,6 +1745,7 @@ int game_lua_kernel::impl_current_get(lua_State *L)
const game_events::queued_event &ev = get_event_info();
config cfg;
cfg["name"] = ev.name;
cfg["id"] = ev.id;
if (const config &weapon = ev.data.child("first")) {
cfg.add_child("weapon", weapon);
}
@ -4582,7 +4591,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
, queued_events_()
, map_locked_(0)
{
static game_events::queued_event default_queued_event("_from_lua", map_location(), map_location(), config());
static game_events::queued_event default_queued_event("_from_lua", "", map_location(), map_location(), config());
queued_events_.push(&default_queued_event);
lua_State *L = mState;
@ -4635,7 +4644,9 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
{ "find_path", &dispatch<&game_lua_kernel::intf_find_path > },
{ "find_reach", &dispatch<&game_lua_kernel::intf_find_reach > },
{ "find_vacant_tile", &dispatch<&game_lua_kernel::intf_find_vacant_tile > },
{ "fire_event", &dispatch<&game_lua_kernel::intf_fire_event > },
{ "fire_event", &dispatch2<&game_lua_kernel::intf_fire_event, false > },
{ "fire_event_by_name", &dispatch2<&game_lua_kernel::intf_fire_event, false > },
{ "fire_event_by_id", &dispatch2<&game_lua_kernel::intf_fire_event, true > },
{ "fire_wml_menu_item", &dispatch<&game_lua_kernel::intf_fire_wml_menu_item > },
{ "float_label", &dispatch<&game_lua_kernel::intf_float_label > },
{ "gamestate_inspector", &dispatch<&game_lua_kernel::intf_gamestate_inspector > },

View file

@ -162,7 +162,7 @@ class game_lua_kernel : public lua_kernel_base
int impl_theme_items_set(lua_State *L);
int cfun_builtin_effect(lua_State *L);
int cfun_wml_action(lua_State *L);
int intf_fire_event(lua_State *L);
int intf_fire_event(lua_State *L, const bool by_id);
int intf_fire_wml_menu_item(lua_State *L);
int intf_teleport(lua_State *L);
int intf_remove_sound_source(lua_State *L);