Game Events: reformatted pump code
[ci skip]
This commit is contained in:
parent
79ffbbe9b4
commit
a25f3d39f0
2 changed files with 471 additions and 433 deletions
|
@ -24,23 +24,22 @@
|
|||
|
||||
#include "display_chat_manager.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "game_display.hpp"
|
||||
#include "game_data.hpp"
|
||||
#include "game_display.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "play_controller.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
#include "side_filter.hpp"
|
||||
#include "units/unit.hpp"
|
||||
#include "units/map.hpp"
|
||||
#include "whiteboard/manager.hpp"
|
||||
#include "units/unit.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "whiteboard/manager.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
static lg::log_domain log_engine("engine");
|
||||
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||
|
@ -56,27 +55,36 @@ static lg::log_domain log_event_handler("event_handler");
|
|||
#define DBG_EH LOG_STREAM(debug, log_event_handler)
|
||||
|
||||
// This file is in the game_events namespace.
|
||||
namespace game_events {
|
||||
namespace game_events
|
||||
{
|
||||
namespace context
|
||||
{
|
||||
/// State when processing a particular flight of events or commands.
|
||||
struct state
|
||||
{
|
||||
bool mutated;
|
||||
bool skip_messages;
|
||||
|
||||
namespace context {
|
||||
/// State when processing a particular flight of events or commands.
|
||||
struct state {
|
||||
bool mutated;
|
||||
bool skip_messages;
|
||||
explicit state(bool s, bool m = true)
|
||||
: mutated(m)
|
||||
, skip_messages(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
explicit state(bool s, bool m = true) : mutated(m), skip_messages(s) {}
|
||||
};
|
||||
class scoped
|
||||
{
|
||||
public:
|
||||
scoped(std::stack<context::state>& contexts, bool m = true);
|
||||
~scoped();
|
||||
|
||||
class scoped {
|
||||
public:
|
||||
scoped(std::stack<context::state> & contexts, bool m = true);
|
||||
~scoped();
|
||||
private:
|
||||
std::stack<context::state> & contexts_;
|
||||
};
|
||||
private:
|
||||
std::stack<context::state>& contexts_;
|
||||
};
|
||||
}
|
||||
|
||||
struct pump_impl {
|
||||
struct pump_impl
|
||||
{
|
||||
std::vector<queued_event> events_queue;
|
||||
|
||||
/// The value returned by wml_tracking();
|
||||
|
@ -88,9 +96,9 @@ struct pump_impl {
|
|||
|
||||
unsigned instance_count;
|
||||
|
||||
manager * my_manager;
|
||||
manager* my_manager;
|
||||
|
||||
pump_impl(manager & man)
|
||||
pump_impl(manager& man)
|
||||
: events_queue()
|
||||
, internal_wml_tracking(0)
|
||||
, wml_messages_stream()
|
||||
|
@ -102,306 +110,317 @@ struct pump_impl {
|
|||
}
|
||||
};
|
||||
|
||||
namespace { // Types
|
||||
class pump_manager {
|
||||
public:
|
||||
pump_manager(pump_impl & );
|
||||
~pump_manager();
|
||||
namespace
|
||||
{ // Types
|
||||
class pump_manager
|
||||
{
|
||||
public:
|
||||
pump_manager(pump_impl&);
|
||||
~pump_manager();
|
||||
|
||||
/// Allows iteration through the queued events.
|
||||
queued_event & next() { return queue_[pumped_count_++]; }
|
||||
/// Indicates the iteration is over.
|
||||
bool done() const { return pumped_count_ >= queue_.size(); }
|
||||
|
||||
unsigned count() {
|
||||
return impl_.instance_count;
|
||||
}
|
||||
|
||||
private:
|
||||
pump_impl & impl_;
|
||||
int x1_, x2_, y1_, y2_;
|
||||
/// Tracks the events to process.
|
||||
/// This isolates these events from any events that might be generated
|
||||
/// during the processing.
|
||||
std::vector<queued_event> queue_;
|
||||
/// Tracks how many events have been processed.
|
||||
size_t pumped_count_;
|
||||
};
|
||||
} // end anonymous namespace (types)
|
||||
|
||||
namespace { // Support functions
|
||||
|
||||
pump_manager::pump_manager(pump_impl & impl) :
|
||||
impl_(impl),
|
||||
x1_(resources::gamedata->get_variable("x1")),
|
||||
x2_(resources::gamedata->get_variable("x2")),
|
||||
y1_(resources::gamedata->get_variable("y1")),
|
||||
y2_(resources::gamedata->get_variable("y2")),
|
||||
queue_(), // Filled later with a swap().
|
||||
pumped_count_(0)
|
||||
/// Allows iteration through the queued events.
|
||||
queued_event& next()
|
||||
{
|
||||
queue_.swap(impl_.events_queue);
|
||||
++impl_.instance_count;
|
||||
return queue_[pumped_count_++];
|
||||
}
|
||||
/// Indicates the iteration is over.
|
||||
bool done() const
|
||||
{
|
||||
return pumped_count_ >= queue_.size();
|
||||
}
|
||||
|
||||
pump_manager::~pump_manager() {
|
||||
--impl_.instance_count;
|
||||
unsigned count()
|
||||
{
|
||||
return impl_.instance_count;
|
||||
}
|
||||
|
||||
// Not sure what the correct thing to do is here. In princple,
|
||||
// discarding all events (i.e. clearing events_queue) seems like
|
||||
// the right thing to do in the face of an exception. However, the
|
||||
// previous functionality preserved the queue, so for now we will
|
||||
// restore it.
|
||||
if ( !done() ) {
|
||||
// The remainig events get inserted at the beginning of events_queue.
|
||||
std::vector<queued_event> temp;
|
||||
impl_.events_queue.swap(temp);
|
||||
impl_.events_queue.insert(impl_.events_queue.end(), queue_.begin() + pumped_count_, queue_.end());
|
||||
impl_.events_queue.insert(impl_.events_queue.end(), temp.begin(), temp.end());
|
||||
private:
|
||||
pump_impl& impl_;
|
||||
int x1_, x2_, y1_, y2_;
|
||||
|
||||
/**
|
||||
* Tracks the events to process.
|
||||
* This isolates these events from any events that might be generated during the processing.
|
||||
*/
|
||||
std::vector<queued_event> queue_;
|
||||
|
||||
/** Tracks how many events have been processed. */
|
||||
size_t pumped_count_;
|
||||
};
|
||||
} // end anonymous namespace (types)
|
||||
|
||||
namespace
|
||||
{ // Support functions
|
||||
|
||||
pump_manager::pump_manager(pump_impl& impl)
|
||||
: impl_(impl)
|
||||
, x1_(resources::gamedata->get_variable("x1"))
|
||||
, x2_(resources::gamedata->get_variable("x2"))
|
||||
, y1_(resources::gamedata->get_variable("y1"))
|
||||
, y2_(resources::gamedata->get_variable("y2"))
|
||||
, queue_()
|
||||
, pumped_count_(0) // Filled later with a swap().
|
||||
{
|
||||
queue_.swap(impl_.events_queue);
|
||||
++impl_.instance_count;
|
||||
}
|
||||
|
||||
pump_manager::~pump_manager()
|
||||
{
|
||||
--impl_.instance_count;
|
||||
|
||||
// Not sure what the correct thing to do is here. In princple,
|
||||
// discarding all events (i.e. clearing events_queue) seems like
|
||||
// the right thing to do in the face of an exception. However, the
|
||||
// previous functionality preserved the queue, so for now we will
|
||||
// restore it.
|
||||
if(!done()) {
|
||||
// The remaining events get inserted at the beginning of events_queue.
|
||||
std::vector<queued_event> temp;
|
||||
impl_.events_queue.swap(temp);
|
||||
impl_.events_queue.insert(impl_.events_queue.end(), queue_.begin() + pumped_count_, queue_.end());
|
||||
impl_.events_queue.insert(impl_.events_queue.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
// Restore the old values of the game variables.
|
||||
resources::gamedata->get_variable("y2") = y2_;
|
||||
resources::gamedata->get_variable("y1") = y1_;
|
||||
resources::gamedata->get_variable("x2") = x2_;
|
||||
resources::gamedata->get_variable("x1") = x1_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the given event passes all its filters.
|
||||
*/
|
||||
bool wml_event_pump::filter_event(const event_handler& handler, const queued_event& ev)
|
||||
{
|
||||
const unit_map& units = resources::gameboard->units();
|
||||
unit_map::const_iterator unit1 = units.find(ev.loc1);
|
||||
unit_map::const_iterator unit2 = units.find(ev.loc2);
|
||||
vconfig filters(handler.get_config());
|
||||
|
||||
for(const vconfig& condition : filters.get_children("filter_condition")) {
|
||||
if(!conditional_passed(condition)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(const vconfig& f : filters.get_children("filter_side")) {
|
||||
side_filter ssf(f, &resources::controller->gamestate());
|
||||
if(!ssf.match(resources::controller->current_side()))
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const vconfig& f : filters.get_children("filter")) {
|
||||
if(!ev.loc1.matches_unit_filter(unit1, f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vconfig::child_list special_filters = filters.get_children("filter_attack");
|
||||
bool special_matches = special_filters.empty();
|
||||
if(!special_matches && unit1 != units.end()) {
|
||||
const bool matches_unit = ev.loc1.matches_unit(unit1);
|
||||
const config& attack = ev.data.child("first");
|
||||
for(const vconfig& f : special_filters) {
|
||||
if(f.empty()) {
|
||||
special_matches = true;
|
||||
} else if(!matches_unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
special_matches = special_matches || matches_special_filter(attack, f);
|
||||
}
|
||||
}
|
||||
|
||||
if(!special_matches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const vconfig& f : filters.get_children("filter_second")) {
|
||||
if(!ev.loc2.matches_unit_filter(unit2, f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
special_filters = filters.get_children("filter_second_attack");
|
||||
special_matches = special_filters.empty();
|
||||
if(!special_matches && unit2 != units.end()) {
|
||||
const bool matches_unit = ev.loc2.matches_unit(unit2);
|
||||
const config& attack = ev.data.child("second");
|
||||
for(const vconfig& f : special_filters) {
|
||||
if(f.empty()) {
|
||||
special_matches = true;
|
||||
} else if(!matches_unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
special_matches = special_matches || matches_special_filter(attack, f);
|
||||
}
|
||||
}
|
||||
|
||||
if(!special_matches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All filters passed.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an event through a single event handler.
|
||||
* This includes checking event filters, but not checking that the event
|
||||
* name matches.
|
||||
*
|
||||
* @param[in,out] handler_p The handler to offer the event to.
|
||||
* This may be reset during processing.
|
||||
* @param[in] ev The event information.
|
||||
*
|
||||
* @returns true if the game state changed.
|
||||
*/
|
||||
bool wml_event_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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unit_map& units = resources::gameboard->units();
|
||||
scoped_xy_unit first_unit("unit", ev.loc1, units);
|
||||
scoped_xy_unit second_unit("second_unit", ev.loc2, units);
|
||||
scoped_weapon_info first_weapon("weapon", ev.data.child("first"));
|
||||
scoped_weapon_info second_weapon("second_weapon", ev.data.child("second"));
|
||||
|
||||
if(!filter_event(*handler_p, ev)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The event hasn't been filtered out, so execute the handler.
|
||||
++impl_->internal_wml_tracking;
|
||||
context::scoped evc(impl_->contexts_);
|
||||
assert(resources::lua_kernel != nullptr);
|
||||
handler_p->handle_event(ev, handler_p, *resources::lua_kernel);
|
||||
// NOTE: handler_p may be null at this point!
|
||||
|
||||
if(ev.name == "select") {
|
||||
resources::gamedata->last_selected = ev.loc1;
|
||||
}
|
||||
|
||||
if(resources::screen != nullptr) {
|
||||
resources::screen->maybe_rebuild();
|
||||
}
|
||||
|
||||
return context_mutated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for show_wml_messages(), which gathers
|
||||
* the messages from a stringstream.
|
||||
*/
|
||||
void wml_event_pump::fill_wml_messages_map(std::map<std::string, int>& msg_map, std::stringstream& source)
|
||||
{
|
||||
while(true) {
|
||||
std::string msg;
|
||||
std::getline(source, msg);
|
||||
|
||||
if(source.eof()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Restore the old values of the game variables.
|
||||
resources::gamedata->get_variable("y2") = y2_;
|
||||
resources::gamedata->get_variable("y1") = y1_;
|
||||
resources::gamedata->get_variable("x2") = x2_;
|
||||
resources::gamedata->get_variable("x1") = x1_;
|
||||
if(msg == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(msg_map.find(msg) == msg_map.end()) {
|
||||
msg_map[msg] = 1;
|
||||
} else {
|
||||
msg_map[msg]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the eof flag is cleared otherwise no new messages are shown
|
||||
source.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a summary of messages/errors generated so far by WML.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
* Messages are also written to std::cerr if to_cerr is true.
|
||||
*/
|
||||
void wml_event_pump::show_wml_messages(std::stringstream& source, const std::string& caption, bool to_cerr)
|
||||
{
|
||||
// Get all unique messages in messages,
|
||||
// with the number of encounters for these messages
|
||||
std::map<std::string, int> messages;
|
||||
fill_wml_messages_map(messages, source);
|
||||
|
||||
// Show the messages collected
|
||||
for(std::map<std::string, int>::const_iterator itor = messages.begin(); itor != messages.end(); ++itor) {
|
||||
std::stringstream msg;
|
||||
msg << itor->first;
|
||||
if(itor->second > 1) {
|
||||
msg << " (" << itor->second << ")";
|
||||
}
|
||||
|
||||
resources::screen->get_chat_manager().add_chat_message(
|
||||
time(nullptr), caption, 0, msg.str(), events::chat_handler::MESSAGE_PUBLIC, false);
|
||||
|
||||
if(to_cerr) {
|
||||
std::cerr << caption << ": " << msg.str() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the given event passes all its filters.
|
||||
*/
|
||||
bool wml_event_pump::filter_event(const event_handler& handler, const queued_event& ev)
|
||||
{
|
||||
const unit_map& units = resources::gameboard->units();
|
||||
unit_map::const_iterator unit1 = units.find(ev.loc1);
|
||||
unit_map::const_iterator unit2 = units.find(ev.loc2);
|
||||
vconfig filters(handler.get_config());
|
||||
/**
|
||||
* Shows a summary of the errors encountered in WML so far,
|
||||
* to avoid a lot of the same messages to be shown.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
* Messages are always written to std::cerr.
|
||||
*/
|
||||
void wml_event_pump::show_wml_errors()
|
||||
{
|
||||
static const std::string caption("Invalid WML found");
|
||||
|
||||
for (const vconfig &condition : filters.get_children("filter_condition"))
|
||||
{
|
||||
if (!conditional_passed(condition)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
show_wml_messages(lg::wml_error(), caption, true);
|
||||
}
|
||||
|
||||
for (const vconfig &f : filters.get_children("filter_side"))
|
||||
{
|
||||
side_filter ssf(f, &resources::controller->gamestate());
|
||||
if ( !ssf.match(resources::controller->current_side()) )
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Shows a summary of the messages generated so far by WML.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
*/
|
||||
void wml_event_pump::show_wml_messages()
|
||||
{
|
||||
static const std::string caption("WML");
|
||||
|
||||
for (const vconfig &f : filters.get_children("filter"))
|
||||
{
|
||||
if ( !ev.loc1.matches_unit_filter(unit1, f) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
show_wml_messages(impl_->wml_messages_stream, caption, false);
|
||||
}
|
||||
|
||||
vconfig::child_list special_filters = filters.get_children("filter_attack");
|
||||
bool special_matches = special_filters.empty();
|
||||
if ( !special_matches && unit1 != units.end() )
|
||||
{
|
||||
const bool matches_unit = ev.loc1.matches_unit(unit1);
|
||||
const config & attack = ev.data.child("first");
|
||||
for (const vconfig &f : special_filters)
|
||||
{
|
||||
if ( f.empty() )
|
||||
special_matches = true;
|
||||
else if ( !matches_unit )
|
||||
return false;
|
||||
|
||||
special_matches = special_matches ||
|
||||
matches_special_filter(attack, f);
|
||||
}
|
||||
}
|
||||
if(!special_matches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const vconfig &f : filters.get_children("filter_second"))
|
||||
{
|
||||
if ( !ev.loc2.matches_unit_filter(unit2, f) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
special_filters = filters.get_children("filter_second_attack");
|
||||
special_matches = special_filters.empty();
|
||||
if ( !special_matches && unit2 != units.end() )
|
||||
{
|
||||
const bool matches_unit = ev.loc2.matches_unit(unit2);
|
||||
const config & attack = ev.data.child("second");
|
||||
for (const vconfig &f : special_filters)
|
||||
{
|
||||
if ( f.empty() )
|
||||
special_matches = true;
|
||||
else if ( !matches_unit )
|
||||
return false;
|
||||
|
||||
special_matches = special_matches ||
|
||||
matches_special_filter(attack, f);
|
||||
}
|
||||
}
|
||||
if(!special_matches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All filters passed.
|
||||
return true;
|
||||
void wml_event_pump::put_wml_message(
|
||||
lg::logger& logger, const std::string& prefix, const std::string& message, bool in_chat)
|
||||
{
|
||||
logger(log_wml) << message << std::endl;
|
||||
if(in_chat) {
|
||||
impl_->wml_messages_stream << prefix << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an event through a single event handler.
|
||||
* This includes checking event filters, but not checking that the event
|
||||
* name matches.
|
||||
*
|
||||
* @param[in,out] handler_p The handler to offer the event to.
|
||||
* This may be reset during processing.
|
||||
* @param[in] ev The event information.
|
||||
*
|
||||
* @returns true if the game state changed.
|
||||
*/
|
||||
bool wml_event_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 )
|
||||
return false;
|
||||
|
||||
unit_map& units = resources::gameboard->units();
|
||||
scoped_xy_unit first_unit("unit", ev.loc1, units);
|
||||
scoped_xy_unit second_unit("second_unit", ev.loc2, units);
|
||||
scoped_weapon_info first_weapon("weapon", ev.data.child("first"));
|
||||
scoped_weapon_info second_weapon("second_weapon", ev.data.child("second"));
|
||||
|
||||
if ( !filter_event(*handler_p, ev) )
|
||||
return false;
|
||||
|
||||
// The event hasn't been filtered out, so execute the handler.
|
||||
++impl_->internal_wml_tracking;
|
||||
context::scoped evc(impl_->contexts_);
|
||||
assert(resources::lua_kernel != nullptr);
|
||||
handler_p->handle_event(ev, handler_p, *resources::lua_kernel);
|
||||
// NOTE: handler_p may be null at this point!
|
||||
|
||||
if(ev.name == "select") {
|
||||
resources::gamedata->last_selected = ev.loc1;
|
||||
}
|
||||
if(resources::screen != nullptr) {
|
||||
resources::screen->maybe_rebuild();
|
||||
}
|
||||
return context_mutated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for show_wml_messages(), which gathers
|
||||
* the messages from a stringstream.
|
||||
*/
|
||||
void wml_event_pump::fill_wml_messages_map(std::map<std::string, int>& msg_map, std::stringstream& source)
|
||||
{
|
||||
while(true) {
|
||||
std::string msg;
|
||||
std::getline(source, msg);
|
||||
|
||||
if(source.eof()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(msg == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(msg_map.find(msg) == msg_map.end()) {
|
||||
msg_map[msg] = 1;
|
||||
} else {
|
||||
msg_map[msg]++;
|
||||
}
|
||||
}
|
||||
// Make sure the eof flag is cleared otherwise no new messages are shown
|
||||
source.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a summary of messages/errors generated so far by WML.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
* Messages are also written to std::cerr if to_cerr is true.
|
||||
*/
|
||||
void wml_event_pump::show_wml_messages(std::stringstream& source, const std::string & caption,
|
||||
bool to_cerr)
|
||||
{
|
||||
// Get all unique messages in messages,
|
||||
// with the number of encounters for these messages
|
||||
std::map<std::string, int> messages;
|
||||
fill_wml_messages_map(messages, source);
|
||||
|
||||
// Show the messages collected
|
||||
for(std::map<std::string, int>::const_iterator itor = messages.begin();
|
||||
itor != messages.end(); ++itor )
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << itor->first;
|
||||
if(itor->second > 1) {
|
||||
msg << " (" << itor->second << ")";
|
||||
}
|
||||
|
||||
resources::screen->get_chat_manager().add_chat_message(time(nullptr), caption, 0, msg.str(),
|
||||
events::chat_handler::MESSAGE_PUBLIC, false);
|
||||
if ( to_cerr )
|
||||
std::cerr << caption << ": " << msg.str() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a summary of the errors encountered in WML so far,
|
||||
* to avoid a lot of the same messages to be shown.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
* Messages are always written to std::cerr.
|
||||
*/
|
||||
void wml_event_pump::show_wml_errors()
|
||||
{
|
||||
static const std::string caption("Invalid WML found");
|
||||
|
||||
show_wml_messages(lg::wml_error(), caption, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a summary of the messages generated so far by WML.
|
||||
* Identical messages are shown once, with (between parentheses)
|
||||
* the number of times that message was encountered.
|
||||
* The order in which the messages are shown does not need
|
||||
* to be the order in which these messages are encountered.
|
||||
*/
|
||||
void wml_event_pump::show_wml_messages()
|
||||
{
|
||||
static const std::string caption("WML");
|
||||
|
||||
show_wml_messages(impl_->wml_messages_stream, caption, false);
|
||||
}
|
||||
|
||||
void wml_event_pump::put_wml_message(lg::logger& logger, const std::string& prefix, const std::string& message, bool in_chat)
|
||||
{
|
||||
logger(log_wml) << message << std::endl;
|
||||
if (in_chat)
|
||||
{
|
||||
impl_->wml_messages_stream << prefix << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context::scoped::scoped(std::stack<context::state> & contexts, bool m)
|
||||
context::scoped::scoped(std::stack<context::state>& contexts, bool m)
|
||||
: contexts_(contexts)
|
||||
{
|
||||
//The default context at least should always be on the stack
|
||||
// The default context at least should always be on the stack
|
||||
assert(contexts_.size() > 0);
|
||||
|
||||
bool skip_messages = (contexts_.size() > 1) && contexts_.top().skip_messages;
|
||||
|
@ -446,41 +465,39 @@ void wml_event_pump::context_skip_messages(bool b)
|
|||
*/
|
||||
void wml_event_pump::put_wml_message(const std::string& logger, const std::string& message, bool in_chat)
|
||||
{
|
||||
if (logger == "err" || logger == "error") {
|
||||
put_wml_message(lg::err(), _("Error: "), message, in_chat );
|
||||
} else if (logger == "warn" || logger == "wrn" || logger == "warning") {
|
||||
put_wml_message(lg::warn(), _("Warning: "), message, in_chat );
|
||||
} else if ((logger == "debug" || logger == "dbg") && !lg::debug().dont_log(log_wml)) {
|
||||
put_wml_message(lg::debug(), _("Debug: "), message, in_chat );
|
||||
} else if (!lg::info().dont_log(log_wml)) {
|
||||
put_wml_message(lg::info(), _("Info: "), message, in_chat );
|
||||
if(logger == "err" || logger == "error") {
|
||||
put_wml_message(lg::err(), _("Error: "), message, in_chat);
|
||||
} else if(logger == "warn" || logger == "wrn" || logger == "warning") {
|
||||
put_wml_message(lg::warn(), _("Warning: "), message, in_chat);
|
||||
} else if((logger == "debug" || logger == "dbg") && !lg::debug().dont_log(log_wml)) {
|
||||
put_wml_message(lg::debug(), _("Debug: "), message, in_chat);
|
||||
} else if(!lg::info().dont_log(log_wml)) {
|
||||
put_wml_message(lg::info(), _("Info: "), message, in_chat);
|
||||
}
|
||||
}
|
||||
|
||||
bool wml_event_pump::fire(const std::string& event,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& data)
|
||||
bool wml_event_pump::fire(
|
||||
const std::string& event, const entity_location& loc1, const entity_location& loc2, const config& data)
|
||||
{
|
||||
raise(event,loc1,loc2,data);
|
||||
raise(event, loc1, loc2, data);
|
||||
return (*this)();
|
||||
}
|
||||
|
||||
bool wml_event_pump::fire(const std::string& event,
|
||||
const std::string& id,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& data)
|
||||
const std::string& id,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& data)
|
||||
{
|
||||
raise(event,id,loc1,loc2,data);
|
||||
raise(event, id, loc1, loc2, data);
|
||||
return (*this)();
|
||||
}
|
||||
|
||||
void wml_event_pump::raise(const std::string& event,
|
||||
const std::string& id,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& data)
|
||||
const std::string& id,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& data)
|
||||
{
|
||||
if(resources::screen == nullptr)
|
||||
return;
|
||||
|
@ -493,27 +510,33 @@ void wml_event_pump::raise(const std::string& event,
|
|||
bool wml_event_pump::operator()()
|
||||
{
|
||||
// Quick aborts:
|
||||
if(resources::screen == nullptr)
|
||||
if(resources::screen == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(resources::lua_kernel != nullptr);
|
||||
if ( impl_->events_queue.empty() ) {
|
||||
if(impl_->events_queue.empty()) {
|
||||
DBG_EH << "Processing queued events, but none found.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(impl_->instance_count >= game_config::max_loop) {
|
||||
ERR_NG << "game_events pump waiting to process new events because "
|
||||
<< "recursion level would exceed maximum: " << game_config::max_loop << '\n';
|
||||
<< "recursion level would exceed maximum: " << game_config::max_loop << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!lg::debug().dont_log("event_handler")) {
|
||||
std::stringstream ss;
|
||||
for(const queued_event& ev : impl_->events_queue) {
|
||||
ss << "name=" << ev.name << ", " << "id=" << ev.id << "; ";
|
||||
ss << "name=" << ev.name << ", "
|
||||
<< "id=" << ev.id << "; ";
|
||||
}
|
||||
DBG_EH << "processing queued events: " << ss.str() << "\n";
|
||||
}
|
||||
|
||||
const size_t old_wml_track = impl_->internal_wml_tracking;
|
||||
|
||||
// Ensure the whiteboard doesn't attempt to build its future unit map
|
||||
// while events are being processed.
|
||||
wb::real_map real_unit_map;
|
||||
|
@ -521,15 +544,15 @@ bool wml_event_pump::operator()()
|
|||
pump_manager pump_instance(*impl_);
|
||||
context::scoped evc(impl_->contexts_, false);
|
||||
// Loop through the events we need to process.
|
||||
while ( !pump_instance.done() )
|
||||
{
|
||||
queued_event & ev = pump_instance.next();
|
||||
while(!pump_instance.done()) {
|
||||
queued_event& ev = pump_instance.next();
|
||||
|
||||
if( ev.name.empty() && ev.id.empty() )
|
||||
if(ev.name.empty() && ev.id.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& event_name = ev.name;
|
||||
const std::string& event_id = ev.id;
|
||||
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.
|
||||
|
@ -537,7 +560,7 @@ bool wml_event_pump::operator()()
|
|||
|
||||
{ // Block for context::scoped
|
||||
context::scoped inner_evc(impl_->contexts_, false);
|
||||
if ( resources::lua_kernel->run_event(ev) ) {
|
||||
if(resources::lua_kernel->run_event(ev)) {
|
||||
++impl_->internal_wml_tracking;
|
||||
}
|
||||
}
|
||||
|
@ -549,27 +572,22 @@ bool wml_event_pump::operator()()
|
|||
resources::gamedata->get_variable("x2") = ev.loc2.filter_loc().wml_x();
|
||||
resources::gamedata->get_variable("y2") = ev.loc2.filter_loc().wml_y();
|
||||
|
||||
if ( event_id.empty() ) {
|
||||
|
||||
if(event_id.empty()) {
|
||||
// Handle events of this name.
|
||||
impl_->my_manager->execute_on_events(event_name, [&](game_events::manager&, handler_ptr ptr) {
|
||||
DBG_EH << "processing event " << event_name << " with id="<<
|
||||
ptr->get_config()["id"] << "\n";
|
||||
DBG_EH << "processing event " << event_name << " with id=" << ptr->get_config()["id"] << "\n";
|
||||
|
||||
// Let this handler process our event.
|
||||
process_event(ptr, ev);
|
||||
|
||||
// NOTE: ptr may be null at this point!
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Get the handler directly via ID
|
||||
handler_ptr cur_handler = impl_->my_manager->get_event_handler_by_id(event_id);
|
||||
|
||||
//Get the handler directly via ID
|
||||
handler_ptr cur_handler = impl_->my_manager->get_event_handler_by_id( event_id );
|
||||
|
||||
if( cur_handler ) {
|
||||
DBG_EH << "processing event " << event_name << " with id="<<
|
||||
cur_handler->get_config()["id"] << "\n";
|
||||
if(cur_handler) {
|
||||
DBG_EH << "processing event " << event_name << " with id=" << cur_handler->get_config()["id"] << "\n";
|
||||
process_event(cur_handler, ev);
|
||||
}
|
||||
}
|
||||
|
@ -578,10 +596,11 @@ bool wml_event_pump::operator()()
|
|||
flush_messages();
|
||||
}
|
||||
|
||||
if ( old_wml_track != impl_->internal_wml_tracking )
|
||||
if(old_wml_track != impl_->internal_wml_tracking) {
|
||||
// Notify the whiteboard of any event.
|
||||
// This is used to track when moves, recruits, etc. happen.
|
||||
resources::whiteboard->on_gamestate_change();
|
||||
}
|
||||
|
||||
return context_mutated();
|
||||
}
|
||||
|
@ -589,13 +608,12 @@ bool wml_event_pump::operator()()
|
|||
void wml_event_pump::flush_messages()
|
||||
{
|
||||
// Dialogs can only be shown if the display is not locked
|
||||
if (resources::screen && !resources::screen->video().update_locked()) {
|
||||
if(resources::screen && !resources::screen->video().update_locked()) {
|
||||
show_wml_errors();
|
||||
show_wml_messages();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function can be used to detect when no WML/Lua has been executed.
|
||||
*
|
||||
|
@ -616,11 +634,13 @@ size_t wml_event_pump::wml_tracking()
|
|||
return impl_->internal_wml_tracking;
|
||||
}
|
||||
|
||||
wml_event_pump::wml_event_pump(manager & man)
|
||||
wml_event_pump::wml_event_pump(manager& man)
|
||||
: impl_(new pump_impl(man))
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
wml_event_pump::~wml_event_pump() {}
|
||||
wml_event_pump::~wml_event_pump()
|
||||
{
|
||||
}
|
||||
|
||||
} // end namespace game_events
|
||||
|
||||
|
|
|
@ -33,107 +33,125 @@
|
|||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class game_display;
|
||||
class vconfig;
|
||||
|
||||
namespace lg { class logger; }
|
||||
namespace lg
|
||||
{
|
||||
class logger;
|
||||
}
|
||||
|
||||
namespace game_events
|
||||
{
|
||||
struct queued_event {
|
||||
queued_event(const std::string& name, const std::string& id, const entity_location& loc1,
|
||||
const entity_location& loc2, const config& data)
|
||||
: name(name), id(id), loc1(loc1), loc2(loc2), data(data)
|
||||
{
|
||||
std::replace(this->name.begin(), this->name.end(), ' ', '_');
|
||||
}
|
||||
struct queued_event
|
||||
{
|
||||
queued_event(const std::string& name,
|
||||
const std::string& id,
|
||||
const entity_location& loc1,
|
||||
const entity_location& loc2,
|
||||
const config& 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;
|
||||
};
|
||||
std::string name;
|
||||
std::string id;
|
||||
entity_location loc1;
|
||||
entity_location loc2;
|
||||
config data;
|
||||
};
|
||||
|
||||
struct pump_impl;
|
||||
class manager;
|
||||
struct pump_impl;
|
||||
class manager;
|
||||
|
||||
class wml_event_pump {
|
||||
const std::unique_ptr<pump_impl> impl_;
|
||||
public:
|
||||
wml_event_pump(manager &);
|
||||
~wml_event_pump();
|
||||
/// Context: The general environment within which events are processed.
|
||||
/// Returns whether or not we believe WML might have changed something.
|
||||
bool context_mutated();
|
||||
/// Sets whether or not we believe WML might have changed something.
|
||||
void context_mutated(bool mutated);
|
||||
/// Returns whether or not we are skipping messages.
|
||||
bool context_skip_messages();
|
||||
/// Sets whether or not we are skipping messages.
|
||||
void context_skip_messages(bool skip);
|
||||
class wml_event_pump
|
||||
{
|
||||
const std::unique_ptr<pump_impl> impl_;
|
||||
|
||||
/// Helper function which determines whether a wml_message text can
|
||||
/// really be pushed into the wml_messages_stream, and does it.
|
||||
void put_wml_message(const std::string& logger, const std::string& message, bool in_chat);
|
||||
public:
|
||||
wml_event_pump(manager&);
|
||||
~wml_event_pump();
|
||||
|
||||
/**
|
||||
* Function to fire an event.
|
||||
*
|
||||
* Events may have up to two arguments, both of which must be locations.
|
||||
*/
|
||||
bool fire(const std::string& event,
|
||||
const entity_location& loc1=entity_location::null_entity,
|
||||
const entity_location& loc2=entity_location::null_entity,
|
||||
const config& data=config());
|
||||
/**
|
||||
* Context: The general environment within which events are processed.
|
||||
* Returns whether or not we believe WML might have changed something.
|
||||
*/
|
||||
bool context_mutated();
|
||||
|
||||
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());
|
||||
/** Sets whether or not we believe WML might have changed something. */
|
||||
void context_mutated(bool mutated);
|
||||
|
||||
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());
|
||||
/** Returns whether or not we are skipping messages. */
|
||||
bool context_skip_messages();
|
||||
|
||||
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);
|
||||
}
|
||||
/** Sets whether or not we are skipping messages. */
|
||||
void context_skip_messages(bool skip);
|
||||
|
||||
bool operator()();
|
||||
/*
|
||||
* Helper function which determines whether a wml_message text can
|
||||
* really be pushed into the wml_messages_stream, and does it.
|
||||
*/
|
||||
void put_wml_message(const std::string& logger, const std::string& message, bool in_chat);
|
||||
|
||||
/**
|
||||
* Flushes WML messages and errors.
|
||||
*/
|
||||
void flush_messages();
|
||||
/**
|
||||
* Function to fire an event.
|
||||
*
|
||||
* Events may have up to two arguments, both of which must be locations.
|
||||
*/
|
||||
bool fire(const std::string& event,
|
||||
const entity_location& loc1 = entity_location::null_entity,
|
||||
const entity_location& loc2 = entity_location::null_entity,
|
||||
const config& data = config());
|
||||
|
||||
/**
|
||||
* This function can be used to detect when no WML/Lua has been executed.
|
||||
*/
|
||||
size_t wml_tracking();
|
||||
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());
|
||||
|
||||
private:
|
||||
bool filter_event(const event_handler& handler, const queued_event& ev);
|
||||
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());
|
||||
|
||||
bool process_event(handler_ptr& handler_p, const queued_event& ev);
|
||||
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);
|
||||
}
|
||||
|
||||
void fill_wml_messages_map(std::map<std::string, int>& msg_map, std::stringstream& source);
|
||||
bool operator()();
|
||||
|
||||
void show_wml_messages(std::stringstream& source, const std::string & caption, bool to_cerr);
|
||||
/** Flushes WML messages and errors. */
|
||||
void flush_messages();
|
||||
|
||||
void show_wml_errors();
|
||||
/** This function can be used to detect when no WML/Lua has been executed. */
|
||||
size_t wml_tracking();
|
||||
|
||||
void show_wml_messages();
|
||||
private:
|
||||
bool filter_event(const event_handler& handler, const queued_event& ev);
|
||||
|
||||
void put_wml_message(lg::logger& logger, const std::string& prefix, const std::string& message, bool in_chat);
|
||||
};
|
||||
bool process_event(handler_ptr& handler_p, const queued_event& ev);
|
||||
|
||||
void fill_wml_messages_map(std::map<std::string, int>& msg_map, std::stringstream& source);
|
||||
|
||||
void show_wml_messages(std::stringstream& source, const std::string& caption, bool to_cerr);
|
||||
|
||||
void show_wml_errors();
|
||||
|
||||
void show_wml_messages();
|
||||
|
||||
void put_wml_message(lg::logger& logger, const std::string& prefix, const std::string& message, bool in_chat);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue