h1-mod/src/client/game/scripting/lua/event_handler.cpp

176 lines
3.5 KiB
C++
Raw Normal View History

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;
}
}