aboutsummaryrefslogtreecommitdiff
path: root/src/common/Utilities
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/Utilities')
-rw-r--r--src/common/Utilities/ByteConverter.h68
-rw-r--r--src/common/Utilities/Duration.h39
-rw-r--r--src/common/Utilities/EventMap.cpp136
-rw-r--r--src/common/Utilities/EventMap.h342
-rw-r--r--src/common/Utilities/EventProcessor.cpp99
-rw-r--r--src/common/Utilities/EventProcessor.h73
-rw-r--r--src/common/Utilities/StringFormat.h46
-rw-r--r--src/common/Utilities/TaskScheduler.cpp229
-rw-r--r--src/common/Utilities/TaskScheduler.h650
-rw-r--r--src/common/Utilities/Timer.h203
-rw-r--r--src/common/Utilities/Util.cpp569
-rw-r--r--src/common/Utilities/Util.h548
12 files changed, 3002 insertions, 0 deletions
diff --git a/src/common/Utilities/ByteConverter.h b/src/common/Utilities/ByteConverter.h
new file mode 100644
index 00000000000..a077de3eb0b
--- /dev/null
+++ b/src/common/Utilities/ByteConverter.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITY_BYTECONVERTER_H
+#define TRINITY_BYTECONVERTER_H
+
+/** ByteConverter reverse your byte order. This is use
+ for cross platform where they have different endians.
+ */
+
+#include "Define.h"
+#include <algorithm>
+
+namespace ByteConverter
+{
+ template<size_t T>
+ inline void convert(char *val)
+ {
+ std::swap(*val, *(val + T - 1));
+ convert<T - 2>(val + 1);
+ }
+
+ template<> inline void convert<0>(char *) { }
+ template<> inline void convert<1>(char *) { } // ignore central byte
+
+ template<typename T> inline void apply(T *val)
+ {
+ convert<sizeof(T)>((char *)(val));
+ }
+}
+
+#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
+template<typename T> inline void EndianConvert(T& val) { ByteConverter::apply<T>(&val); }
+template<typename T> inline void EndianConvertReverse(T&) { }
+template<typename T> inline void EndianConvertPtr(void* val) { ByteConverter::apply<T>(val); }
+template<typename T> inline void EndianConvertPtrReverse(void*) { }
+#else
+template<typename T> inline void EndianConvert(T&) { }
+template<typename T> inline void EndianConvertReverse(T& val) { ByteConverter::apply<T>(&val); }
+template<typename T> inline void EndianConvertPtr(void*) { }
+template<typename T> inline void EndianConvertPtrReverse(void* val) { ByteConverter::apply<T>(val); }
+#endif
+
+template<typename T> void EndianConvert(T*); // will generate link error
+template<typename T> void EndianConvertReverse(T*); // will generate link error
+
+inline void EndianConvert(uint8&) { }
+inline void EndianConvert( int8&) { }
+inline void EndianConvertReverse(uint8&) { }
+inline void EndianConvertReverse( int8&) { }
+
+#endif
+
diff --git a/src/common/Utilities/Duration.h b/src/common/Utilities/Duration.h
new file mode 100644
index 00000000000..58a08e5842f
--- /dev/null
+++ b/src/common/Utilities/Duration.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DURATION_H_
+#define _DURATION_H_
+
+#include <chrono>
+
+/// Milliseconds shorthand typedef.
+typedef std::chrono::milliseconds Milliseconds;
+
+/// Seconds shorthand typedef.
+typedef std::chrono::seconds Seconds;
+
+/// Minutes shorthand typedef.
+typedef std::chrono::minutes Minutes;
+
+/// Hours shorthand typedef.
+typedef std::chrono::hours Hours;
+
+/// Makes std::chrono_literals globally available.
+// ToDo: Enable this when TC supports C++14.
+// using namespace std::chrono_literals;
+
+#endif // _DURATION_H_
diff --git a/src/common/Utilities/EventMap.cpp b/src/common/Utilities/EventMap.cpp
new file mode 100644
index 00000000000..8c3f60afe82
--- /dev/null
+++ b/src/common/Utilities/EventMap.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "EventMap.h"
+
+void EventMap::Reset()
+{
+ _eventMap.clear();
+ _time = 0;
+ _phase = 0;
+}
+
+void EventMap::SetPhase(uint8 phase)
+{
+ if (!phase)
+ _phase = 0;
+ else if (phase <= 8)
+ _phase = uint8(1 << (phase - 1));
+}
+
+void EventMap::ScheduleEvent(uint32 eventId, uint32 time, uint32 group /*= 0*/, uint8 phase /*= 0*/)
+{
+ if (group && group <= 8)
+ eventId |= (1 << (group + 15));
+
+ if (phase && phase <= 8)
+ eventId |= (1 << (phase + 23));
+
+ _eventMap.insert(EventStore::value_type(_time + time, eventId));
+}
+
+uint32 EventMap::ExecuteEvent()
+{
+ while (!Empty())
+ {
+ EventStore::iterator itr = _eventMap.begin();
+
+ if (itr->first > _time)
+ return 0;
+ else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
+ _eventMap.erase(itr);
+ else
+ {
+ uint32 eventId = (itr->second & 0x0000FFFF);
+ _lastEvent = itr->second; // include phase/group
+ _eventMap.erase(itr);
+ return eventId;
+ }
+ }
+
+ return 0;
+}
+
+void EventMap::DelayEvents(uint32 delay, uint32 group)
+{
+ if (!group || group > 8 || Empty())
+ 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++);
+ }
+ else
+ ++itr;
+ }
+
+ _eventMap.insert(delayed.begin(), delayed.end());
+}
+
+void EventMap::CancelEvent(uint32 eventId)
+{
+ if (Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (eventId == (itr->second & 0x0000FFFF))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+}
+
+void EventMap::CancelEventGroup(uint32 group)
+{
+ if (!group || group > 8 || Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & (1 << (group + 15)))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+}
+
+uint32 EventMap::GetNextEventTime(uint32 eventId) const
+{
+ if (Empty())
+ return 0;
+
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first;
+
+ return 0;
+}
+
+uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first - _time;
+
+ return std::numeric_limits<uint32>::max();
+}
diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h
new file mode 100644
index 00000000000..021dffc4940
--- /dev/null
+++ b/src/common/Utilities/EventMap.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _EVENT_MAP_H_
+#define _EVENT_MAP_H_
+
+#include "Common.h"
+#include "Duration.h"
+#include "Util.h"
+
+class EventMap
+{
+ /**
+ * Internal storage type.
+ * Key: Time as uint32 when the event should occur.
+ * Value: The event data as uint32.
+ *
+ * Structure of event data:
+ * - Bit 0 - 15: Event Id.
+ * - Bit 16 - 23: Group
+ * - Bit 24 - 31: Phase
+ * - Pattern: 0xPPGGEEEE
+ */
+ typedef std::multimap<uint32, uint32> EventStore;
+
+public:
+ EventMap() : _time(0), _phase(0), _lastEvent(0) { }
+
+ /**
+ * @name Reset
+ * @brief Removes all scheduled events and resets time and phase.
+ */
+ void Reset();
+
+ /**
+ * @name Update
+ * @brief Updates the timer of the event map.
+ * @param time Value in ms to be added to time.
+ */
+ void Update(uint32 time)
+ {
+ _time += time;
+ }
+
+ /**
+ * @name GetTimer
+ * @return Current timer in ms value.
+ */
+ uint32 GetTimer() const
+ {
+ return _time;
+ }
+
+ /**
+ * @name GetPhaseMask
+ * @return Active phases as mask.
+ */
+ uint8 GetPhaseMask() const
+ {
+ return _phase;
+ }
+
+ /**
+ * @name Empty
+ * @return True, if there are no events scheduled.
+ */
+ bool Empty() const
+ {
+ return _eventMap.empty();
+ }
+
+ /**
+ * @name SetPhase
+ * @brief Sets the phase of the map (absolute).
+ * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
+ */
+ void SetPhase(uint8 phase);
+
+ /**
+ * @name AddPhase
+ * @brief Activates the given phase (bitwise).
+ * @param phase Phase which should be activated. Values: 1 - 8
+ */
+ void AddPhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase |= uint8(1 << (phase - 1));
+ }
+
+ /**
+ * @name RemovePhase
+ * @brief Deactivates the given phase (bitwise).
+ * @param phase Phase which should be deactivated. Values: 1 - 8.
+ */
+ void RemovePhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase &= uint8(~(1 << (phase - 1)));
+ }
+
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds as std::chrono::duration until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
+ {
+ ScheduleEvent(eventId, time.count(), group, phase);
+ }
+
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0);
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds as std::chrono::duration until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, Milliseconds const& time, uint32 group = 0, uint8 phase = 0)
+ {
+ RescheduleEvent(eventId, time.count(), group, phase);
+ }
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
+ {
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, time, group, phase);
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until in milliseconds as std::chrono::duration the event occurs.
+ */
+ void Repeat(Milliseconds const& time)
+ {
+ Repeat(time.count());
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until the event occurs.
+ */
+ void Repeat(uint32 time)
+ {
+ _eventMap.insert(EventStore::value_type(_time + time, _lastEvent));
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param minTime Minimum time as std::chrono::duration until the event occurs.
+ * @param maxTime Maximum time as std::chrono::duration until the event occurs.
+ */
+ void Repeat(Milliseconds const& minTime, Milliseconds const& maxTime)
+ {
+ Repeat(minTime.count(), maxTime.count());
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event, Equivalent to Repeat(urand(minTime, maxTime).
+ * @param minTime Minimum time until the event occurs.
+ * @param maxTime Maximum time until the event occurs.
+ */
+ void Repeat(uint32 minTime, uint32 maxTime)
+ {
+ Repeat(urand(minTime, maxTime));
+ }
+
+ /**
+ * @name ExecuteEvent
+ * @brief Returns the next event to execute and removes it from map.
+ * @return Id of the event to execute.
+ */
+ uint32 ExecuteEvent();
+
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay in ms as std::chrono::duration.
+ */
+ void DelayEvents(Milliseconds const& delay)
+ {
+ DelayEvents(delay.count());
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay.
+ */
+ void DelayEvents(uint32 delay)
+ {
+ _time = delay < _time ? _time - delay : 0;
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay in ms as std::chrono::duration.
+ * @param group Group of the events.
+ */
+ void DelayEvents(Milliseconds const& delay, uint32 group)
+ {
+ DelayEvents(delay.count(), group);
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay.
+ * @param group Group of the events.
+ */
+ void DelayEvents(uint32 delay, uint32 group);
+
+ /**
+ * @name CancelEvent
+ * @brief Cancels all events of the specified id.
+ * @param eventId Event id to cancel.
+ */
+ void CancelEvent(uint32 eventId);
+
+ /**
+ * @name CancelEventGroup
+ * @brief Cancel events belonging to specified group.
+ * @param group Group to cancel.
+ */
+ void CancelEventGroup(uint32 group);
+
+ /**
+ * @name GetNextEventTime
+ * @brief Returns closest occurence of specified event.
+ * @param eventId Wanted event id.
+ * @return Time of found event.
+ */
+ uint32 GetNextEventTime(uint32 eventId) const;
+
+ /**
+ * @name GetNextEventTime
+ * @return Time of next event.
+ */
+ uint32 GetNextEventTime() const
+ {
+ return Empty() ? 0 : _eventMap.begin()->first;
+ }
+
+ /**
+ * @name IsInPhase
+ * @brief Returns whether event map is in specified phase or not.
+ * @param phase Wanted phase.
+ * @return True, if phase of event map contains specified phase.
+ */
+ bool IsInPhase(uint8 phase) const
+ {
+ return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
+ }
+
+ /**
+ * @name GetTimeUntilEvent
+ * @brief Returns time in milliseconds until next event.
+ * @param eventId of the event.
+ * @return Time of next event.
+ */
+ uint32 GetTimeUntilEvent(uint32 eventId) const;
+
+private:
+ /**
+ * @name _time
+ * @brief Internal timer.
+ *
+ * This does not represent the real date/time value.
+ * It's more like a stopwatch: It can run, it can be stopped,
+ * it can be resetted and so on. Events occur when this timer
+ * has reached their time value. Its value is changed in the
+ * Update method.
+ */
+ uint32 _time;
+
+ /**
+ * @name _phase
+ * @brief Phase mask of the event map.
+ *
+ * Contains the phases the event map is in. Multiple
+ * phases from 1 to 8 can be set with SetPhase or
+ * AddPhase. RemovePhase deactives a phase.
+ */
+ uint8 _phase;
+
+ /**
+ * @name _eventMap
+ * @brief Internal event storage map. Contains the scheduled events.
+ *
+ * See typedef at the beginning of the class for more
+ * details.
+ */
+ EventStore _eventMap;
+
+ /**
+ * @name _lastEvent
+ * @brief Stores information on the most recently executed event
+ */
+ uint32 _lastEvent;
+};
+
+#endif // _EVENT_MAP_H_
diff --git a/src/common/Utilities/EventProcessor.cpp b/src/common/Utilities/EventProcessor.cpp
new file mode 100644
index 00000000000..34695665443
--- /dev/null
+++ b/src/common/Utilities/EventProcessor.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "EventProcessor.h"
+
+EventProcessor::EventProcessor()
+{
+ m_time = 0;
+ m_aborting = false;
+}
+
+EventProcessor::~EventProcessor()
+{
+ KillAllEvents(true);
+}
+
+void EventProcessor::Update(uint32 p_time)
+{
+ // update time
+ m_time += p_time;
+
+ // main event loop
+ EventList::iterator i;
+ while (((i = m_events.begin()) != m_events.end()) && i->first <= m_time)
+ {
+ // get and remove event from queue
+ BasicEvent* Event = i->second;
+ m_events.erase(i);
+
+ if (!Event->to_Abort)
+ {
+ if (Event->Execute(m_time, p_time))
+ {
+ // completely destroy event if it is not re-added
+ delete Event;
+ }
+ }
+ else
+ {
+ Event->Abort(m_time);
+ delete Event;
+ }
+ }
+}
+
+void EventProcessor::KillAllEvents(bool force)
+{
+ // prevent event insertions
+ m_aborting = true;
+
+ // first, abort all existing events
+ for (EventList::iterator i = m_events.begin(); i != m_events.end();)
+ {
+ EventList::iterator i_old = i;
+ ++i;
+
+ i_old->second->to_Abort = true;
+ i_old->second->Abort(m_time);
+ if (force || i_old->second->IsDeletable())
+ {
+ delete i_old->second;
+
+ if (!force) // need per-element cleanup
+ m_events.erase (i_old);
+ }
+ }
+
+ // fast clear event list (in force case)
+ if (force)
+ m_events.clear();
+}
+
+void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)
+{
+ if (set_addtime) Event->m_addTime = m_time;
+ Event->m_execTime = e_time;
+ m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event));
+}
+
+uint64 EventProcessor::CalculateTime(uint64 t_offset) const
+{
+ return(m_time + t_offset);
+}
+
diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h
new file mode 100644
index 00000000000..3d54bd6f9f2
--- /dev/null
+++ b/src/common/Utilities/EventProcessor.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __EVENTPROCESSOR_H
+#define __EVENTPROCESSOR_H
+
+#include "Define.h"
+
+#include <map>
+
+// Note. All times are in milliseconds here.
+
+class BasicEvent
+{
+ public:
+ BasicEvent()
+ {
+ to_Abort = false;
+ m_addTime = 0;
+ m_execTime = 0;
+ }
+ virtual ~BasicEvent() { } // override destructor to perform some actions on event removal
+
+ // this method executes when the event is triggered
+ // return false if event does not want to be deleted
+ // e_time is execution time, p_time is update interval
+ virtual bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) { return true; }
+
+ virtual bool IsDeletable() const { return true; } // this event can be safely deleted
+
+ virtual void Abort(uint64 /*e_time*/) { } // this method executes when the event is aborted
+
+ bool to_Abort; // set by externals when the event is aborted, aborted events don't execute
+ // and get Abort call when deleted
+
+ // these can be used for time offset control
+ uint64 m_addTime; // time when the event was added to queue, filled by event handler
+ uint64 m_execTime; // planned time of next execution, filled by event handler
+};
+
+typedef std::multimap<uint64, BasicEvent*> EventList;
+
+class EventProcessor
+{
+ public:
+ EventProcessor();
+ ~EventProcessor();
+
+ void Update(uint32 p_time);
+ void KillAllEvents(bool force);
+ void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true);
+ uint64 CalculateTime(uint64 t_offset) const;
+ protected:
+ uint64 m_time;
+ EventList m_events;
+ bool m_aborting;
+};
+#endif
diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h
new file mode 100644
index 00000000000..67e0100e7c8
--- /dev/null
+++ b/src/common/Utilities/StringFormat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_STRING_FORMAT_H
+#define TRINITYCORE_STRING_FORMAT_H
+
+#include "format.h"
+
+namespace Trinity
+{
+ /// Default TC string format function.
+ template<typename Format, typename... Args>
+ inline std::string StringFormat(Format&& fmt, Args&&... args)
+ {
+ return fmt::sprintf(std::forward<Format>(fmt), std::forward<Args>(args)...);
+ }
+
+ /// Returns true if the given char pointer is null.
+ inline bool IsFormatEmptyOrNull(const char* fmt)
+ {
+ return fmt == nullptr;
+ }
+
+ /// Returns true if the given std::string is empty.
+ inline bool IsFormatEmptyOrNull(std::string const& fmt)
+ {
+ return fmt.empty();
+ }
+}
+
+#endif
diff --git a/src/common/Utilities/TaskScheduler.cpp b/src/common/Utilities/TaskScheduler.cpp
new file mode 100644
index 00000000000..801cc96cf77
--- /dev/null
+++ b/src/common/Utilities/TaskScheduler.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TaskScheduler.h"
+
+TaskScheduler& TaskScheduler::ClearValidator()
+{
+ _predicate = EmptyValidator;
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::Update(success_t const& callback)
+{
+ _now = clock_t::now();
+ Dispatch(callback);
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::Update(size_t const milliseconds, success_t const& callback)
+{
+ return Update(std::chrono::milliseconds(milliseconds), callback);
+}
+
+TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable)
+{
+ _asyncHolder.push(callable);
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelAll()
+{
+ /// Clear the task holder
+ _task_holder.Clear();
+ _asyncHolder = AsyncHolder();
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroup(group_t const group)
+{
+ _task_holder.RemoveIf([group](TaskContainer const& task) -> bool
+ {
+ return task->IsInGroup(group);
+ });
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
+{
+ std::for_each(groups.begin(), groups.end(),
+ std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1));
+
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
+{
+ _task_holder.Push(std::move(task));
+ return *this;
+}
+
+void TaskScheduler::Dispatch(success_t const& callback)
+{
+ // If the validation failed abort the dispatching here.
+ if (!_predicate())
+ return;
+
+ // Process all asyncs
+ while (!_asyncHolder.empty())
+ {
+ _asyncHolder.front()();
+ _asyncHolder.pop();
+
+ // If the validation failed abort the dispatching here.
+ if (!_predicate())
+ return;
+ }
+
+ while (!_task_holder.IsEmpty())
+ {
+ if (_task_holder.First()->_end > _now)
+ break;
+
+ // Perfect forward the context to the handler
+ // Use weak references to catch destruction before callbacks.
+ TaskContext context(_task_holder.Pop(), std::weak_ptr<TaskScheduler>(self_reference));
+
+ // Invoke the context
+ context.Invoke();
+
+ // If the validation failed abort the dispatching here.
+ if (!_predicate())
+ return;
+ }
+
+ // On finish call the final callback
+ callback();
+}
+
+void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
+{
+ container.insert(task);
+}
+
+auto TaskScheduler::TaskQueue::Pop() -> TaskContainer
+{
+ TaskContainer result = *container.begin();
+ container.erase(container.begin());
+ return result;
+}
+
+auto TaskScheduler::TaskQueue::First() const -> TaskContainer const&
+{
+ return *container.begin();
+}
+
+void TaskScheduler::TaskQueue::Clear()
+{
+ container.clear();
+}
+
+void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ itr = container.erase(itr);
+ else
+ ++itr;
+}
+
+void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ std::vector<TaskContainer> cache;
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ {
+ cache.push_back(*itr);
+ itr = container.erase(itr);
+ }
+ else
+ ++itr;
+
+ container.insert(cache.begin(), cache.end());
+}
+
+bool TaskScheduler::TaskQueue::IsEmpty() const
+{
+ return container.empty();
+}
+
+TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
+{
+ if (auto const owner = _owner.lock())
+ apply(*owner);
+
+ return *this;
+}
+
+bool TaskContext::IsExpired() const
+{
+ return _owner.expired();
+}
+
+bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const
+{
+ return _task->IsInGroup(group);
+}
+
+TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group)
+{
+ _task->_group = group;
+ return *this;
+}
+
+TaskContext& TaskContext::ClearGroup()
+{
+ _task->_group = boost::none;
+ return *this;
+}
+
+TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const
+{
+ return _task->_repeated;
+}
+
+TaskContext& TaskContext::Async(std::function<void()> const& callable)
+{
+ return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable));
+}
+
+TaskContext& TaskContext::CancelAll()
+{
+ return Dispatch(std::mem_fn(&TaskScheduler::CancelAll));
+}
+
+TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group));
+}
+
+TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups)));
+}
+
+void TaskContext::AssertOnConsumed() const
+{
+ // This was adapted to TC to prevent static analysis tools from complaining.
+ // If you encounter this assertion check if you repeat a TaskContext more then 1 time!
+ ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!");
+}
+
+void TaskContext::Invoke()
+{
+ _task->_task(*this);
+}
diff --git a/src/common/Utilities/TaskScheduler.h b/src/common/Utilities/TaskScheduler.h
new file mode 100644
index 00000000000..f1fe7ea0a21
--- /dev/null
+++ b/src/common/Utilities/TaskScheduler.h
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TASK_SCHEDULER_H_
+#define _TASK_SCHEDULER_H_
+
+#include <algorithm>
+#include <chrono>
+#include <vector>
+#include <queue>
+#include <memory>
+#include <utility>
+#include <set>
+
+#include <boost/optional.hpp>
+
+#include "Util.h"
+#include "Duration.h"
+
+class TaskContext;
+
+/// The TaskScheduler class provides the ability to schedule std::function's in the near future.
+/// Use TaskScheduler::Update to update the scheduler.
+/// Popular methods are:
+/// * Schedule (Schedules a std::function which will be executed in the near future).
+/// * Schedules an asynchronous function which will be executed at the next update tick.
+/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks).
+/// Tasks are organized in groups (uint), multiple tasks can have the same group id,
+/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id!
+/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides
+/// access to the function schedule plan which makes it possible to repeat the task
+/// with the same duration or a new one.
+/// It also provides access to the repeat counter which is useful for task that repeat itself often
+/// but behave different every time (spoken event dialogs for example).
+class TaskScheduler
+{
+ friend class TaskContext;
+
+ // Time definitions (use steady clock)
+ typedef std::chrono::steady_clock clock_t;
+ typedef clock_t::time_point timepoint_t;
+ typedef clock_t::duration duration_t;
+
+ // Task group type
+ typedef uint32 group_t;
+ // Task repeated type
+ typedef uint32 repeated_t;
+ // Task handle type
+ typedef std::function<void(TaskContext)> task_handler_t;
+ // Predicate type
+ typedef std::function<bool()> predicate_t;
+ // Success handle type
+ typedef std::function<void()> success_t;
+
+ class Task
+ {
+ friend class TaskContext;
+ friend class TaskScheduler;
+
+ timepoint_t _end;
+ duration_t _duration;
+ boost::optional<group_t> _group;
+ repeated_t _repeated;
+ task_handler_t _task;
+
+ public:
+ // All Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group,
+ repeated_t const repeated, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { }
+
+ // Minimal Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { }
+
+ // Copy construct
+ Task(Task const&) = delete;
+ // Move construct
+ Task(Task&&) = delete;
+ // Copy Assign
+ Task& operator= (Task const&) = default;
+ // Move Assign
+ Task& operator= (Task&& right) = delete;
+
+ // Order tasks by its end
+ inline bool operator< (Task const& other) const
+ {
+ return _end < other._end;
+ }
+
+ inline bool operator> (Task const& other) const
+ {
+ return _end > other._end;
+ }
+
+ // Compare tasks with its end
+ inline bool operator== (Task const& other)
+ {
+ return _end == other._end;
+ }
+
+ // Returns true if the task is in the given group
+ inline bool IsInGroup(group_t const group) const
+ {
+ return _group == group;
+ }
+ };
+
+ typedef std::shared_ptr<Task> TaskContainer;
+
+ /// Container which provides Task order, insert and reschedule operations.
+ struct Compare
+ {
+ bool operator() (TaskContainer const& left, TaskContainer const& right)
+ {
+ return (*left.get()) < (*right.get());
+ };
+ };
+
+ class TaskQueue
+ {
+ std::multiset<TaskContainer, Compare> container;
+
+ public:
+ // Pushes the task in the container
+ void Push(TaskContainer&& task);
+
+ /// Pops the task out of the container
+ TaskContainer Pop();
+
+ TaskContainer const& First() const;
+
+ void Clear();
+
+ void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ bool IsEmpty() const;
+ };
+
+ /// Contains a self reference to track if this object was deleted or not.
+ std::shared_ptr<TaskScheduler> self_reference;
+
+ /// The current time point (now)
+ timepoint_t _now;
+
+ /// The Task Queue which contains all task objects.
+ TaskQueue _task_holder;
+
+ typedef std::queue<std::function<void()>> AsyncHolder;
+
+ /// Contains all asynchronous tasks which will be invoked at
+ /// the next update tick.
+ AsyncHolder _asyncHolder;
+
+ predicate_t _predicate;
+
+ static bool EmptyValidator()
+ {
+ return true;
+ }
+
+ static void EmptyCallback()
+ {
+ }
+
+public:
+ TaskScheduler()
+ : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(EmptyValidator) { }
+
+ template<typename P>
+ TaskScheduler(P&& predicate)
+ : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(std::forward<P>(predicate)) { }
+
+ TaskScheduler(TaskScheduler const&) = delete;
+ TaskScheduler(TaskScheduler&&) = delete;
+ TaskScheduler& operator= (TaskScheduler const&) = delete;
+ TaskScheduler& operator= (TaskScheduler&&) = delete;
+
+ /// Sets a validator which is asked if tasks are allowed to be executed.
+ template<typename P>
+ TaskScheduler& SetValidator(P&& predicate)
+ {
+ _predicate = std::forward<P>(predicate);
+ return *this;
+ }
+
+ /// Clears the validator which is asked if tasks are allowed to be executed.
+ TaskScheduler& ClearValidator();
+
+ /// Update the scheduler to the current time.
+ /// Calls the optional callback on successfully finish.
+ TaskScheduler& Update(success_t const& callback = EmptyCallback);
+
+ /// Update the scheduler with a difftime in ms.
+ /// Calls the optional callback on successfully finish.
+ TaskScheduler& Update(size_t const milliseconds, success_t const& callback = EmptyCallback);
+
+ /// 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> const& difftime,
+ success_t const& callback = EmptyCallback)
+ {
+ _now += difftime;
+ Dispatch(callback);
+ return *this;
+ }
+
+ /// Schedule an callable function that is executed at the next update tick.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskScheduler& Async(std::function<void()> const& callable);
+
+ /// 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> const& time,
+ task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, 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& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, group, task);
+ }
+
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group,
+ task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks.
+ /// Never call this from within a task context! Use TaskContext::CancelAll instead!
+ TaskScheduler& CancelAll();
+
+ /// Cancel all tasks of a single group.
+ /// Never call this from within a task context! Use TaskContext::CancelGroup instead!
+ TaskScheduler& CancelGroup(group_t const group);
+
+ /// Cancels all groups in the given std::vector.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ 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> const& duration)
+ {
+ _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool
+ {
+ task->_end += duration;
+ return true;
+ });
+ return *this;
+ }
+
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(RandomDurationBetween(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> const& duration)
+ {
+ _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
+ {
+ if (task->IsInGroup(group))
+ {
+ task->_end += duration;
+ return true;
+ }
+ else
+ return false;
+ });
+ return *this;
+ }
+
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with a given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ auto const end = _now + duration;
+ _task_holder.ModifyIf([end](TaskContainer const& task) -> bool
+ {
+ task->_end = end;
+ return true;
+ });
+ return *this;
+ }
+
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(RandomDurationBetween(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> const& 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;
+ }
+
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Insert a new task to the enqueued tasks.
+ TaskScheduler& InsertTask(TaskContainer task);
+
+ template<class _Rep, class _Period>
+ TaskScheduler& ScheduleAt(timepoint_t const& end,
+ std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task)
+ {
+ return InsertTask(TaskContainer(new Task(end + time, time, 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 const& end,
+ std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ static repeated_t const DEFAULT_REPEATED = 0;
+ return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task)));
+ }
+
+ // Returns a random duration between min and max
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ static std::chrono::milliseconds
+ RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min);
+ auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max);
+
+ // TC specific: use SFMT URandom
+ return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count()));
+ }
+
+ /// Dispatch remaining tasks
+ void Dispatch(success_t const& callback);
+};
+
+class TaskContext
+{
+ friend class TaskScheduler;
+
+ /// Associated task
+ TaskScheduler::TaskContainer _task;
+
+ /// Owner
+ std::weak_ptr<TaskScheduler> _owner;
+
+ /// Marks the task as consumed
+ std::shared_ptr<bool> _consumed;
+
+ /// Dispatches an action safe on the TaskScheduler
+ TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
+
+public:
+ // Empty constructor
+ TaskContext()
+ : _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
+
+ // Construct from task and owner
+ explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
+ : _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { }
+
+ // Copy construct
+ TaskContext(TaskContext const& right)
+ : _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
+
+ // Move construct
+ TaskContext(TaskContext&& right)
+ : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
+
+ // Copy assign
+ TaskContext& operator= (TaskContext const& right)
+ {
+ _task = right._task;
+ _owner = right._owner;
+ _consumed = right._consumed;
+ return *this;
+ }
+
+ // Move assign
+ TaskContext& operator= (TaskContext&& right)
+ {
+ _task = std::move(right._task);
+ _owner = std::move(right._owner);
+ _consumed = std::move(right._consumed);
+ return *this;
+ }
+
+ /// Returns true if the owner was deallocated and this context has expired.
+ bool IsExpired() const;
+
+ /// Returns true if the event is in the given group
+ bool IsInGroup(TaskScheduler::group_t const group) const;
+
+ /// Sets the event in the given group
+ TaskContext& SetGroup(TaskScheduler::group_t const group);
+
+ /// Removes the group from the event
+ TaskContext& ClearGroup();
+
+ /// Returns the repeat counter which increases every time the task is repeated.
+ TaskScheduler::repeated_t GetRepeatCounter() const;
+
+ /// Repeats the event and sets a new duration.
+ /// 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> const& duration)
+ {
+ AssertOnConsumed();
+
+ // Set new duration, in-context timing and increment repeat counter
+ _task->_duration = duration;
+ _task->_end += duration;
+ _task->_repeated += 1;
+ (*_consumed) = true;
+ return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
+ }
+
+ /// Repeats the event with the same duration.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ TaskContext& Repeat()
+ {
+ return Repeat(_task->_duration);
+ }
+
+ /// Repeats the event and set a new duration that is randomized between min and max.
+ /// 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return Repeat(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Schedule a callable function that is executed at the next update tick from within the context.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskContext& Async(std::function<void()> const& callable);
+
+ /// 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> const& time,
+ TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, 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> const& time,
+ TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
+ TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks from within the context.
+ TaskContext& CancelAll();
+
+ /// Cancel all tasks of a single group from within the context.
+ TaskContext& CancelGroup(TaskScheduler::group_t const group);
+
+ /// Cancels all groups in the given std::vector from within the context.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ 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> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(TaskScheduler::RandomDurationBetween(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> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with the given duration.
+ template<class _Rep, class _Period>
+ TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(TaskScheduler::RandomDurationBetween(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> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, 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> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Asserts if the task was consumed already.
+ void AssertOnConsumed() const;
+
+ /// Invokes the associated hook of the task.
+ void Invoke();
+};
+
+#endif /// _TASK_SCHEDULER_H_
diff --git a/src/common/Utilities/Timer.h b/src/common/Utilities/Timer.h
new file mode 100644
index 00000000000..c54903d7be2
--- /dev/null
+++ b/src/common/Utilities/Timer.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITY_TIMER_H
+#define TRINITY_TIMER_H
+
+#include <chrono>
+
+inline uint32 getMSTime()
+{
+ using namespace std::chrono;
+
+ static const system_clock::time_point ApplicationStartTime = system_clock::now();
+
+ return uint32(duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count());
+}
+
+inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
+{
+ // getMSTime() have limited data range and this is case when it overflow in this tick
+ if (oldMSTime > newMSTime)
+ return (0xFFFFFFFF - oldMSTime) + newMSTime;
+ else
+ return newMSTime - oldMSTime;
+}
+
+inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
+{
+ return getMSTimeDiff(oldMSTime, getMSTime());
+}
+
+struct IntervalTimer
+{
+public:
+
+ IntervalTimer()
+ : _interval(0), _current(0)
+ {
+ }
+
+ void Update(time_t diff)
+ {
+ _current += diff;
+ if (_current < 0)
+ _current = 0;
+ }
+
+ bool Passed()
+ {
+ return _current >= _interval;
+ }
+
+ void Reset()
+ {
+ if (_current >= _interval)
+ _current %= _interval;
+ }
+
+ void SetCurrent(time_t current)
+ {
+ _current = current;
+ }
+
+ void SetInterval(time_t interval)
+ {
+ _interval = interval;
+ }
+
+ time_t GetInterval() const
+ {
+ return _interval;
+ }
+
+ time_t GetCurrent() const
+ {
+ return _current;
+ }
+
+private:
+
+ time_t _interval;
+ time_t _current;
+};
+
+struct TimeTracker
+{
+public:
+
+ TimeTracker(time_t expiry)
+ : i_expiryTime(expiry)
+ {
+ }
+
+ void Update(time_t diff)
+ {
+ i_expiryTime -= diff;
+ }
+
+ bool Passed() const
+ {
+ return i_expiryTime <= 0;
+ }
+
+ void Reset(time_t interval)
+ {
+ i_expiryTime = interval;
+ }
+
+ time_t GetExpiry() const
+ {
+ return i_expiryTime;
+ }
+
+private:
+
+ time_t i_expiryTime;
+};
+
+struct TimeTrackerSmall
+{
+public:
+
+ TimeTrackerSmall(uint32 expiry = 0)
+ : i_expiryTime(expiry)
+ {
+ }
+
+ void Update(int32 diff)
+ {
+ i_expiryTime -= diff;
+ }
+
+ bool Passed() const
+ {
+ return i_expiryTime <= 0;
+ }
+
+ void Reset(uint32 interval)
+ {
+ i_expiryTime = interval;
+ }
+
+ int32 GetExpiry() const
+ {
+ return i_expiryTime;
+ }
+
+private:
+
+ int32 i_expiryTime;
+};
+
+struct PeriodicTimer
+{
+public:
+
+ PeriodicTimer(int32 period, int32 start_time)
+ : i_period(period), i_expireTime(start_time)
+ {
+ }
+
+ bool Update(const uint32 diff)
+ {
+ if ((i_expireTime -= diff) > 0)
+ return false;
+
+ i_expireTime += i_period > int32(diff) ? i_period : diff;
+ return true;
+ }
+
+ void SetPeriodic(int32 period, int32 start_time)
+ {
+ i_expireTime = start_time;
+ i_period = period;
+ }
+
+ // Tracker interface
+ void TUpdate(int32 diff) { i_expireTime -= diff; }
+ bool TPassed() const { return i_expireTime <= 0; }
+ void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; }
+
+private:
+
+ int32 i_period;
+ int32 i_expireTime;
+};
+
+#endif
diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp
new file mode 100644
index 00000000000..9f61dd12e4c
--- /dev/null
+++ b/src/common/Utilities/Util.cpp
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Util.h"
+#include "Common.h"
+#include "CompilerDefs.h"
+#include "utf8.h"
+#include "SFMT.h"
+#include "Errors.h" // for ASSERT
+#include <stdarg.h>
+#include <boost/thread/tss.hpp>
+
+#if COMPILER == COMPILER_GNU
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif
+
+static boost::thread_specific_ptr<SFMTRand> sfmtRand;
+
+static SFMTRand* GetRng()
+{
+ SFMTRand* rand = sfmtRand.get();
+
+ if (!rand)
+ {
+ rand = new SFMTRand();
+ sfmtRand.reset(rand);
+ }
+
+ return rand;
+}
+
+int32 irand(int32 min, int32 max)
+{
+ ASSERT(max >= min);
+ return int32(GetRng()->IRandom(min, max));
+}
+
+uint32 urand(uint32 min, uint32 max)
+{
+ ASSERT(max >= min);
+ return GetRng()->URandom(min, max);
+}
+
+uint32 urandms(uint32 min, uint32 max)
+{
+ ASSERT(max >= min);
+ ASSERT(INT_MAX/IN_MILLISECONDS >= max);
+ return GetRng()->URandom(min * IN_MILLISECONDS, max * IN_MILLISECONDS);
+}
+
+float frand(float min, float max)
+{
+ ASSERT(max >= min);
+ return float(GetRng()->Random() * (max - min) + min);
+}
+
+uint32 rand32()
+{
+ return GetRng()->BRandom();
+}
+
+double rand_norm()
+{
+ return GetRng()->Random();
+}
+
+double rand_chance()
+{
+ return GetRng()->Random() * 100.0;
+}
+
+Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve)
+{
+ m_str = new char[src.length() + 1];
+ memcpy(m_str, src.c_str(), src.length() + 1);
+
+ if (vectorReserve)
+ m_storage.reserve(vectorReserve);
+
+ char* posold = m_str;
+ char* posnew = m_str;
+
+ for (;;)
+ {
+ if (*posnew == sep)
+ {
+ m_storage.push_back(posold);
+ posold = posnew + 1;
+
+ *posnew = '\0';
+ }
+ else if (*posnew == '\0')
+ {
+ // Hack like, but the old code accepted these kind of broken strings,
+ // so changing it would break other things
+ if (posold != posnew)
+ m_storage.push_back(posold);
+
+ break;
+ }
+
+ ++posnew;
+ }
+}
+
+void stripLineInvisibleChars(std::string &str)
+{
+ static std::string const invChars = " \t\7\n";
+
+ size_t wpos = 0;
+
+ bool space = false;
+ for (size_t pos = 0; pos < str.size(); ++pos)
+ {
+ if (invChars.find(str[pos])!=std::string::npos)
+ {
+ if (!space)
+ {
+ str[wpos++] = ' ';
+ space = true;
+ }
+ }
+ else
+ {
+ if (wpos!=pos)
+ str[wpos++] = str[pos];
+ else
+ ++wpos;
+ space = false;
+ }
+ }
+
+ if (wpos < str.size())
+ str.erase(wpos, str.size());
+ if (str.find("|TInterface")!=std::string::npos)
+ str.clear();
+
+}
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+struct tm* localtime_r(const time_t* time, struct tm *result)
+{
+ localtime_s(result, time);
+ return result;
+}
+#endif
+
+std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly)
+{
+ uint64 secs = timeInSecs % MINUTE;
+ uint64 minutes = timeInSecs % HOUR / MINUTE;
+ uint64 hours = timeInSecs % DAY / HOUR;
+ uint64 days = timeInSecs / DAY;
+
+ std::ostringstream ss;
+ if (days)
+ ss << days << (shortText ? "d" : " Day(s) ");
+ if (hours || hoursOnly)
+ ss << hours << (shortText ? "h" : " Hour(s) ");
+ if (!hoursOnly)
+ {
+ if (minutes)
+ ss << minutes << (shortText ? "m" : " Minute(s) ");
+ if (secs || (!days && !hours && !minutes) )
+ ss << secs << (shortText ? "s" : " Second(s).");
+ }
+
+ return ss.str();
+}
+
+int32 MoneyStringToMoney(const std::string& moneyString)
+{
+ int32 money = 0;
+
+ if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 ||
+ std::count(moneyString.begin(), moneyString.end(), 's') == 1 ||
+ std::count(moneyString.begin(), moneyString.end(), 'c') == 1))
+ return 0; // Bad format
+
+ Tokenizer tokens(moneyString, ' ');
+ for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
+ {
+ std::string tokenString(*itr);
+ size_t gCount = std::count(tokenString.begin(), tokenString.end(), 'g');
+ size_t sCount = std::count(tokenString.begin(), tokenString.end(), 's');
+ size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c');
+ if (gCount + sCount + cCount != 1)
+ return 0;
+
+ uint32 amount = atoi(*itr);
+ if (gCount == 1)
+ money += amount * 100 * 100;
+ else if (sCount == 1)
+ money += amount * 100;
+ else if (cCount == 1)
+ money += amount;
+ }
+
+ return money;
+}
+
+uint32 TimeStringToSecs(const std::string& timestring)
+{
+ uint32 secs = 0;
+ uint32 buffer = 0;
+ uint32 multiplier = 0;
+
+ for (std::string::const_iterator itr = timestring.begin(); itr != timestring.end(); ++itr)
+ {
+ if (isdigit(*itr))
+ {
+ buffer*=10;
+ buffer+= (*itr)-'0';
+ }
+ else
+ {
+ switch (*itr)
+ {
+ case 'd': multiplier = DAY; break;
+ case 'h': multiplier = HOUR; break;
+ case 'm': multiplier = MINUTE; break;
+ case 's': multiplier = 1; break;
+ default : return 0; //bad format
+ }
+ buffer*=multiplier;
+ secs+=buffer;
+ buffer=0;
+ }
+ }
+
+ return secs;
+}
+
+std::string TimeToTimestampStr(time_t t)
+{
+ tm aTm;
+ localtime_r(&t, &aTm);
+ // YYYY year
+ // MM month (2 digits 01-12)
+ // DD day (2 digits 01-31)
+ // HH hour (2 digits 00-23)
+ // MM minutes (2 digits 00-59)
+ // SS seconds (2 digits 00-59)
+ char buf[20];
+ snprintf(buf, 20, "%04d-%02d-%02d_%02d-%02d-%02d", aTm.tm_year+1900, aTm.tm_mon+1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+ return std::string(buf);
+}
+
+/// Check if the string is a valid ip address representation
+bool IsIPAddress(char const* ipaddress)
+{
+ if (!ipaddress)
+ return false;
+
+ // Let the big boys do it.
+ // Drawback: all valid ip address formats are recognized e.g.: 12.23, 121234, 0xABCD)
+ return inet_addr(ipaddress) != INADDR_NONE;
+}
+
+/// create PID file
+uint32 CreatePIDFile(const std::string& filename)
+{
+ FILE* pid_file = fopen (filename.c_str(), "w" );
+ if (pid_file == NULL)
+ return 0;
+
+#ifdef _WIN32
+ DWORD pid = GetCurrentProcessId();
+#else
+ pid_t pid = getpid();
+#endif
+
+ fprintf(pid_file, "%u", pid );
+ fclose(pid_file);
+
+ return (uint32)pid;
+}
+
+size_t utf8length(std::string& utf8str)
+{
+ try
+ {
+ return utf8::distance(utf8str.c_str(), utf8str.c_str()+utf8str.size());
+ }
+ catch(std::exception)
+ {
+ utf8str.clear();
+ return 0;
+ }
+}
+
+void utf8truncate(std::string& utf8str, size_t len)
+{
+ try
+ {
+ size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str()+utf8str.size());
+ if (wlen <= len)
+ return;
+
+ std::wstring wstr;
+ wstr.resize(wlen);
+ utf8::utf8to16(utf8str.c_str(), utf8str.c_str()+utf8str.size(), &wstr[0]);
+ wstr.resize(len);
+ char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str()+wstr.size(), &utf8str[0]);
+ utf8str.resize(oend-(&utf8str[0])); // remove unused tail
+ }
+ catch(std::exception)
+ {
+ utf8str.clear();
+ }
+}
+
+bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
+{
+ try
+ {
+ size_t len = utf8::distance(utf8str, utf8str+csize);
+ if (len > wsize)
+ {
+ if (wsize > 0)
+ wstr[0] = L'\0';
+ wsize = 0;
+ return false;
+ }
+
+ wsize = len;
+ utf8::utf8to16(utf8str, utf8str+csize, wstr);
+ wstr[len] = L'\0';
+ }
+ catch(std::exception)
+ {
+ if (wsize > 0)
+ wstr[0] = L'\0';
+ wsize = 0;
+ return false;
+ }
+
+ return true;
+}
+
+bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr)
+{
+ try
+ {
+ if (size_t len = utf8::distance(utf8str.c_str(), utf8str.c_str()+utf8str.size()))
+ {
+ wstr.resize(len);
+ utf8::utf8to16(utf8str.c_str(), utf8str.c_str()+utf8str.size(), &wstr[0]);
+ }
+ }
+ catch(std::exception)
+ {
+ wstr.clear();
+ return false;
+ }
+
+ return true;
+}
+
+bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str)
+{
+ try
+ {
+ std::string utf8str2;
+ utf8str2.resize(size*4); // allocate for most long case
+
+ if (size)
+ {
+ char* oend = utf8::utf16to8(wstr, wstr+size, &utf8str2[0]);
+ utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
+ }
+ utf8str = utf8str2;
+ }
+ catch(std::exception)
+ {
+ utf8str.clear();
+ return false;
+ }
+
+ return true;
+}
+
+bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str)
+{
+ try
+ {
+ std::string utf8str2;
+ utf8str2.resize(wstr.size()*4); // allocate for most long case
+
+ if (wstr.size())
+ {
+ char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str()+wstr.size(), &utf8str2[0]);
+ utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
+ }
+ utf8str = utf8str2;
+ }
+ catch(std::exception)
+ {
+ utf8str.clear();
+ return false;
+ }
+
+ return true;
+}
+
+typedef wchar_t const* const* wstrlist;
+
+std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension)
+{
+ // supported only Cyrillic cases
+ if (wname.size() < 1 || !isCyrillicCharacter(wname[0]) || declension > 5)
+ return wname;
+
+ // Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
+
+ static wchar_t const a_End[] = { wchar_t(1), wchar_t(0x0430), wchar_t(0x0000)};
+ static wchar_t const o_End[] = { wchar_t(1), wchar_t(0x043E), wchar_t(0x0000)};
+ static wchar_t const ya_End[] = { wchar_t(1), wchar_t(0x044F), wchar_t(0x0000)};
+ static wchar_t const ie_End[] = { wchar_t(1), wchar_t(0x0435), wchar_t(0x0000)};
+ static wchar_t const i_End[] = { wchar_t(1), wchar_t(0x0438), wchar_t(0x0000)};
+ static wchar_t const yeru_End[] = { wchar_t(1), wchar_t(0x044B), wchar_t(0x0000)};
+ static wchar_t const u_End[] = { wchar_t(1), wchar_t(0x0443), wchar_t(0x0000)};
+ static wchar_t const yu_End[] = { wchar_t(1), wchar_t(0x044E), wchar_t(0x0000)};
+ static wchar_t const oj_End[] = { wchar_t(2), wchar_t(0x043E), wchar_t(0x0439), wchar_t(0x0000)};
+ static wchar_t const ie_j_End[] = { wchar_t(2), wchar_t(0x0435), wchar_t(0x0439), wchar_t(0x0000)};
+ static wchar_t const io_j_End[] = { wchar_t(2), wchar_t(0x0451), wchar_t(0x0439), wchar_t(0x0000)};
+ static wchar_t const o_m_End[] = { wchar_t(2), wchar_t(0x043E), wchar_t(0x043C), wchar_t(0x0000)};
+ static wchar_t const io_m_End[] = { wchar_t(2), wchar_t(0x0451), wchar_t(0x043C), wchar_t(0x0000)};
+ static wchar_t const ie_m_End[] = { wchar_t(2), wchar_t(0x0435), wchar_t(0x043C), wchar_t(0x0000)};
+ static wchar_t const soft_End[] = { wchar_t(1), wchar_t(0x044C), wchar_t(0x0000)};
+ static wchar_t const j_End[] = { wchar_t(1), wchar_t(0x0439), wchar_t(0x0000)};
+
+ static wchar_t const* const dropEnds[6][8] = {
+ { &a_End[1], &o_End[1], &ya_End[1], &ie_End[1], &soft_End[1], &j_End[1], NULL, NULL },
+ { &a_End[1], &ya_End[1], &yeru_End[1], &i_End[1], NULL, NULL, NULL, NULL },
+ { &ie_End[1], &u_End[1], &yu_End[1], &i_End[1], NULL, NULL, NULL, NULL },
+ { &u_End[1], &yu_End[1], &o_End[1], &ie_End[1], &soft_End[1], &ya_End[1], &a_End[1], NULL },
+ { &oj_End[1], &io_j_End[1], &ie_j_End[1], &o_m_End[1], &io_m_End[1], &ie_m_End[1], &yu_End[1], NULL },
+ { &ie_End[1], &i_End[1], NULL, NULL, NULL, NULL, NULL, NULL }
+ };
+
+ for (wchar_t const* const* itr = &dropEnds[declension][0]; *itr; ++itr)
+ {
+ size_t len = size_t((*itr)[-1]); // get length from string size field
+
+ if (wname.substr(wname.size()-len, len)==*itr)
+ return wname.substr(0, wname.size()-len);
+ }
+
+ return wname;
+}
+
+bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+ std::wstring wstr;
+ if (!Utf8toWStr(utf8str, wstr))
+ return false;
+
+ conStr.resize(wstr.size());
+ CharToOemBuffW(&wstr[0], &conStr[0], wstr.size());
+#else
+ // not implemented yet
+ conStr = utf8str;
+#endif
+
+ return true;
+}
+
+bool consoleToUtf8(const std::string& conStr, std::string& utf8str)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+ std::wstring wstr;
+ wstr.resize(conStr.size());
+ OemToCharBuffW(&conStr[0], &wstr[0], conStr.size());
+
+ return WStrToUtf8(wstr, utf8str);
+#else
+ // not implemented yet
+ utf8str = conStr;
+ return true;
+#endif
+}
+
+bool Utf8FitTo(const std::string& str, std::wstring const& search)
+{
+ std::wstring temp;
+
+ if (!Utf8toWStr(str, temp))
+ return false;
+
+ // converting to lower case
+ wstrToLower( temp );
+
+ if (temp.find(search) == std::wstring::npos)
+ return false;
+
+ return true;
+}
+
+void utf8printf(FILE* out, const char *str, ...)
+{
+ va_list ap;
+ va_start(ap, str);
+ vutf8printf(out, str, &ap);
+ va_end(ap);
+}
+
+void vutf8printf(FILE* out, const char *str, va_list* ap)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+ char temp_buf[32*1024];
+ wchar_t wtemp_buf[32*1024];
+
+ size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap);
+ //vsnprintf returns -1 if the buffer is too small
+ if (temp_len == size_t(-1))
+ temp_len = 32*1024-1;
+
+ size_t wtemp_len = 32*1024-1;
+ Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
+
+ CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1);
+ fprintf(out, "%s", temp_buf);
+#else
+ vfprintf(out, str, *ap);
+#endif
+}
+
+std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */)
+{
+ int32 init = 0;
+ int32 end = arrayLen;
+ int8 op = 1;
+
+ if (reverse)
+ {
+ init = arrayLen - 1;
+ end = -1;
+ op = -1;
+ }
+
+ std::ostringstream ss;
+ for (int32 i = init; i != end; i += op)
+ {
+ char buffer[4];
+ sprintf(buffer, "%02X", bytes[i]);
+ ss << buffer;
+ }
+
+ return ss.str();
+}
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
new file mode 100644
index 00000000000..b748e83408b
--- /dev/null
+++ b/src/common/Utilities/Util.h
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include "Define.h"
+#include "Errors.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+
+// Searcher for map of structs
+template<typename T, class S> struct Finder
+{
+ T val_;
+ T S::* idMember_;
+
+ Finder(T val, T S::* idMember) : val_(val), idMember_(idMember) {}
+ bool operator()(const std::pair<int, S> &obj) { return obj.second.*idMember_ == val_; }
+};
+
+class Tokenizer
+{
+public:
+ typedef std::vector<char const*> StorageType;
+
+ typedef StorageType::size_type size_type;
+
+ typedef StorageType::const_iterator const_iterator;
+ typedef StorageType::reference reference;
+ typedef StorageType::const_reference const_reference;
+
+public:
+ Tokenizer(const std::string &src, char const sep, uint32 vectorReserve = 0);
+ ~Tokenizer() { delete[] m_str; }
+
+ const_iterator begin() const { return m_storage.begin(); }
+ const_iterator end() const { return m_storage.end(); }
+
+ size_type size() const { return m_storage.size(); }
+
+ reference operator [] (size_type i) { return m_storage[i]; }
+ const_reference operator [] (size_type i) const { return m_storage[i]; }
+
+private:
+ char* m_str;
+ StorageType m_storage;
+};
+
+void stripLineInvisibleChars(std::string &src);
+
+int32 MoneyStringToMoney(const std::string& moneyString);
+
+struct tm* localtime_r(const time_t* time, struct tm *result);
+
+std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false);
+uint32 TimeStringToSecs(const std::string& timestring);
+std::string TimeToTimestampStr(time_t t);
+
+/* Return a random number in the range min..max. */
+int32 irand(int32 min, int32 max);
+
+/* Return a random number in the range min..max (inclusive). */
+uint32 urand(uint32 min, uint32 max);
+
+/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */
+uint32 urandms(uint32 min, uint32 max);
+
+/* Return a random number in the range 0 .. UINT32_MAX. */
+uint32 rand32();
+
+/* Return a random number in the range min..max */
+float frand(float min, float max);
+
+/* Return a random double from 0.0 to 1.0 (exclusive). */
+double rand_norm();
+
+/* Return a random double from 0.0 to 100.0 (exclusive). */
+double rand_chance();
+
+/* Return true if a random roll fits in the specified chance (range 0-100). */
+inline bool roll_chance_f(float chance)
+{
+ return chance > rand_chance();
+}
+
+/* Return true if a random roll fits in the specified chance (range 0-100). */
+inline bool roll_chance_i(int chance)
+{
+ return chance > irand(0, 99);
+}
+
+inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
+{
+ if (val == -100.0f) // prevent set var to zero
+ val = -99.99f;
+ var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
+}
+
+// Percentage calculation
+template <class T, class U>
+inline T CalculatePct(T base, U pct)
+{
+ return T(base * static_cast<float>(pct) / 100.0f);
+}
+
+template <class T, class U>
+inline T AddPct(T &base, U pct)
+{
+ return base += CalculatePct(base, pct);
+}
+
+template <class T, class U>
+inline T ApplyPct(T &base, U pct)
+{
+ return base = CalculatePct(base, pct);
+}
+
+template <class T>
+inline T RoundToInterval(T& num, T floor, T ceil)
+{
+ return num = std::min(std::max(num, floor), ceil);
+}
+
+// UTF8 handling
+bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr);
+// in wsize==max size of buffer, out wsize==real string size
+bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize);
+inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize)
+{
+ return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize);
+}
+
+bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str);
+// size==real string size
+bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str);
+
+size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence
+void utf8truncate(std::string& utf8str, size_t len);
+
+inline bool isBasicLatinCharacter(wchar_t wchar)
+{
+ if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
+ return true;
+ if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
+ return true;
+ return false;
+}
+
+inline bool isExtendedLatinCharacter(wchar_t wchar)
+{
+ if (isBasicLatinCharacter(wchar))
+ return true;
+ if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
+ return true;
+ if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
+ return true;
+ if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
+ return true;
+ if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
+ return true;
+ if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
+ return true;
+ if (wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
+ return true;
+ if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
+ return true;
+ return false;
+}
+
+inline bool isCyrillicCharacter(wchar_t wchar)
+{
+ if (wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
+ return true;
+ if (wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
+ return true;
+ return false;
+}
+
+inline bool isEastAsianCharacter(wchar_t wchar)
+{
+ if (wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo
+ return true;
+ if (wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana
+ return true;
+ if (wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo
+ return true;
+ if (wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext.
+ return true;
+ if (wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A
+ return true;
+ if (wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs
+ return true;
+ if (wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables
+ return true;
+ if (wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms
+ return true;
+ return false;
+}
+
+inline bool isNumeric(wchar_t wchar)
+{
+ return (wchar >= L'0' && wchar <=L'9');
+}
+
+inline bool isNumeric(char c)
+{
+ return (c >= '0' && c <='9');
+}
+
+inline bool isNumeric(char const* str)
+{
+ for (char const* c = str; *c; ++c)
+ if (!isNumeric(*c))
+ return false;
+
+ return true;
+}
+
+inline bool isNumericOrSpace(wchar_t wchar)
+{
+ return isNumeric(wchar) || wchar == L' ';
+}
+
+inline bool isBasicLatinString(const std::wstring &wstr, bool numericOrSpace)
+{
+ for (size_t i = 0; i < wstr.size(); ++i)
+ if (!isBasicLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+ return false;
+ return true;
+}
+
+inline bool isExtendedLatinString(const std::wstring &wstr, bool numericOrSpace)
+{
+ for (size_t i = 0; i < wstr.size(); ++i)
+ if (!isExtendedLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+ return false;
+ return true;
+}
+
+inline bool isCyrillicString(const std::wstring &wstr, bool numericOrSpace)
+{
+ for (size_t i = 0; i < wstr.size(); ++i)
+ if (!isCyrillicCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+ return false;
+ return true;
+}
+
+inline bool isEastAsianString(const std::wstring &wstr, bool numericOrSpace)
+{
+ for (size_t i = 0; i < wstr.size(); ++i)
+ if (!isEastAsianCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+ return false;
+ return true;
+}
+
+inline wchar_t wcharToUpper(wchar_t wchar)
+{
+ if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
+ return wchar_t(uint16(wchar)-0x0020);
+ if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
+ return wchar_t(0x1E9E);
+ if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
+ return wchar_t(uint16(wchar)-0x0020);
+ if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
+ return wchar_t(uint16(wchar)-0x0020);
+ if (wchar >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
+ {
+ if (wchar % 2 == 1)
+ return wchar_t(uint16(wchar)-0x0001);
+ }
+ if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
+ return wchar_t(uint16(wchar)-0x0020);
+ if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
+ return wchar_t(0x0401);
+
+ return wchar;
+}
+
+inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
+{
+ return isBasicLatinCharacter(wchar) ? wcharToUpper(wchar) : wchar;
+}
+
+inline wchar_t wcharToLower(wchar_t wchar)
+{
+ if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
+ return wchar_t(uint16(wchar)+0x0020);
+ if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
+ return wchar_t(uint16(wchar)+0x0020);
+ if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
+ return wchar_t(uint16(wchar)+0x0020);
+ if (wchar >= 0x0100 && wchar <= 0x012E) // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0)
+ {
+ if (wchar % 2 == 0)
+ return wchar_t(uint16(wchar)+0x0001);
+ }
+ if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
+ return wchar_t(0x00DF);
+ if (wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO
+ return wchar_t(0x0451);
+ if (wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
+ return wchar_t(uint16(wchar)+0x0020);
+
+ return wchar;
+}
+
+inline void wstrToUpper(std::wstring& str)
+{
+ std::transform( str.begin(), str.end(), str.begin(), wcharToUpper );
+}
+
+inline void wstrToLower(std::wstring& str)
+{
+ std::transform( str.begin(), str.end(), str.begin(), wcharToLower );
+}
+
+std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension);
+
+bool utf8ToConsole(const std::string& utf8str, std::string& conStr);
+bool consoleToUtf8(const std::string& conStr, std::string& utf8str);
+bool Utf8FitTo(const std::string& str, std::wstring const& search);
+void utf8printf(FILE* out, const char *str, ...);
+void vutf8printf(FILE* out, const char *str, va_list* ap);
+
+bool IsIPAddress(char const* ipaddress);
+
+uint32 CreatePIDFile(const std::string& filename);
+
+std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
+
+// simple class for not-modifyable list
+template <typename T>
+class HookList
+{
+ typedef typename std::list<T>::iterator ListIterator;
+ private:
+ typename std::list<T> m_list;
+ public:
+ HookList<T> & operator+=(T t)
+ {
+ m_list.push_back(t);
+ return *this;
+ }
+ HookList<T> & operator-=(T t)
+ {
+ m_list.remove(t);
+ return *this;
+ }
+ size_t size()
+ {
+ return m_list.size();
+ }
+ ListIterator begin()
+ {
+ return m_list.begin();
+ }
+ ListIterator end()
+ {
+ return m_list.end();
+ }
+};
+
+class flag96
+{
+private:
+ uint32 part[3];
+
+public:
+ flag96(uint32 p1 = 0, uint32 p2 = 0, uint32 p3 = 0)
+ {
+ part[0] = p1;
+ part[1] = p2;
+ part[2] = p3;
+ }
+
+ inline bool IsEqual(uint32 p1 = 0, uint32 p2 = 0, uint32 p3 = 0) const
+ {
+ return (part[0] == p1 && part[1] == p2 && part[2] == p3);
+ }
+
+ inline bool HasFlag(uint32 p1 = 0, uint32 p2 = 0, uint32 p3 = 0) const
+ {
+ return (part[0] & p1 || part[1] & p2 || part[2] & p3);
+ }
+
+ inline void Set(uint32 p1 = 0, uint32 p2 = 0, uint32 p3 = 0)
+ {
+ part[0] = p1;
+ part[1] = p2;
+ part[2] = p3;
+ }
+
+ inline bool operator <(const flag96 &right) const
+ {
+ for (uint8 i = 3; i > 0; --i)
+ {
+ if (part[i - 1] < right.part[i - 1])
+ return true;
+ else if (part[i - 1] > right.part[i - 1])
+ return false;
+ }
+ return false;
+ }
+
+ inline bool operator ==(const flag96 &right) const
+ {
+ return
+ (
+ part[0] == right.part[0] &&
+ part[1] == right.part[1] &&
+ part[2] == right.part[2]
+ );
+ }
+
+ inline bool operator !=(const flag96 &right) const
+ {
+ return !this->operator ==(right);
+ }
+
+ inline flag96 & operator =(const flag96 &right)
+ {
+ part[0] = right.part[0];
+ part[1] = right.part[1];
+ part[2] = right.part[2];
+ return *this;
+ }
+
+ inline flag96 operator &(const flag96 &right) const
+ {
+ return flag96(part[0] & right.part[0], part[1] & right.part[1],
+ part[2] & right.part[2]);
+ }
+
+ inline flag96 & operator &=(const flag96 &right)
+ {
+ part[0] &= right.part[0];
+ part[1] &= right.part[1];
+ part[2] &= right.part[2];
+ return *this;
+ }
+
+ inline flag96 operator |(const flag96 &right) const
+ {
+ return flag96(part[0] | right.part[0], part[1] | right.part[1],
+ part[2] | right.part[2]);
+ }
+
+ inline flag96 & operator |=(const flag96 &right)
+ {
+ part[0] |= right.part[0];
+ part[1] |= right.part[1];
+ part[2] |= right.part[2];
+ return *this;
+ }
+
+ inline flag96 operator ~() const
+ {
+ return flag96(~part[0], ~part[1], ~part[2]);
+ }
+
+ inline flag96 operator ^(const flag96 &right) const
+ {
+ return flag96(part[0] ^ right.part[0], part[1] ^ right.part[1],
+ part[2] ^ right.part[2]);
+ }
+
+ inline flag96 & operator ^=(const flag96 &right)
+ {
+ part[0] ^= right.part[0];
+ part[1] ^= right.part[1];
+ part[2] ^= right.part[2];
+ return *this;
+ }
+
+ inline operator bool() const
+ {
+ return (part[0] != 0 || part[1] != 0 || part[2] != 0);
+ }
+
+ inline bool operator !() const
+ {
+ return !this->operator bool();
+ }
+
+ inline uint32 & operator [](uint8 el)
+ {
+ return part[el];
+ }
+
+ inline const uint32 & operator [](uint8 el) const
+ {
+ return part[el];
+ }
+};
+
+enum ComparisionType
+{
+ COMP_TYPE_EQ = 0,
+ COMP_TYPE_HIGH,
+ COMP_TYPE_LOW,
+ COMP_TYPE_HIGH_EQ,
+ COMP_TYPE_LOW_EQ,
+ COMP_TYPE_MAX
+};
+
+template <class T>
+bool CompareValues(ComparisionType type, T val1, T val2)
+{
+ switch (type)
+ {
+ case COMP_TYPE_EQ:
+ return val1 == val2;
+ case COMP_TYPE_HIGH:
+ return val1 > val2;
+ case COMP_TYPE_LOW:
+ return val1 < val2;
+ case COMP_TYPE_HIGH_EQ:
+ return val1 >= val2;
+ case COMP_TYPE_LOW_EQ:
+ return val1 <= val2;
+ default:
+ // incorrect parameter
+ ABORT();
+ return false;
+ }
+}
+
+#endif