2022-03-01 22:14:41 +02:00
|
|
|
#include "std_include.hpp"
|
|
|
|
#include "context.hpp"
|
|
|
|
#include "error.hpp"
|
|
|
|
#include "value_conversion.hpp"
|
|
|
|
|
|
|
|
namespace scripting::lua
|
|
|
|
{
|
|
|
|
event_handler::event_handler(sol::state& state)
|
|
|
|
: state_(state)
|
|
|
|
{
|
|
|
|
auto event_listener_handle_type = state.new_usertype<event_listener_handle>("event_listener_handle");
|
|
|
|
|
|
|
|
event_listener_handle_type["clear"] = [this](const event_listener_handle& handle)
|
|
|
|
{
|
|
|
|
this->remove(handle);
|
|
|
|
};
|
|
|
|
|
|
|
|
event_listener_handle_type["endon"] = [this](const event_listener_handle& handle, const entity& entity, const std::string& event)
|
|
|
|
{
|
|
|
|
this->add_endon_condition(handle, entity, event);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::dispatch(const event& event)
|
|
|
|
{
|
|
|
|
bool has_built_arguments = false;
|
|
|
|
event_arguments arguments{};
|
|
|
|
|
|
|
|
callbacks_.access([&](task_list& tasks)
|
|
|
|
{
|
|
|
|
this->merge_callbacks();
|
|
|
|
this->handle_endon_conditions(event);
|
|
|
|
|
2022-03-13 23:40:22 +01:00
|
|
|
for (auto i = 0; i < tasks.size();)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
const auto task = tasks[i];
|
|
|
|
if (task.event != event.name || task.entity != event.entity)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
|
|
|
++i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-03-13 23:40:22 +01:00
|
|
|
if (!task.is_deleted)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
if (!has_built_arguments)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
|
|
|
has_built_arguments = true;
|
|
|
|
arguments = this->build_arguments(event);
|
|
|
|
}
|
|
|
|
|
2022-03-13 23:40:22 +01:00
|
|
|
handle_error(task.callback(sol::as_args(arguments)));
|
2022-03-01 22:14:41 +02:00
|
|
|
}
|
|
|
|
|
2022-03-13 23:40:22 +01:00
|
|
|
if (task.is_volatile || task.is_deleted)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
tasks.erase(tasks.begin() + i);
|
2022-03-01 22:14:41 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
event_listener_handle event_handler::add_event_listener(event_listener&& listener)
|
|
|
|
{
|
|
|
|
const uint64_t id = ++this->current_listener_id_;
|
|
|
|
listener.id = id;
|
|
|
|
listener.is_deleted = false;
|
|
|
|
|
|
|
|
new_callbacks_.access([&listener](task_list& tasks)
|
|
|
|
{
|
|
|
|
tasks.emplace_back(std::move(listener));
|
|
|
|
});
|
|
|
|
|
|
|
|
return {id};
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::add_endon_condition(const event_listener_handle& handle, const entity& entity,
|
|
|
|
const std::string& event)
|
|
|
|
{
|
|
|
|
auto merger = [&](task_list& tasks)
|
|
|
|
{
|
2022-03-13 23:11:49 +01:00
|
|
|
for (auto& task : tasks)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:11:49 +01:00
|
|
|
if (task.id == handle.id)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
|
|
|
task.endon_conditions.emplace_back(entity, event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
callbacks_.access([&](task_list& tasks)
|
|
|
|
{
|
|
|
|
merger(tasks);
|
|
|
|
new_callbacks_.access(merger);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::clear()
|
|
|
|
{
|
|
|
|
callbacks_.access([&](task_list& tasks)
|
|
|
|
{
|
|
|
|
new_callbacks_.access([&](task_list& new_tasks)
|
|
|
|
{
|
|
|
|
new_tasks.clear();
|
|
|
|
tasks.clear();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::remove(const event_listener_handle& handle)
|
|
|
|
{
|
|
|
|
auto mask_as_deleted = [&](task_list& tasks)
|
|
|
|
{
|
|
|
|
for (auto& task : tasks)
|
|
|
|
{
|
|
|
|
if (task.id == handle.id)
|
|
|
|
{
|
|
|
|
task.is_deleted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
callbacks_.access(mask_as_deleted);
|
|
|
|
new_callbacks_.access(mask_as_deleted);
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::merge_callbacks()
|
|
|
|
{
|
|
|
|
callbacks_.access([&](task_list& tasks)
|
|
|
|
{
|
|
|
|
new_callbacks_.access([&](task_list& new_tasks)
|
|
|
|
{
|
|
|
|
tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()),
|
|
|
|
std::move_iterator(new_tasks.end()));
|
|
|
|
new_tasks = {};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_handler::handle_endon_conditions(const event& event)
|
|
|
|
{
|
|
|
|
auto deleter = [&](task_list& tasks)
|
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
for (auto& task : tasks)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
for (auto& condition : task.endon_conditions)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
2022-03-13 23:40:22 +01:00
|
|
|
if (condition.first == event.entity && condition.second == event.name)
|
2022-03-01 22:14:41 +02:00
|
|
|
{
|
|
|
|
task.is_deleted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
callbacks_.access(deleter);
|
|
|
|
}
|
|
|
|
|
|
|
|
event_arguments event_handler::build_arguments(const event& event) const
|
|
|
|
{
|
|
|
|
event_arguments arguments;
|
|
|
|
|
|
|
|
for (const auto& argument : event.arguments)
|
|
|
|
{
|
|
|
|
arguments.emplace_back(convert(this->state_, argument));
|
|
|
|
}
|
|
|
|
|
|
|
|
return arguments;
|
|
|
|
}
|
|
|
|
}
|