diff options
Diffstat (limited to 'src')
19 files changed, 345 insertions, 298 deletions
diff --git a/src/common/Utilities/EventMap.cpp b/src/common/Utilities/EventMap.cpp index dcfe4686f6b..c3997634370 100644 --- a/src/common/Utilities/EventMap.cpp +++ b/src/common/Utilities/EventMap.cpp @@ -18,6 +18,10 @@ #include "EventMap.h" #include "Random.h" +EventMap::EventMap(EventMap const& other) = default; +EventMap& EventMap::operator=(EventMap const& other) = default; +EventMap::~EventMap() = default; + void EventMap::Reset() { _eventMap.clear(); @@ -41,7 +45,7 @@ void EventMap::ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group /*= if (phase && phase <= 8) eventId |= (1 << (phase + 23)); - _eventMap.insert(EventStore::value_type(_time + time, eventId)); + _eventMap.insert({ _time + time, eventId }); } void EventMap::ScheduleEvent(uint32 eventId, Milliseconds minTime, Milliseconds maxTime, uint32 group /*= 0*/, uint8 phase /*= 0*/) @@ -102,7 +106,7 @@ void EventMap::DelayEvents(Milliseconds delay) for (EventStore::iterator itr = delayed.begin(); itr != delayed.end();) { EventStore::node_type node = delayed.extract(itr++); - node.key() = node.key() + delay; + node.key() += delay; _eventMap.insert(_eventMap.end(), std::move(node)); } } @@ -113,19 +117,19 @@ void EventMap::DelayEvents(Milliseconds delay, uint32 group) return; EventStore delayed; - for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { if (itr->second & (1 << (group + 15))) { - delayed.insert(EventStore::value_type(itr->first + delay, itr->second)); - _eventMap.erase(itr++); + EventStore::node_type node = _eventMap.extract(itr++); + node.key() += delay; + delayed.insert(delayed.end(), std::move(node)); } else ++itr; } - _eventMap.insert(delayed.begin(), delayed.end()); + _eventMap.merge(delayed); } void EventMap::CancelEvent(uint32 eventId) @@ -187,33 +191,32 @@ void EventMap::ScheduleNextFromSeries(uint32 eventData) if (itr == _timerSeries.end()) return; - if (itr->first != eventData) - return; + ScheduleEvent(eventData, itr->second.front()); - if (itr->second.size() == 0) - return; - - Milliseconds time = itr->second.front(); - itr->second.pop(); - - ScheduleEvent(eventData, time); + if (itr->second.size() > 1) + itr->second.erase(itr->second.begin()); + else + _timerSeries.erase(itr); } -void EventMap::ScheduleEventSeries(uint32 eventId, uint8 group, uint8 phase, std::initializer_list<Milliseconds> const& timeSeries) +void EventMap::ScheduleEventSeries(uint32 eventId, uint8 group, uint8 phase, std::initializer_list<Milliseconds> timeSeries) { + if (!timeSeries.size()) + return; + if (group && group <= 8) eventId |= (1 << (group + 15)); if (phase && phase <= 8) eventId |= (1 << (phase + 23)); - for (Milliseconds const& time : timeSeries) - _timerSeries[eventId].push(time); + std::vector<Milliseconds>& series = _timerSeries[eventId]; + series.insert(series.end(), timeSeries.begin(), timeSeries.end()); ScheduleNextFromSeries(eventId); } -void EventMap::ScheduleEventSeries(uint32 eventId, std::initializer_list<Milliseconds> const& timeSeries) +void EventMap::ScheduleEventSeries(uint32 eventId, std::initializer_list<Milliseconds> timeSeries) { ScheduleEventSeries(eventId, 0, 0, timeSeries); } diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h index 82c466408cd..7d8c006e3bf 100644 --- a/src/common/Utilities/EventMap.h +++ b/src/common/Utilities/EventMap.h @@ -21,7 +21,7 @@ #include "Define.h" #include "Duration.h" #include <map> -#include <queue> +#include <vector> class TC_COMMON_API EventMap { @@ -37,10 +37,15 @@ class TC_COMMON_API EventMap * - Pattern: 0xPPGGEEEE */ typedef std::multimap<TimePoint, uint32> EventStore; - typedef std::map<uint32 /*event data*/, std::queue<Milliseconds>> EventSeriesStore; + typedef std::map<uint32 /*event data*/, std::vector<Milliseconds>> EventSeriesStore; public: EventMap() : _time(TimePoint::min()), _phase(0), _lastEvent(0) { } + EventMap(EventMap const& other); + EventMap(EventMap&& other) noexcept = default; + EventMap& operator=(EventMap const& other); + EventMap& operator=(EventMap&& other) noexcept = default; + ~EventMap(); /** * @name Reset @@ -242,7 +247,7 @@ public: * @param phase of the event. * @param timeSeries specifying the times the event should be automatically scheduled after each trigger (first value is initial schedule) */ - void ScheduleEventSeries(uint32 eventId, uint8 group, uint8 phase, std::initializer_list<Milliseconds> const& timeSeries); + void ScheduleEventSeries(uint32 eventId, uint8 group, uint8 phase, std::initializer_list<Milliseconds> timeSeries); /** * @name ScheduleEventSeries @@ -250,7 +255,7 @@ public: * @param eventId of the event. * @param timeSeries specifying the times the event should be automatically scheduled after each trigger (first value is initial schedule) */ - void ScheduleEventSeries(uint32 eventId, std::initializer_list<Milliseconds> const& series); + void ScheduleEventSeries(uint32 eventId, std::initializer_list<Milliseconds> series); private: /** diff --git a/src/common/Utilities/TaskScheduler.cpp b/src/common/Utilities/TaskScheduler.cpp index 60eb9284713..4ee9451b846 100644 --- a/src/common/Utilities/TaskScheduler.cpp +++ b/src/common/Utilities/TaskScheduler.cpp @@ -18,6 +18,15 @@ #include "TaskScheduler.h" #include "Errors.h" +TaskScheduler::TaskScheduler() + : self_reference(this, [](TaskScheduler const*) { }), + _now(clock_t::now()), + _predicate(EmptyValidator) +{ +} + +TaskScheduler::~TaskScheduler() = default; + TaskScheduler& TaskScheduler::ClearValidator() { _predicate = EmptyValidator; @@ -36,6 +45,13 @@ TaskScheduler& TaskScheduler::Update(size_t milliseconds, success_t const& callb return Update(std::chrono::milliseconds(milliseconds), callback); } +TaskScheduler& TaskScheduler::Update(duration_t difftime, success_t const& callback/* = nullptr*/) +{ + _now += difftime; + Dispatch(callback); + return *this; +} + TaskScheduler& TaskScheduler::Async(std::function<void()> callable) { _asyncHolder.emplace(std::move(callable)); @@ -67,12 +83,75 @@ TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups) return *this; } +TaskScheduler& TaskScheduler::DelayAll(duration_t duration) +{ + _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool + { + task->_end += duration; + return true; + }); + return *this; +} + +TaskScheduler& TaskScheduler::DelayGroup(group_t const group, duration_t duration) +{ + _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end += duration; + return true; + } + else + return false; + }); + return *this; +} + +TaskScheduler& TaskScheduler::RescheduleAll(duration_t duration) +{ + auto const end = _now + duration; + _task_holder.ModifyIf([end](TaskContainer const& task) -> bool + { + task->_end = end; + return true; + }); + return *this; +} + +TaskScheduler& TaskScheduler::RescheduleGroup(group_t const group, duration_t duration) +{ + auto const end = _now + duration; + _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end = end; + return true; + } + else + return false; + }); + return *this; +} + TaskScheduler& TaskScheduler::InsertTask(TaskContainer task) { _task_holder.Push(std::move(task)); return *this; } +TaskScheduler& TaskScheduler::ScheduleAt(timepoint_t end, duration_t time, task_handler_t task) +{ + return InsertTask(TaskContainer(new Task(end + time, time, std::move(task)))); +} + +TaskScheduler& TaskScheduler::ScheduleAt(timepoint_t end, duration_t time, group_t const group, task_handler_t task) +{ + static constexpr repeated_t DEFAULT_REPEATED = 0; + return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, std::move(task)))); +} + void TaskScheduler::Dispatch(success_t const& callback/* = nullptr*/) { // If the validation failed abort the dispatching here. @@ -198,6 +277,21 @@ TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const return _task->_repeated; } +TaskContext& TaskContext::Repeat(TaskScheduler::duration_t duration) +{ + AssertOnConsumed(); + + // Set new duration, in-context timing and increment repeat counter + _task->_duration = duration; + _task->_end += duration; + _task->_repeated += 1; + (*_consumed) = true; + return this->Dispatch([this](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.InsertTask(_task); + }); +} + TaskContext& TaskContext::Async(std::function<void()> const& callable) { return Dispatch([&](TaskScheduler& scheduler) -> TaskScheduler& @@ -206,6 +300,24 @@ TaskContext& TaskContext::Async(std::function<void()> const& callable) }); } +TaskContext& TaskContext::Schedule(TaskScheduler::duration_t time, TaskScheduler::task_handler_t task) +{ + auto const end = _task->_end; + return this->Dispatch([end, time, task = std::move(task)](TaskScheduler& scheduler) mutable -> TaskScheduler& + { + return scheduler.ScheduleAt(end, time, std::move(task)); + }); +} + +TaskContext& TaskContext::Schedule(TaskScheduler::duration_t time, TaskScheduler::group_t const group, TaskScheduler::task_handler_t task) +{ + auto const end = _task->_end; + return this->Dispatch([end, time, group, task = std::move(task)](TaskScheduler& scheduler) mutable -> TaskScheduler& + { + return scheduler.ScheduleAt(end, time, group, std::move(task)); + }); +} + TaskContext& TaskContext::CancelAll() { return Dispatch(&TaskScheduler::CancelAll); @@ -227,6 +339,38 @@ TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> con }); } +TaskContext& TaskContext::DelayAll(TaskScheduler::duration_t duration) +{ + return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.DelayAll(duration); + }); +} + +TaskContext& TaskContext::DelayGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration) +{ + return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.DelayGroup(group, duration); + }); +} + +TaskContext& TaskContext::RescheduleAll(TaskScheduler::duration_t duration) +{ + return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.RescheduleAll(duration); + }); +} + +TaskContext& TaskContext::RescheduleGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration) +{ + return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.RescheduleGroup(group, duration); + }); +} + void TaskContext::AssertOnConsumed() const { // This was adapted to TC to prevent static analysis tools from complaining. diff --git a/src/common/Utilities/TaskScheduler.h b/src/common/Utilities/TaskScheduler.h index 2ebd3e57b37..c9029a002db 100644 --- a/src/common/Utilities/TaskScheduler.h +++ b/src/common/Utilities/TaskScheduler.h @@ -171,11 +171,10 @@ class TC_COMMON_API TaskScheduler } public: - TaskScheduler() - : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(EmptyValidator) { } + TaskScheduler(); template<typename P> - TaskScheduler(P&& predicate) + explicit TaskScheduler(P&& predicate) : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(std::forward<P>(predicate)) { } TaskScheduler(TaskScheduler const&) = delete; @@ -183,7 +182,7 @@ public: TaskScheduler& operator= (TaskScheduler const&) = delete; TaskScheduler& operator= (TaskScheduler&&) = delete; - ~TaskScheduler() = default; + ~TaskScheduler(); /// Sets a validator which is asked if tasks are allowed to be executed. template<typename P> @@ -206,14 +205,7 @@ public: /// Update the scheduler with a difftime. /// Calls the optional callback on successfully finish. - template<class Rep, class Period> - TaskScheduler& Update(std::chrono::duration<Rep, Period> difftime, - success_t const& callback = nullptr) - { - _now += difftime; - Dispatch(callback); - return *this; - } + TaskScheduler& Update(duration_t difftime, success_t const& callback = nullptr); /// Schedule an callable function that is executed at the next update tick. /// Its safe to modify the TaskScheduler from within the callable. @@ -221,8 +213,7 @@ public: /// Schedule an event with a fixed rate. /// Never call this from within a task context! Use TaskContext::Schedule instead! - template<class Rep, class Period> - TaskScheduler& Schedule(std::chrono::duration<Rep, Period> time, + TaskScheduler& Schedule(duration_t time, task_handler_t task) { return this->ScheduleAt(_now, time, std::move(task)); @@ -230,8 +221,7 @@ public: /// Schedule an event with a fixed rate. /// Never call this from within a task context! Use TaskContext::Schedule instead! - template<class Rep, class Period> - TaskScheduler& Schedule(std::chrono::duration<Rep, Period> time, + TaskScheduler& Schedule(duration_t time, group_t const group, task_handler_t task) { return this->ScheduleAt(_now, time, group, std::move(task)); @@ -239,18 +229,16 @@ public: /// Schedule an event with a randomized rate between min and max rate. /// Never call this from within a task context! Use TaskContext::Schedule instead! - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskScheduler& Schedule(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max, task_handler_t task) + TaskScheduler& Schedule(std::chrono::milliseconds min, + std::chrono::milliseconds max, task_handler_t task) { return this->Schedule(::randtime(min, max), std::move(task)); } /// Schedule an event with a fixed rate. /// Never call this from within a task context! Use TaskContext::Schedule instead! - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskScheduler& Schedule(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max, group_t const group, + TaskScheduler& Schedule(std::chrono::milliseconds min, + std::chrono::milliseconds max, group_t const group, task_handler_t task) { return this->Schedule(::randtime(min, max), group, std::move(task)); @@ -269,95 +257,42 @@ public: TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups); /// Delays all tasks with the given duration. - template<class Rep, class Period> - TaskScheduler& DelayAll(std::chrono::duration<Rep, Period> duration) - { - _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool - { - task->_end += duration; - return true; - }); - return *this; - } + TaskScheduler& DelayAll(duration_t duration); /// Delays all tasks with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskScheduler& DelayAll(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + TaskScheduler& DelayAll(std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->DelayAll(::randtime(min, max)); } /// Delays all tasks of a group with the given duration. - template<class Rep, class Period> - TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<Rep, Period> duration) - { - _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool - { - if (task->IsInGroup(group)) - { - task->_end += duration; - return true; - } - else - return false; - }); - return *this; - } + TaskScheduler& DelayGroup(group_t const group, duration_t duration); /// Delays all tasks of a group with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> TaskScheduler& DelayGroup(group_t const group, - std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->DelayGroup(group, ::randtime(min, max)); } /// Reschedule all tasks with a given duration. - template<class Rep, class Period> - TaskScheduler& RescheduleAll(std::chrono::duration<Rep, Period> duration) - { - auto const end = _now + duration; - _task_holder.ModifyIf([end](TaskContainer const& task) -> bool - { - task->_end = end; - return true; - }); - return *this; - } + TaskScheduler& RescheduleAll(duration_t duration); /// Reschedule all tasks with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskScheduler& RescheduleAll(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + TaskScheduler& RescheduleAll(std::chrono::milliseconds min, std::chrono::milliseconds max) { return this->RescheduleAll(::randtime(min, max)); } /// Reschedule all tasks of a group with the given duration. - template<class Rep, class Period> - TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<Rep, Period> duration) - { - auto const end = _now + duration; - _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool - { - if (task->IsInGroup(group)) - { - task->_end = end; - return true; - } - else - return false; - }); - return *this; - } + TaskScheduler& RescheduleGroup(group_t const group, duration_t duration); /// Reschedule all tasks of a group with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> TaskScheduler& RescheduleGroup(group_t const group, - std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->RescheduleGroup(group, ::randtime(min, max)); } @@ -366,23 +301,14 @@ private: /// Insert a new task to the enqueued tasks. TaskScheduler& InsertTask(TaskContainer task); - template<class Rep, class Period> TaskScheduler& ScheduleAt(timepoint_t end, - std::chrono::duration<Rep, Period> time, task_handler_t task) - { - return InsertTask(TaskContainer(new Task(end + time, time, std::move(task)))); - } + duration_t time, task_handler_t task); /// Schedule an event with a fixed rate. /// Never call this from within a task context! Use TaskContext::schedule instead! - template<class Rep, class Period> TaskScheduler& ScheduleAt(timepoint_t end, - std::chrono::duration<Rep, Period> time, - group_t const group, task_handler_t task) - { - static constexpr repeated_t DEFAULT_REPEATED = 0; - return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, std::move(task)))); - } + duration_t time, + group_t const group, task_handler_t task); /// Dispatch remaining tasks void Dispatch(success_t const& callback); @@ -414,36 +340,16 @@ public: : _task(std::move(task)), _owner(std::move(owner)), _consumed(std::make_shared<bool>(false)) { } // Copy construct - TaskContext(TaskContext const& right) - : _task(right._task), _owner(right._owner), _consumed(right._consumed) { } + TaskContext(TaskContext const& right) = default; // Move construct - TaskContext(TaskContext&& right) noexcept - : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { } + TaskContext(TaskContext&& right) noexcept = default; // Copy assign - TaskContext& operator=(TaskContext const& right) - { - if (this != &right) - { - _task = right._task; - _owner = right._owner; - _consumed = right._consumed; - } - return *this; - } + TaskContext& operator=(TaskContext const& right) = default; // Move assign - TaskContext& operator=(TaskContext&& right) noexcept - { - if (this != &right) - { - _task = std::move(right._task); - _owner = std::move(right._owner); - _consumed = std::move(right._consumed); - } - return *this; - } + TaskContext& operator=(TaskContext&& right) noexcept = default; ~TaskContext() = default; @@ -466,21 +372,7 @@ public: /// std::chrono::seconds(5) for example. /// This will consume the task context, its not possible to repeat the task again /// from the same task context! - template<class Rep, class Period> - TaskContext& Repeat(std::chrono::duration<Rep, Period> duration) - { - AssertOnConsumed(); - - // Set new duration, in-context timing and increment repeat counter - _task->_duration = duration; - _task->_end += duration; - _task->_repeated += 1; - (*_consumed) = true; - return this->Dispatch([this](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.InsertTask(_task); - }); - } + TaskContext& Repeat(TaskScheduler::duration_t duration); /// Repeats the event with the same duration. /// This will consume the task context, its not possible to repeat the task again @@ -494,9 +386,8 @@ public: /// std::chrono::seconds(5) for example. /// This will consume the task context, its not possible to repeat the task again /// from the same task context! - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskContext& Repeat(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + TaskContext& Repeat(std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->Repeat(::randtime(min, max)); } @@ -509,39 +400,22 @@ public: /// Its possible that the new event is executed immediately! /// Use TaskScheduler::Async to create a task /// which will be called at the next update tick. - template<class Rep, class Period> - TaskContext& Schedule(std::chrono::duration<Rep, Period> time, - TaskScheduler::task_handler_t task) - { - auto const end = _task->_end; - return this->Dispatch([end, time, task = std::move(task)](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.ScheduleAt<Rep, Period>(end, time, std::move(task)); - }); - } + TaskContext& Schedule(TaskScheduler::duration_t time, + TaskScheduler::task_handler_t task); /// Schedule an event with a fixed rate from within the context. /// Its possible that the new event is executed immediately! /// Use TaskScheduler::Async to create a task /// which will be called at the next update tick. - template<class Rep, class Period> - TaskContext& Schedule(std::chrono::duration<Rep, Period> time, - TaskScheduler::group_t const group, TaskScheduler::task_handler_t task) - { - auto const end = _task->_end; - return this->Dispatch([end, time, group, task = std::move(task)](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.ScheduleAt<Rep, Period>(end, time, group, std::move(task)); - }); - } + TaskContext& Schedule(TaskScheduler::duration_t time, + TaskScheduler::group_t const group, TaskScheduler::task_handler_t task); /// Schedule an event with a randomized rate between min and max rate from within the context. /// Its possible that the new event is executed immediately! /// Use TaskScheduler::Async to create a task /// which will be called at the next update tick. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskContext& Schedule(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max, TaskScheduler::task_handler_t task) + TaskContext& Schedule(std::chrono::milliseconds min, + std::chrono::milliseconds max, TaskScheduler::task_handler_t task) { return this->Schedule(::randtime(min, max), std::move(task)); } @@ -550,9 +424,8 @@ public: /// Its possible that the new event is executed immediately! /// Use TaskScheduler::Async to create a task /// which will be called at the next update tick. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskContext& Schedule(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max, TaskScheduler::group_t const group, + TaskContext& Schedule(std::chrono::milliseconds min, + std::chrono::milliseconds max, TaskScheduler::group_t const group, TaskScheduler::task_handler_t task) { return this->Schedule(::randtime(min, max), group, std::move(task)); @@ -569,75 +442,43 @@ public: TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups); /// Delays all tasks with the given duration from within the context. - template<class Rep, class Period> - TaskContext& DelayAll(std::chrono::duration<Rep, Period> duration) - { - return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.DelayAll(duration); - }); - } + TaskContext& DelayAll(TaskScheduler::duration_t duration); /// Delays all tasks with a random duration between min and max from within the context. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskContext& DelayAll(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + TaskContext& DelayAll(std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->DelayAll(::randtime(min, max)); } /// Delays all tasks of a group with the given duration from within the context. - template<class Rep, class Period> - TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<Rep, Period> duration) - { - return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.DelayGroup(group, duration); - }); - } + TaskContext& DelayGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration); /// Delays all tasks of a group with a random duration between min and max from within the context. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> TaskContext& DelayGroup(TaskScheduler::group_t const group, - std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->DelayGroup(group, ::randtime(min, max)); } /// Reschedule all tasks with the given duration. - template<class Rep, class Period> - TaskContext& RescheduleAll(std::chrono::duration<Rep, Period> duration) - { - return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.RescheduleAll(duration); - }); - } + TaskContext& RescheduleAll(TaskScheduler::duration_t duration); /// Reschedule all tasks with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> - TaskContext& RescheduleAll(std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + TaskContext& RescheduleAll(std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->RescheduleAll(::randtime(min, max)); } /// Reschedule all tasks of a group with the given duration. - template<class Rep, class Period> - TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<Rep, Period> duration) - { - return this->Dispatch([=](TaskScheduler& scheduler) -> TaskScheduler& - { - return scheduler.RescheduleGroup(group, duration); - }); - } + TaskContext& RescheduleGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration); /// Reschedule all tasks of a group with a random duration between min and max. - template<class RepLeft, class PeriodLeft, class RepRight, class PeriodRight> TaskContext& RescheduleGroup(TaskScheduler::group_t const group, - std::chrono::duration<RepLeft, PeriodLeft> min, - std::chrono::duration<RepRight, PeriodRight> max) + std::chrono::milliseconds min, + std::chrono::milliseconds max) { return this->RescheduleGroup(group, ::randtime(min, max)); } diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index a16e6ba0e89..dd233a9266d 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -482,7 +482,7 @@ TC_COMMON_API void StringReplaceAll(std::string* str, std::string_view text, std // simple class for not-modifyable list template <typename T> -class HookList final +class HookList { private: typedef std::vector<T> ContainerType; @@ -495,7 +495,7 @@ class HookList final HookList<T>& operator+=(T&& t) { - _container.push_back(std::move(t)); + _container.emplace_back(std::move(t)); return *this; } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index e016c30289b..1c950a6b203 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -124,7 +124,7 @@ void SummonList::DoActionImpl(int32 action, StorageType& summons, uint16 max) ScriptedAI::ScriptedAI(Creature* creature) : ScriptedAI(creature, creature->GetScriptId()) { } -ScriptedAI::ScriptedAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), IsFleeing(false), _isCombatMovementAllowed(true) +ScriptedAI::ScriptedAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), _isCombatMovementAllowed(true) { _difficulty = me->GetMap()->GetDifficultyID(); } @@ -538,6 +538,8 @@ BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature), instan }); } +BossAI::~BossAI() = default; + void BossAI::_Reset() { if (!me->IsAlive()) @@ -657,6 +659,8 @@ void BossAI::_DespawnAtEvade(Seconds delayToRespawn /*= 30s*/, Creature* who /*= // WorldBossAI - for non-instanced bosses WorldBossAI::WorldBossAI(Creature* creature) : ScriptedAI(creature), summons(creature) { } +WorldBossAI::~WorldBossAI() = default; + void WorldBossAI::_Reset() { if (!me->IsAlive()) diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index a52b33b0dcc..456a2569932 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -150,9 +150,6 @@ struct TC_GAME_API ScriptedAI : public CreatureAI // Variables // ************* - // For fleeing - bool IsFleeing; - // ************* // Pure virtual functions // ************* @@ -312,7 +309,7 @@ class TC_GAME_API BossAI : public ScriptedAI { public: BossAI(Creature* creature, uint32 bossId); - virtual ~BossAI() { } + virtual ~BossAI(); InstanceScript* const instance; @@ -359,7 +356,7 @@ class TC_GAME_API WorldBossAI : public ScriptedAI { public: WorldBossAI(Creature* creature); - virtual ~WorldBossAI() { } + virtual ~WorldBossAI(); void JustSummoned(Creature* summon) override; void SummonedCreatureDespawn(Creature* summon) override; diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 40c08e742f7..a24e0a9b91f 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -159,6 +159,11 @@ void InstanceScript::SetHeaders(std::string const& dataHeaders) headers = dataHeaders; } +void InstanceScript::SetBossNumber(uint32 number) +{ + bosses.resize(number); +} + void InstanceScript::LoadBossBoundaries(BossBoundaryData const& data) { for (BossBoundaryEntry const& entry : data) diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 618600815ae..2ac6c0da04f 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -322,7 +322,7 @@ class TC_GAME_API InstanceScript : public ZoneScript protected: void SetHeaders(std::string const& dataHeaders); - void SetBossNumber(uint32 number) { bosses.resize(number); } + void SetBossNumber(uint32 number); void LoadBossBoundaries(BossBoundaryData const& data); void LoadDoorData(DoorData const* data); void LoadMinionData(MinionData const* data); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index d541c5f0a46..5314223ea8d 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -102,6 +102,13 @@ std::string_view SpellScriptBase::GetScriptName() const return m_scriptName; } +template <typename T> +SpellScriptBase::HookList<T>& SpellScriptBase::HookList<T>::operator+=(T&& t) +{ + ::HookList<T>::operator+=(std::move(t)); + return *this; +} + SpellScriptBase::EffectHook::EffectHook(uint8 effIndex) { // effect index must be in range <0;2>, allow use of special effindexes @@ -248,6 +255,19 @@ bool SpellScript::TargetHook::CheckEffect(SpellInfo const* spellInfo, uint8 effI return false; } +template TC_GAME_API SpellScriptBase::HookList<SpellScript::CastHandler>& SpellScriptBase::HookList<SpellScript::CastHandler>::operator+=(SpellScript::CastHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::CheckCastHandler>& SpellScriptBase::HookList<SpellScript::CheckCastHandler>::operator+=(SpellScript::CheckCastHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::EffectHandler>& SpellScriptBase::HookList<SpellScript::EffectHandler>::operator+=(SpellScript::EffectHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::BeforeHitHandler>& SpellScriptBase::HookList<SpellScript::BeforeHitHandler>::operator+=(SpellScript::BeforeHitHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::HitHandler>& SpellScriptBase::HookList<SpellScript::HitHandler>::operator+=(SpellScript::HitHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::OnCalcCritChanceHandler>& SpellScriptBase::HookList<SpellScript::OnCalcCritChanceHandler>::operator+=(SpellScript::OnCalcCritChanceHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::ObjectAreaTargetSelectHandler>& SpellScriptBase::HookList<SpellScript::ObjectAreaTargetSelectHandler>::operator+=(SpellScript::ObjectAreaTargetSelectHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::ObjectTargetSelectHandler>& SpellScriptBase::HookList<SpellScript::ObjectTargetSelectHandler>::operator+=(SpellScript::ObjectTargetSelectHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::DestinationTargetSelectHandler>& SpellScriptBase::HookList<SpellScript::DestinationTargetSelectHandler>::operator+=(SpellScript::DestinationTargetSelectHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::DamageAndHealingCalcHandler>& SpellScriptBase::HookList<SpellScript::DamageAndHealingCalcHandler>::operator+=(SpellScript::DamageAndHealingCalcHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::OnCalculateResistAbsorbHandler>& SpellScriptBase::HookList<SpellScript::OnCalculateResistAbsorbHandler>::operator+=(SpellScript::OnCalculateResistAbsorbHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<SpellScript::EmpowerStageCompletedHandler>& SpellScriptBase::HookList<SpellScript::EmpowerStageCompletedHandler>::operator+=(SpellScript::EmpowerStageCompletedHandler&& hook); + SpellScript::SpellScript(): m_spell(nullptr), m_hitPreventEffectMask(0), m_hitPreventDefaultEffectMask(0) { } @@ -770,6 +790,25 @@ Difficulty SpellScript::GetCastDifficulty() const return m_spell->GetCastDifficulty(); } +template TC_GAME_API SpellScriptBase::HookList<AuraScript::CheckAreaTargetHandler>& SpellScriptBase::HookList<AuraScript::CheckAreaTargetHandler>::operator+=(AuraScript::CheckAreaTargetHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::AuraDispelHandler>& SpellScriptBase::HookList<AuraScript::AuraDispelHandler>::operator+=(AuraScript::AuraDispelHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::AuraHeartbeatHandler>& SpellScriptBase::HookList<AuraScript::AuraHeartbeatHandler>::operator+=(AuraScript::AuraHeartbeatHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectApplyHandler>& SpellScriptBase::HookList<AuraScript::EffectApplyHandler>::operator+=(AuraScript::EffectApplyHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectPeriodicHandler>& SpellScriptBase::HookList<AuraScript::EffectPeriodicHandler>::operator+=(AuraScript::EffectPeriodicHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectUpdatePeriodicHandler>& SpellScriptBase::HookList<AuraScript::EffectUpdatePeriodicHandler>::operator+=(AuraScript::EffectUpdatePeriodicHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectCalcAmountHandler>& SpellScriptBase::HookList<AuraScript::EffectCalcAmountHandler>::operator+=(AuraScript::EffectCalcAmountHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectCalcPeriodicHandler>& SpellScriptBase::HookList<AuraScript::EffectCalcPeriodicHandler>::operator+=(AuraScript::EffectCalcPeriodicHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectCalcSpellModHandler>& SpellScriptBase::HookList<AuraScript::EffectCalcSpellModHandler>::operator+=(AuraScript::EffectCalcSpellModHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectCalcCritChanceHandler>& SpellScriptBase::HookList<AuraScript::EffectCalcCritChanceHandler>::operator+=(AuraScript::EffectCalcCritChanceHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectCalcDamageAndHealingHandler>& SpellScriptBase::HookList<AuraScript::EffectCalcDamageAndHealingHandler>::operator+=(AuraScript::EffectCalcDamageAndHealingHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectAbsorbHandler>& SpellScriptBase::HookList<AuraScript::EffectAbsorbHandler>::operator+=(AuraScript::EffectAbsorbHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectAbsorbHealHandler>& SpellScriptBase::HookList<AuraScript::EffectAbsorbHealHandler>::operator+=(AuraScript::EffectAbsorbHealHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::CheckProcHandler>& SpellScriptBase::HookList<AuraScript::CheckProcHandler>::operator+=(AuraScript::CheckProcHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::CheckEffectProcHandler>& SpellScriptBase::HookList<AuraScript::CheckEffectProcHandler>::operator+=(AuraScript::CheckEffectProcHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::AuraProcHandler>& SpellScriptBase::HookList<AuraScript::AuraProcHandler>::operator+=(AuraScript::AuraProcHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EffectProcHandler>& SpellScriptBase::HookList<AuraScript::EffectProcHandler>::operator+=(AuraScript::EffectProcHandler&& hook); +template TC_GAME_API SpellScriptBase::HookList<AuraScript::EnterLeaveCombatHandler>& SpellScriptBase::HookList<AuraScript::EnterLeaveCombatHandler>::operator+=(AuraScript::EnterLeaveCombatHandler&& hook); + bool AuraScript::_Validate(SpellInfo const* entry) { for (auto itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 22b54191244..5857d63fb08 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -89,6 +89,14 @@ public: protected: virtual bool _Validate(SpellInfo const* entry); + // compile barrier to avoid instantiating operator+= in every script file + template <typename T> + class HookList : public ::HookList<T> + { + public: + HookList& operator+=(T&& t); + }; + class TC_GAME_API EffectHook { public: diff --git a/src/server/scripts/Battlegrounds/DeephaulRavine/battleground_deephaul_ravine.cpp b/src/server/scripts/Battlegrounds/DeephaulRavine/battleground_deephaul_ravine.cpp index 663a6170963..8be231534ab 100644 --- a/src/server/scripts/Battlegrounds/DeephaulRavine/battleground_deephaul_ravine.cpp +++ b/src/server/scripts/Battlegrounds/DeephaulRavine/battleground_deephaul_ravine.cpp @@ -743,7 +743,8 @@ struct battleground_deephaul_ravine : BattlegroundScript return false; } - void DoForLeaders(std::function<void(Creature*)> const& fn) const + template <std::invocable<Creature*> Action> + void DoForLeaders(Action const& fn) const { for (ObjectGuid const& guid : _leaderGUIDs) if (Creature* creature = battlegroundMap->GetCreature(guid)) diff --git a/src/server/scripts/Battlegrounds/EyeOfTheStorm/battleground_eye_of_the_storm.cpp b/src/server/scripts/Battlegrounds/EyeOfTheStorm/battleground_eye_of_the_storm.cpp index 3c8ef48438e..107b003fe78 100644 --- a/src/server/scripts/Battlegrounds/EyeOfTheStorm/battleground_eye_of_the_storm.cpp +++ b/src/server/scripts/Battlegrounds/EyeOfTheStorm/battleground_eye_of_the_storm.cpp @@ -367,7 +367,8 @@ struct battleground_eye_of_the_storm : BattlegroundScript return baseCount; } - void DoForFlagKeepers(std::function<void(Player*)> const& action) const + template <std::invocable<Player*> Action> + void DoForFlagKeepers(Action const& action) const { if (GameObject const* flag = battlegroundMap->GetGameObject(_flagGUID)) if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID())) diff --git a/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp b/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp index 5d55df8d6b7..fb48e239129 100644 --- a/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp +++ b/src/server/scripts/Battlegrounds/IsleOfConquest/battleground_isle_of_conquest.cpp @@ -339,7 +339,7 @@ struct battleground_isle_of_conquest : BattlegroundScript { BattlegroundScript::OnStart(); - auto gameobjectAction = [&](GuidVector const& guids, std::function<void(GameObject*)> const& action) -> void + auto gameobjectAction = [&]<std::invocable<GameObject*> Action>(GuidVector const& guids, Action const& action) -> void { for (ObjectGuid const& guid : guids) if (GameObject* gameObject = battlegroundMap->GetGameObject(guid)) diff --git a/src/server/scripts/Battlegrounds/SilvershardMines/battleground_silvershard_mines.cpp b/src/server/scripts/Battlegrounds/SilvershardMines/battleground_silvershard_mines.cpp index 30721e47425..e23de84bab0 100644 --- a/src/server/scripts/Battlegrounds/SilvershardMines/battleground_silvershard_mines.cpp +++ b/src/server/scripts/Battlegrounds/SilvershardMines/battleground_silvershard_mines.cpp @@ -715,7 +715,8 @@ public: } } - void DoForPlayersInControlZone(std::function<void(GameObject const*, Player*)> const& fn) const + template <std::invocable<GameObject const*, Player*> Action> + void DoForPlayersInControlZone(Action const& fn) const { if (GameObject const* controlZone = GetControlZone()) for (ObjectGuid const& playerGuid : *controlZone->GetInsidePlayers()) diff --git a/src/server/scripts/Battlegrounds/TwinPeaks/battleground_twin_peaks.cpp b/src/server/scripts/Battlegrounds/TwinPeaks/battleground_twin_peaks.cpp index 0a0b37e4a16..f71cf0e5017 100644 --- a/src/server/scripts/Battlegrounds/TwinPeaks/battleground_twin_peaks.cpp +++ b/src/server/scripts/Battlegrounds/TwinPeaks/battleground_twin_peaks.cpp @@ -190,7 +190,8 @@ struct battleground_twin_peaks : BattlegroundScript TriggerGameEvent(TwinPeaks::Events::StartBattle); } - void DoForFlagKeepers(std::function<void(Player*)> const& action) const + template <std::invocable<Player*> Action> + void DoForFlagKeepers(Action const& action) const { for (ObjectGuid flagGUID : _flags) if (GameObject const* flag = battlegroundMap->GetGameObject(flagGUID)) diff --git a/src/server/scripts/Battlegrounds/WarsongGulch/battleground_warsong_gulch.cpp b/src/server/scripts/Battlegrounds/WarsongGulch/battleground_warsong_gulch.cpp index be76b69abf1..f658211a1bf 100644 --- a/src/server/scripts/Battlegrounds/WarsongGulch/battleground_warsong_gulch.cpp +++ b/src/server/scripts/Battlegrounds/WarsongGulch/battleground_warsong_gulch.cpp @@ -227,7 +227,8 @@ struct battleground_warsong_gulch : BattlegroundScript battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(_honorEndKills), HORDE); } - void DoForFlagKeepers(std::function<void(Player*)> const& action) const + template <std::invocable<Player*> Action> + void DoForFlagKeepers(Action const& action) const { for (ObjectGuid flagGUID : _flags) if (GameObject const* flag = battlegroundMap->GetGameObject(flagGUID)) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index b21e77530e0..762eafebd85 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -637,12 +637,12 @@ struct npc_high_overlord_saurfang_icc : public ScriptedAI return false; } - void GuardBroadcast(std::function<void(Creature*)>&& action) const + void GuardBroadcast(int32 action) const { std::vector<Creature*> guardList; GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 100.0f); for (Creature* guard : guardList) - action(guard); + guard->AI()->DoAction(action); } void DoAction(int32 action) override @@ -681,19 +681,13 @@ struct npc_high_overlord_saurfang_icc : public ScriptedAI _events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 30s); // move me->SetDisableGravity(false); me->GetMotionMaster()->MoveFall(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); + GuardBroadcast(ACTION_DESPAWN); break; } case ACTION_INTERRUPT_INTRO: { _events.Reset(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); + GuardBroadcast(ACTION_DESPAWN); break; } default: @@ -774,10 +768,7 @@ struct npc_high_overlord_saurfang_icc : public ScriptedAI break; case EVENT_INTRO_HORDE_8: Talk(SAY_INTRO_HORDE_8); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_CHARGE); - }); + GuardBroadcast(ACTION_CHARGE); me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); break; case EVENT_OUTRO_HORDE_2: // say @@ -834,12 +825,12 @@ struct npc_muradin_bronzebeard_icc : public ScriptedAI return false; } - void GuardBroadcast(std::function<void(Creature*)>&& action) const + void GuardBroadcast(int32 action) const { std::vector<Creature*> guardList; GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 100.0f); for (Creature* guard : guardList) - action(guard); + guard->AI()->DoAction(action); } void DoAction(int32 action) override @@ -874,10 +865,7 @@ struct npc_muradin_bronzebeard_icc : public ScriptedAI Talk(SAY_OUTRO_ALLIANCE_1); me->SetDisableGravity(false); me->GetMotionMaster()->MoveFall(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); + GuardBroadcast(ACTION_DESPAWN); // temp until outro fully done - to put deathbringer on respawn timer (until next reset) if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) @@ -886,10 +874,7 @@ struct npc_muradin_bronzebeard_icc : public ScriptedAI } case ACTION_INTERRUPT_INTRO: _events.Reset(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); + GuardBroadcast(ACTION_DESPAWN); break; } } @@ -932,10 +917,7 @@ struct npc_muradin_bronzebeard_icc : public ScriptedAI break; case EVENT_INTRO_ALLIANCE_5: Talk(SAY_INTRO_ALLIANCE_5); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_CHARGE); - }); + GuardBroadcast(ACTION_CHARGE); me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); break; } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index 6a2289b5642..9a2fe5e8926 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -160,12 +160,25 @@ static Player* FindEligibleTarget(Creature const* me, bool isGateOpen) } /* Wave data */ -typedef std::pair<uint32, uint8> GothikWaveEntry; // (npcEntry, npcCount) -typedef std::set<GothikWaveEntry> GothikWave; -typedef std::pair<GothikWave, uint8> GothikWaveInfo; // (wave, secondsToNext) -typedef std::vector<GothikWaveInfo> GothikWaveData; -const GothikWaveData waves10 = +struct GothikWaveEntry { + uint32 CreatureId = 0; + uint32 Count = 0; +}; + +struct GothikWaveInfo +{ + constexpr GothikWaveInfo(std::initializer_list<GothikWaveEntry> waves, int64 timeToNextWave) : TimeToNextWave(timeToNextWave) + { + std::ranges::copy_n(waves.begin(), std::min(std::ranges::ssize(waves), std::ranges::ssize(Creatures)), Creatures.begin()); + } + + std::array<GothikWaveEntry, 3> Creatures; + Seconds TimeToNextWave; +}; + +static constexpr std::array<GothikWaveInfo, 19> waves10 = +{ { { {{NPC_LIVE_TRAINEE, 2}}, 20}, @@ -223,10 +236,10 @@ const GothikWaveData waves10 = { {{NPC_LIVE_TRAINEE, 2}}, 0} -}; +} }; -const GothikWaveData waves25 = -{ +static constexpr std::array<GothikWaveInfo, 18> waves25 = +{ { { {{NPC_LIVE_TRAINEE, 3}}, 20}, @@ -281,7 +294,7 @@ const GothikWaveData waves25 = { {{NPC_LIVE_RIDER, 1}, {NPC_LIVE_KNIGHT, 2}, {NPC_LIVE_TRAINEE, 3}}, 0} -}; +} }; // GUID of first trigger NPC (used as offset for guid checks) // 0-1 are living side soul triggers, 2-3 are spectral side soul triggers, 4 is living rider spawn trigger, 5-7 are living other spawn trigger, 8-12 are skull pile triggers @@ -426,7 +439,7 @@ struct boss_gothik : public BossAI { case EVENT_SUMMON: { - if (RAID_MODE(waves10,waves25).size() <= _waveCount) // bounds check + if (RAID_MODE(waves10.size(), waves25.size()) <= _waveCount) // bounds check { TC_LOG_INFO("scripts", "GothikAI: Wave count {} is out of range for difficulty {}.", _waveCount, static_cast<uint32>(GetDifficulty())); break; @@ -434,8 +447,9 @@ struct boss_gothik : public BossAI std::list<Creature*> triggers; me->GetCreatureListWithEntryInGrid(triggers, NPC_TRIGGER, 150.0f); - for (GothikWaveEntry entry : RAID_MODE(waves10, waves25)[_waveCount].first) - for (uint8 i = 0; i < entry.second; ++i) + for (GothikWaveEntry entry : RAID_MODE(waves10[_waveCount], waves25[_waveCount]).Creatures) + { + for (uint32 i = 0; i < entry.Count; ++i) { // GUID layout is as follows: // CGUID+4: center (back of platform) - primary rider spawn @@ -443,7 +457,7 @@ struct boss_gothik : public BossAI // CGUID+6: center (front of platform) - second spawn // CGUID+7: south (front of platform) - primary trainee spawn uint32 targetDBGuid; - switch (entry.first) + switch (entry.CreatureId) { case NPC_LIVE_RIDER: // only spawns from center (back) > north targetDBGuid = (CGUID_TRIGGER + 4) + (i % 2); @@ -455,19 +469,17 @@ struct boss_gothik : public BossAI targetDBGuid = (CGUID_TRIGGER + 7) - (i % 3); break; default: - targetDBGuid = 0; + continue; } - for (Creature* trigger : triggers) - if (trigger && trigger->GetSpawnId() == targetDBGuid) - { - DoSummon(entry.first, trigger, 1.0f, 15s, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - break; - } + auto triggerItr = std::ranges::find(triggers, targetDBGuid, [](Creature const* trigger) { return trigger->GetSpawnId(); }); + if (triggerItr != triggers.end()) + DoSummon(entry.CreatureId, *triggerItr, 1.0f, 15s, TEMPSUMMON_CORPSE_TIMED_DESPAWN); } + } - if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second) - events.Repeat(Seconds(timeToNext)); + if (Seconds timeToNext = RAID_MODE(waves10[_waveCount], waves25[_waveCount]).TimeToNextWave; timeToNext > 0s) + events.Repeat(timeToNext); ++_waveCount; break; @@ -532,6 +544,8 @@ struct boss_gothik : public BossAI case EVENT_INTRO_4: Talk(SAY_INTRO_4); break; + default: + break; } } } |