Eluna fix crash in timed events and prepare some for future changes. Ditched EventProcessor

This commit is contained in:
Rochet2
2014-09-13 16:05:16 +03:00
parent 7be917335a
commit 06be9650bb
12 changed files with 388 additions and 346 deletions

View File

@@ -6,6 +6,7 @@
#include "ElunaEventMgr.h" #include "ElunaEventMgr.h"
#include "LuaEngine.h" #include "LuaEngine.h"
#include "Object.h"
extern "C" extern "C"
{ {
@@ -13,139 +14,131 @@ extern "C"
#include "lauxlib.h" #include "lauxlib.h"
}; };
LuaEvent::LuaEvent(Eluna& _E, EventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls, Object* _obj): LuaEvent::LuaEvent(ElunaEventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls) :
E(_E), events(_events), funcRef(_funcRef), delay(_delay), calls(_calls), obj(_obj) to_Abort(false), events(_events), funcRef(_funcRef), delay(_delay), calls(_calls)
{ {
if (_events)
E.m_EventMgr->LuaEvents[_events].insert(this); // Able to access the event if we have the processor
} }
LuaEvent::~LuaEvent() LuaEvent::~LuaEvent()
{ {
if (events) luaL_unref(sEluna->L, LUA_REGISTRYINDEX, funcRef); // Free lua function ref
{
// Attempt to remove the pointer from LuaEvents
EventMgr::EventMap::const_iterator it = E.m_EventMgr->LuaEvents.find(events); // Get event set
if (it != E.m_EventMgr->LuaEvents.end())
E.m_EventMgr->LuaEvents[events].erase(this);// Remove pointer
}
luaL_unref(E.L, LUA_REGISTRYINDEX, funcRef); // Free lua function ref
} }
bool LuaEvent::Execute(uint64 /*time*/, uint32 /*diff*/) void LuaEvent::Execute()
{ {
bool remove = (calls == 1); // In multithread get map from object and the map's lua state
if (!remove) lua_rawgeti(sEluna->L, LUA_REGISTRYINDEX, funcRef);
events->AddEvent(this, events->CalculateTime(delay)); // Reschedule before calling incase RemoveEvents used Eluna::Push(sEluna->L, funcRef);
lua_rawgeti(E.L, LUA_REGISTRYINDEX, funcRef); Eluna::Push(sEluna->L, delay);
Eluna::Push(E.L, funcRef); Eluna::Push(sEluna->L, calls);
Eluna::Push(E.L, delay); if (calls) // Must be before calling
Eluna::Push(E.L, calls);
if (!remove && calls)
--calls; --calls;
Eluna::Push(E.L, obj); Eluna::Push(sEluna->L, events->obj);
Eluna::ExecuteCall(E.L, 4, 0); Eluna::ExecuteCall(sEluna->L, 4, 0);
return remove; // Destory (true) event if not run
} }
EventMgr::EventMgr(Eluna& _E): E(_E) ElunaEventProcessor::ElunaEventProcessor(WorldObject* _obj) : m_time(0), obj(_obj)
{
// In multithread get the object's map's lua state
Eluna* E = obj ? sEluna : sEluna;
EventMgr::WriteGuard lock(E->eventMgr->GetLock());
E->eventMgr->processors.insert(this);
}
ElunaEventProcessor::~ElunaEventProcessor()
{
RemoveEvents();
// In multithread get the object's map's lua state
Eluna* E = obj ? sEluna : sEluna;
EventMgr::WriteGuard lock(E->eventMgr->GetLock());
E->eventMgr->processors.erase(this);
}
void ElunaEventProcessor::Update(uint32 diff)
{
m_time += diff;
for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin())
{
LuaEvent* event = it->second;
eventList.erase(it);
eventMap.erase(event->funcRef);
if (event->to_Abort)
{
delete event;
continue;
}
bool remove = event->calls == 1;
if (!remove)
AddEvent(event); // Reschedule before calling incase RemoveEvents used
event->Execute();
if (remove)
delete event;
}
}
void ElunaEventProcessor::RemoveEvents()
{
//if (!final)
//{
// for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
// it->second->to_Abort = true;
// return;
//}
for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
delete it->second;
eventList.clear();
eventMap.clear();
}
void ElunaEventProcessor::RemoveEvent(int eventId)
{
if (eventMap.find(eventId) != eventMap.end())
eventMap[eventId]->to_Abort = true;
}
void ElunaEventProcessor::AddEvent(LuaEvent* event)
{
eventList.insert(std::pair<uint64, LuaEvent*>(m_time + event->delay, event));
eventMap[event->funcRef] = event;
}
void ElunaEventProcessor::AddEvent(int funcRef, uint32 delay, uint32 repeats)
{
AddEvent(new LuaEvent(this, funcRef, delay, repeats));
}
EventMgr::EventMgr() : globalProcessor(NULL)
{ {
} }
EventMgr::~EventMgr() EventMgr::~EventMgr()
{ {
RemoveEvents(); RemoveEvents();
delete globalProcessor;
} }
void EventMgr::Update(uint32 diff)
{
GlobalEvents.Update(diff);
}
/*
void EventMgr::KillAllEvents(EventProcessor* events)
{
if (!events)
return;
if (LuaEvents.empty())
return;
EventMap::const_iterator it = LuaEvents.find(events); // Get event set
if (it == LuaEvents.end())
return;
if (it->second.empty())
return;
for (EventSet::const_iterator itr = it->second.begin(); itr != it->second.end();) // Loop events
(*(itr++))->to_Abort = true; // Abort event
}
*/
void EventMgr::RemoveEvents() void EventMgr::RemoveEvents()
{ {
if (!LuaEvents.empty()) ReadGuard lock(GetLock());
for (EventMap::const_iterator it = LuaEvents.begin(); it != LuaEvents.end();) // loop processors if (!processors.empty())
(it++)->first->KillAllEvents(false); // KillAllEvents((it++)->first); for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
LuaEvents.clear(); // remove pointers (*it)->RemoveEvents();
// This is handled automatically on delete globalProcessor->RemoveEvents();
// for (ProcessorMap::iterator it = Processors.begin(); it != Processors.end();)
// (it++)->second.KillAllEvents(true);
// Processors.clear(); // remove guid saved processors
GlobalEvents.KillAllEvents(true);
}
void EventMgr::RemoveEvents(EventProcessor* events)
{
if (!events)
return;
// KillAllEvents(events);
events->KillAllEvents(false);
LuaEvents.erase(events); // remove pointer set
}
int EventMgr::AddEvent(EventProcessor* events, int funcRef, uint32 delay, uint32 calls, Object* obj)
{
if (!events || funcRef <= 0) // If funcRef <= 0, function reference failed
return 0; // on fail always return 0. funcRef can be negative.
events->AddEvent(new LuaEvent(E, events, funcRef, delay, calls, obj), events->CalculateTime(delay));
return funcRef; // return the event ID
}
LuaEvent* EventMgr::GetEvent(EventProcessor* events, int eventId)
{
if (!events || !eventId)
return NULL;
if (LuaEvents.empty())
return NULL;
EventMap::const_iterator it = LuaEvents.find(events); // Get event set
if (it == LuaEvents.end())
return NULL;
if (it->second.empty())
return NULL;
for (EventSet::const_iterator itr = it->second.begin(); itr != it->second.end(); ++itr) // Loop events
if ((*itr) && (*itr)->funcRef == eventId) // Check if the event has our ID
return *itr; // Return the event if found
return NULL;
}
bool EventMgr::RemoveEvent(EventProcessor* events, int eventId)
{
// eventId = funcRef
if (!events || !eventId)
return false;
LuaEvent* luaEvent = GetEvent(events, eventId);
if (!luaEvent)
return false;
luaEvent->to_Abort = true; // Set to remove on next call
LuaEvents[events].erase(luaEvent); // Remove pointer
return true;
} }
void EventMgr::RemoveEvent(int eventId) void EventMgr::RemoveEvent(int eventId)
{ {
if (!eventId) ReadGuard lock(GetLock());
return; if (!processors.empty())
if (LuaEvents.empty()) for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
return; (*it)->RemoveEvent(eventId);
for (EventMap::const_iterator it = LuaEvents.begin(); it != LuaEvents.end();) // loop processors globalProcessor->RemoveEvent(eventId);
if (RemoveEvent((it++)->first, eventId))
break; // succesfully remove the event, stop loop.
} }

View File

@@ -7,75 +7,82 @@
#ifndef _ELUNA_EVENT_MGR_H #ifndef _ELUNA_EVENT_MGR_H
#define _ELUNA_EVENT_MGR_H #define _ELUNA_EVENT_MGR_H
#include "ElunaUtility.h"
#include "Common.h" #include "Common.h"
#include <map>
#ifdef TRINITY #ifdef TRINITY
#include "EventProcessor.h" #include "Define.h"
#else #else
#include "Utilities/EventProcessor.h" #include "Platform/Define.h"
#endif #endif
class Eluna;
class EventMgr; class EventMgr;
class EventProcessor; class ElunaEventProcessor;
class Object; class WorldObject;
class LuaEvent : public BasicEvent class LuaEvent
{ {
friend class EventMgr; friend class EventMgr;
friend class ElunaEventProcessor;
public: public:
LuaEvent(Eluna& _E, EventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls, Object* _obj);
~LuaEvent();
// Should never execute on dead events // Should never execute on dead events
bool Execute(uint64 time, uint32 diff); void Execute();
bool to_Abort;
private: private:
Eluna& E; LuaEvent(ElunaEventProcessor* _events, int _funcRef, uint32 _delay, uint32 _calls);
EventProcessor* events; // Pointer to events (holds the timed event) ~LuaEvent();
ElunaEventProcessor* events; // Pointer to events (holds the timed event)
int funcRef; // Lua function reference ID, also used as event ID int funcRef; // Lua function reference ID, also used as event ID
uint32 delay; // Delay between event calls uint32 delay; // Delay between event calls
uint32 calls; // Amount of calls to make, 0 for infinite uint32 calls; // Amount of calls to make, 0 for infinite
Object* obj; // Object to push
}; };
class EventMgr class ElunaEventProcessor
{
friend class LuaEvent;
public:
typedef std::multimap<uint64, LuaEvent*> EventList;
typedef UNORDERED_MAP<int, LuaEvent*> EventMap;
ElunaEventProcessor(WorldObject* _obj);
~ElunaEventProcessor();
void Update(uint32 diff);
// instantly removes all timed events
void RemoveEvents();
// set the event to be removed when executing
void RemoveEvent(int eventId);
void AddEvent(int funcRef, uint32 delay, uint32 repeats);
EventMap eventMap;
private:
void AddEvent(LuaEvent* Event);
EventList eventList;
uint64 m_time;
WorldObject* obj;
};
class EventMgr : public ElunaUtil::RWLockable
{ {
public: public:
typedef std::set<LuaEvent*> EventSet; typedef UNORDERED_SET<ElunaEventProcessor*> ProcessorSet;
typedef std::map<EventProcessor*, EventSet> EventMap; ProcessorSet processors;
Eluna& E; ElunaEventProcessor* globalProcessor;
EventMap LuaEvents; // LuaEvents[processor] = {LuaEvent, LuaEvent...} EventMgr();
EventProcessor GlobalEvents;
EventMgr(Eluna& _E);
~EventMgr(); ~EventMgr();
// Should be run on world tick
void Update(uint32 diff);
// Aborts all lua events
// void KillAllEvents(EventProcessor* events);
// Remove all timed events // Remove all timed events
// Execute only in safe env
void RemoveEvents(); void RemoveEvents();
// Remove timed events from processor
void RemoveEvents(EventProcessor* events);
// Adds a new event to the processor and returns the eventID or 0 (Never negative)
int AddEvent(EventProcessor* events, int funcRef, uint32 delay, uint32 calls, Object* obj = NULL);
// Finds the event that has the ID from events
LuaEvent* GetEvent(EventProcessor* events, int eventId);
// Remove the event with the eventId from processor
// Returns true if event is removed
// EventId is func ref
bool RemoveEvent(EventProcessor* events, int eventId);
// Removes the eventId from all events // Removes the eventId from all events
// Execute only in safe env
void RemoveEvent(int eventId); void RemoveEvent(int eventId);
}; };

View File

@@ -120,3 +120,9 @@ enum SelectAggroTarget
SELECT_TARGET_FARTHEST SELECT_TARGET_FARTHEST
}; };
#endif #endif
// Some dummy includes containing BOOST_VERSION:
// ObjectAccessor.h Config.h Log.h
#ifdef BOOST_VERSION
#define USING_BOOST
#endif

View File

@@ -43,6 +43,9 @@ typedef uint64 ObjectGuid;
#ifndef UNORDERED_MAP #ifndef UNORDERED_MAP
#define UNORDERED_MAP std::unordered_map #define UNORDERED_MAP std::unordered_map
#endif #endif
#ifndef UNORDERED_SET
#define UNORDERED_ET std::unordered_set
#endif
class Unit; class Unit;
class WorldObject; class WorldObject;
@@ -91,6 +94,35 @@ namespace ElunaUtil
WorldObjectInRangeCheck(WorldObjectInRangeCheck const&); WorldObjectInRangeCheck(WorldObjectInRangeCheck const&);
}; };
/*
* Usage:
* Inherit this class, then when needing lock, use
* ReadGuard lock(_lock);
* or
* WriteGuard lock(_lock);
*
* The lock is automatically released at end of scope
*/
class RWLockable
{
public:
#ifdef USING_BOOST
typedef boost::shared_mutex LockType;
typedef boost::shared_lock<boost::shared_mutex> ReadGuard;
typedef boost::unique_lock<boost::shared_mutex> WriteGuard;
#else
typedef ACE_RW_Thread_Mutex LockType;
typedef ACE_Read_Guard<LockType> ReadGuard;
typedef ACE_Write_Guard<LockType> WriteGuard;
#endif
LockType& GetLock() { return _lock; }
private:
LockType _lock;
};
}; };
#endif #endif

View File

@@ -204,50 +204,6 @@ namespace LuaGameObject
return 0; return 0;
} }
/**
* Registers a timed event to the [GameObject]
*
* @param function function : function to trigger when the time has passed
* @param uint32 delay : set time in milliseconds for the event to trigger
* @param uint32 repeats : how many times for the event to repeat, 0 is infinite
* @return int32 eventId : unique ID for the timed event used to cancel it
*/
int RegisterEvent(lua_State* L, GameObject* go)
{
luaL_checktype(L, 2, LUA_TFUNCTION);
uint32 delay = Eluna::CHECKVAL<uint32>(L, 3);
uint32 repeats = Eluna::CHECKVAL<uint32>(L, 4);
lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
functionRef = sEluna->m_EventMgr->AddEvent(&go->m_Events, functionRef, delay, repeats, go);
if (functionRef)
Eluna::Push(L, functionRef);
return 1;
}
/**
* Removes the timed event from a [GameObject] by the specified event ID
*
* @param int32 eventId : event Id to remove
*/
int RemoveEventById(lua_State* L, GameObject* go)
{
int eventId = Eluna::CHECKVAL<int>(L, 2);
sEluna->m_EventMgr->RemoveEvent(&go->m_Events, eventId);
return 0;
}
/**
* Removes all timed events from a [GameObject]
*
*/
int RemoveEvents(lua_State* /*L*/, GameObject* go)
{
sEluna->m_EventMgr->RemoveEvents(&go->m_Events);
return 0;
}
/** /**
* Changes uses a door or a button type [GameObject] * Changes uses a door or a button type [GameObject]
* *

View File

@@ -692,6 +692,16 @@ namespace LuaGlobalFunctions
return 0; return 0;
} }
/**
* Registers a global timed event
* When the passed function is called, the parameters `(eventId, delay, repeats)` are passed to it.
* Repeats will decrease on each call if the event does not repeat indefinitely
*
* @param function function : function to trigger when the time has passed
* @param uint32 delay : set time in milliseconds for the event to trigger
* @param uint32 repeats : how many times for the event to repeat, 0 is infinite
* @return int eventId : unique ID for the timed event used to cancel it or nil
*/
int CreateLuaEvent(lua_State* L) int CreateLuaEvent(lua_State* L)
{ {
luaL_checktype(L, 1, LUA_TFUNCTION); luaL_checktype(L, 1, LUA_TFUNCTION);
@@ -700,34 +710,47 @@ namespace LuaGlobalFunctions
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
functionRef = sEluna->m_EventMgr->AddEvent(&sEluna->m_EventMgr->GlobalEvents, functionRef, delay, repeats); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF)
if (functionRef) {
sEluna->eventMgr->globalProcessor->AddEvent(functionRef, delay, repeats);
Eluna::Push(L, functionRef); Eluna::Push(L, functionRef);
else }
Eluna::Push(L);
return 1; return 1;
} }
/**
* Removes a global timed event specified by the event ID
*
* @param int eventId : event Id to remove
* @param bool all_Events = false : remove from all events, not just global
*/
int RemoveEventById(lua_State* L) int RemoveEventById(lua_State* L)
{ {
int eventId = Eluna::CHECKVAL<int>(L, 1); int eventId = Eluna::CHECKVAL<int>(L, 1);
bool all_Events = Eluna::CHECKVAL<bool>(L, 1, false); bool all_Events = Eluna::CHECKVAL<bool>(L, 1, false);
// not thread safe
if (all_Events) if (all_Events)
sEluna->m_EventMgr->RemoveEvent(eventId); sEluna->eventMgr->RemoveEvent(eventId);
else else
sEluna->m_EventMgr->RemoveEvent(&sEluna->m_EventMgr->GlobalEvents, eventId); sEluna->eventMgr->globalProcessor->RemoveEvent(eventId);
return 0; return 0;
} }
/**
* Removes all global timed events
*
* @param bool all_Events = false : remove all events, not just global
*/
int RemoveEvents(lua_State* L) int RemoveEvents(lua_State* L)
{ {
bool all_Events = Eluna::CHECKVAL<bool>(L, 1, false); bool all_Events = Eluna::CHECKVAL<bool>(L, 1, false);
// not thread safe
if (all_Events) if (all_Events)
sEluna->m_EventMgr->RemoveEvents(); sEluna->eventMgr->RemoveEvents();
else else
sEluna->m_EventMgr->GlobalEvents.KillAllEvents(true); sEluna->eventMgr->globalProcessor->RemoveEvents();
return 0; return 0;
} }
@@ -1153,25 +1176,25 @@ namespace LuaGlobalFunctions
switch (banMode) switch (banMode)
{ {
case BAN_ACCOUNT: case BAN_ACCOUNT:
#ifdef CATA #ifdef CATA
if (!Utf8ToUpperOnlyLatin(nameOrIP)) if (!Utf8ToUpperOnlyLatin(nameOrIP))
return 0; return 0;
#else #else
if (!AccountMgr::normalizeString(nameOrIP)) if (!AccountMgr::normalizeString(nameOrIP))
return 0; return 0;
#endif #endif
break; break;
case BAN_CHARACTER: case BAN_CHARACTER:
if (!normalizePlayerName(nameOrIP)) if (!normalizePlayerName(nameOrIP))
return 0;
break;
case BAN_IP:
if (!IsIPAddress(nameOrIP.c_str()))
return 0;
break;
default:
return 0; return 0;
break;
case BAN_IP:
if (!IsIPAddress(nameOrIP.c_str()))
return 0;
break;
default:
return 0;
} }
eWorld->BanAccount((BanMode)banMode, nameOrIP, duration, reason, whoBanned); eWorld->BanAccount((BanMode)banMode, nameOrIP, duration, reason, whoBanned);

View File

@@ -341,13 +341,14 @@ void Eluna::OnShutdownCancel()
void Eluna::OnWorldUpdate(uint32 diff) void Eluna::OnWorldUpdate(uint32 diff)
{ {
eventMgr->globalProcessor->Update(diff);
if (reload) if (reload)
{ {
ReloadEluna(); ReloadEluna();
return; return;
} }
m_EventMgr->Update(diff);
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_UPDATE, return); EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_UPDATE, return);
Push(L, diff); Push(L, diff);
EVENT_EXECUTE(0); EVENT_EXECUTE(0);
@@ -1834,6 +1835,7 @@ bool Eluna::OnQuestComplete(Player* pPlayer, GameObject* pGameObject, Quest cons
void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff)
{ {
pGameObject->elunaEvents.Update(diff);
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_AIUPDATE, return); ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_AIUPDATE, return);
Push(L, pGameObject); Push(L, pGameObject);
Push(L, diff); Push(L, diff);

View File

@@ -12,9 +12,7 @@
#include "ElunaTemplate.h" #include "ElunaTemplate.h"
#include "ElunaUtility.h" #include "ElunaUtility.h"
// Some dummy includes containing BOOST_VERSION: #ifdef USING_BOOST
// ObjectAccessor.h Config.h Log.h
#ifdef BOOST_VERSION
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#else #else
#include <ace/ACE.h> #include <ace/ACE.h>
@@ -89,7 +87,7 @@ void Eluna::ReloadEluna()
Eluna::Eluna(): Eluna::Eluna():
L(luaL_newstate()), L(luaL_newstate()),
m_EventMgr(new EventMgr(*this)), eventMgr(NULL),
ServerEventBindings(new EventBind<HookMgr::ServerEvents>("ServerEvents", *this)), ServerEventBindings(new EventBind<HookMgr::ServerEvents>("ServerEvents", *this)),
PlayerEventBindings(new EventBind<HookMgr::PlayerEvents>("PlayerEvents", *this)), PlayerEventBindings(new EventBind<HookMgr::PlayerEvents>("PlayerEvents", *this)),
@@ -122,6 +120,10 @@ playerGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (player)
ASSERT(!Eluna::GEluna); ASSERT(!Eluna::GEluna);
Eluna::GEluna = this; Eluna::GEluna = this;
// Set event manager. Must be after setting sEluna
eventMgr = new EventMgr();
eventMgr->globalProcessor = new ElunaEventProcessor(NULL);
// run scripts // run scripts
RunScripts(); RunScripts();
@@ -132,7 +134,7 @@ Eluna::~Eluna()
{ {
OnLuaStateClose(); OnLuaStateClose();
delete m_EventMgr; delete eventMgr;
// Replace this with map remove if making multithread version // Replace this with map remove if making multithread version
Eluna::GEluna = NULL; Eluna::GEluna = NULL;
@@ -190,7 +192,7 @@ void Eluna::GetScripts(std::string path, ScriptList& scripts)
{ {
ELUNA_LOG_DEBUG("[Eluna]: GetScripts from path `%s`", path.c_str()); ELUNA_LOG_DEBUG("[Eluna]: GetScripts from path `%s`", path.c_str());
#ifdef BOOST_VERSION #ifdef USING_BOOST
boost::filesystem::path someDir(path); boost::filesystem::path someDir(path);
boost::filesystem::directory_iterator end_iter; boost::filesystem::directory_iterator end_iter;

View File

@@ -108,7 +108,7 @@ public:
lua_State* L; lua_State* L;
int userdata_table; int userdata_table;
EventMgr* m_EventMgr; EventMgr* eventMgr;
EventBind<HookMgr::ServerEvents>* ServerEventBindings; EventBind<HookMgr::ServerEvents>* ServerEventBindings;
EventBind<HookMgr::PlayerEvents>* PlayerEventBindings; EventBind<HookMgr::PlayerEvents>* PlayerEventBindings;

View File

@@ -192,6 +192,9 @@ ElunaRegister<WorldObject> WorldObjectMethods[] =
{ "SummonGameObject", &LuaWorldObject::SummonGameObject }, // :SummonGameObject(entry, x, y, z, o[, respawnDelay]) - Spawns an object to location. Returns the object or nil { "SummonGameObject", &LuaWorldObject::SummonGameObject }, // :SummonGameObject(entry, x, y, z, o[, respawnDelay]) - Spawns an object to location. Returns the object or nil
{ "SpawnCreature", &LuaWorldObject::SpawnCreature }, // :SpawnCreature(entry, x, y, z, o[, spawnType, despawnDelay]) - Spawns a creature to location that despawns after given time (0 for infinite). Returns the creature or nil { "SpawnCreature", &LuaWorldObject::SpawnCreature }, // :SpawnCreature(entry, x, y, z, o[, spawnType, despawnDelay]) - Spawns a creature to location that despawns after given time (0 for infinite). Returns the creature or nil
{ "SendPacket", &LuaWorldObject::SendPacket }, // :SendPacket(packet) - Sends a specified packet to everyone around { "SendPacket", &LuaWorldObject::SendPacket }, // :SendPacket(packet) - Sends a specified packet to everyone around
{ "RegisterEvent", &LuaWorldObject::RegisterEvent },
{ "RemoveEventById", &LuaWorldObject::RemoveEventById },
{ "RemoveEvents", &LuaWorldObject::RemoveEvents },
{ NULL, NULL }, { NULL, NULL },
}; };
@@ -321,7 +324,7 @@ ElunaRegister<Unit> UnitMethods[] =
{ "IsInAccessiblePlaceFor", &LuaUnit::IsInAccessiblePlaceFor }, // :IsInAccessiblePlaceFor(creature) - Returns if the unit is in an accessible place for the specified creature { "IsInAccessiblePlaceFor", &LuaUnit::IsInAccessiblePlaceFor }, // :IsInAccessiblePlaceFor(creature) - Returns if the unit is in an accessible place for the specified creature
{ "IsVendor", &LuaUnit::IsVendor }, // :IsVendor() - Returns if the unit is a vendor or not { "IsVendor", &LuaUnit::IsVendor }, // :IsVendor() - Returns if the unit is a vendor or not
{ "IsWithinLoS", &LuaUnit::IsWithinLoS }, // :IsWithinLoS(x, y, z) { "IsWithinLoS", &LuaUnit::IsWithinLoS }, // :IsWithinLoS(x, y, z)
{"IsRooted", &LuaUnit::IsRooted}, // :IsRooted() { "IsRooted", &LuaUnit::IsRooted }, // :IsRooted()
{ "IsFullHealth", &LuaUnit::IsFullHealth }, // :IsFullHealth() - Returns if the unit is full health { "IsFullHealth", &LuaUnit::IsFullHealth }, // :IsFullHealth() - Returns if the unit is full health
{ "HasAura", &LuaUnit::HasAura }, // :HasAura(spellId) - Returns true if the unit has the aura from the spell { "HasAura", &LuaUnit::HasAura }, // :HasAura(spellId) - Returns true if the unit has the aura from the spell
{ "IsStandState", &LuaUnit::IsStandState }, // :IsStandState() - Returns true if the unit is standing { "IsStandState", &LuaUnit::IsStandState }, // :IsStandState() - Returns true if the unit is standing
@@ -330,9 +333,6 @@ ElunaRegister<Unit> UnitMethods[] =
#endif #endif
// Other // Other
{ "RegisterEvent", &LuaUnit::RegisterEvent }, // :RegisterEvent(function, delay, repeats) - The timer ticks if this unit is visible to someone. The function is called with arguments (eventid, delay, repeats, unit) after the time has passed if the unit exists. Returns EventId
{ "RemoveEventById", &LuaUnit::RemoveEventById }, // :RemoveEventById(eventID) - Removes a Registered (timed) event by it's ID.
{ "RemoveEvents", &LuaUnit::RemoveEvents }, // :RemoveEvents() - Removes all registered timed events
{ "AddAura", &LuaUnit::AddAura }, // :AddAura(spellId, target) - Adds an aura to the specified target { "AddAura", &LuaUnit::AddAura }, // :AddAura(spellId, target) - Adds an aura to the specified target
{ "RemoveAura", &LuaUnit::RemoveAura }, // :RemoveAura(spellId[, casterGUID]) - Removes an aura from the unit by the spellId, casterGUID(Original caster) is optional { "RemoveAura", &LuaUnit::RemoveAura }, // :RemoveAura(spellId[, casterGUID]) - Removes an aura from the unit by the spellId, casterGUID(Original caster) is optional
{ "RemoveAllAuras", &LuaUnit::RemoveAllAuras }, // :RemoveAllAuras() - Removes all the unit's auras { "RemoveAllAuras", &LuaUnit::RemoveAllAuras }, // :RemoveAllAuras() - Removes all the unit's auras
@@ -826,9 +826,6 @@ ElunaRegister<GameObject> GameObjectMethods[] =
{ "IsSpawned", &LuaGameObject::IsSpawned }, { "IsSpawned", &LuaGameObject::IsSpawned },
// Other // Other
{ "RegisterEvent", &LuaGameObject::RegisterEvent },
{ "RemoveEventById", &LuaGameObject::RemoveEventById },
{ "RemoveEvents", &LuaGameObject::RemoveEvents },
{ "RemoveFromWorld", &LuaGameObject::RemoveFromWorld }, { "RemoveFromWorld", &LuaGameObject::RemoveFromWorld },
{ "UseDoorOrButton", &LuaGameObject::UseDoorOrButton }, { "UseDoorOrButton", &LuaGameObject::UseDoorOrButton },
{ "Despawn", &LuaGameObject::Despawn }, { "Despawn", &LuaGameObject::Despawn },

View File

@@ -656,39 +656,39 @@ namespace LuaUnit
const char* str = NULL; const char* str = NULL;
switch (unit->getClass()) switch (unit->getClass())
{ {
case 1: case 1:
str = "Warrior"; str = "Warrior";
break; break;
case 2: case 2:
str = "Paladin"; str = "Paladin";
break; break;
case 3: case 3:
str = "Hunter"; str = "Hunter";
break; break;
case 4: case 4:
str = "Rogue"; str = "Rogue";
break; break;
case 5: case 5:
str = "Priest"; str = "Priest";
break; break;
case 6: case 6:
str = "Death Knight"; str = "Death Knight";
break; break;
case 7: case 7:
str = "Shaman"; str = "Shaman";
break; break;
case 8: case 8:
str = "Mage"; str = "Mage";
break; break;
case 9: case 9:
str = "Warlock"; str = "Warlock";
break; break;
case 11: case 11:
str = "Druid"; str = "Druid";
break; break;
default: default:
str = NULL; str = NULL;
break; break;
} }
Eluna::Push(L, str); Eluna::Push(L, str);
@@ -1422,20 +1422,20 @@ namespace LuaUnit
bool delayed = Eluna::CHECKVAL<bool>(L, 3, true); bool delayed = Eluna::CHECKVAL<bool>(L, 3, true);
switch (spellType) switch (spellType)
{ {
case 0: case 0:
spellType = CURRENT_MELEE_SPELL; spellType = CURRENT_MELEE_SPELL;
break; break;
case 1: case 1:
spellType = CURRENT_GENERIC_SPELL; spellType = CURRENT_GENERIC_SPELL;
break; break;
case 2: case 2:
spellType = CURRENT_CHANNELED_SPELL; spellType = CURRENT_CHANNELED_SPELL;
break; break;
case 3: case 3:
spellType = CURRENT_AUTOREPEAT_SPELL; spellType = CURRENT_AUTOREPEAT_SPELL;
break; break;
default: default:
return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); return luaL_argerror(L, 2, "valid CurrentSpellTypes expected");
} }
unit->InterruptSpell((CurrentSpellTypes)spellType, delayed); unit->InterruptSpell((CurrentSpellTypes)spellType, delayed);
@@ -1461,8 +1461,8 @@ namespace LuaUnit
uint8 eff = spellInfo->Effect[i]; uint8 eff = spellInfo->Effect[i];
if (eff >= TOTAL_SPELL_EFFECTS) if (eff >= TOTAL_SPELL_EFFECTS)
continue; continue;
if (IsAreaAuraEffect(eff) || if (IsAreaAuraEffect(eff) ||
eff == SPELL_EFFECT_APPLY_AURA || eff == SPELL_EFFECT_APPLY_AURA ||
eff == SPELL_EFFECT_PERSISTENT_AREA_AURA) eff == SPELL_EFFECT_PERSISTENT_AREA_AURA)
{ {
Aura* aur = CreateAura(spellInfo, SpellEffIndex(i), NULL, holder, target); Aura* aur = CreateAura(spellInfo, SpellEffIndex(i), NULL, holder, target);
@@ -1517,33 +1517,6 @@ namespace LuaUnit
return 0; return 0;
} }
int RegisterEvent(lua_State* L, Unit* unit)
{
luaL_checktype(L, 2, LUA_TFUNCTION);
uint32 delay = Eluna::CHECKVAL<uint32>(L, 3);
uint32 repeats = Eluna::CHECKVAL<uint32>(L, 4);
lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
functionRef = sEluna->m_EventMgr->AddEvent(&unit->m_Events, functionRef, delay, repeats, unit);
if (functionRef)
Eluna::Push(L, functionRef);
return 1;
}
int RemoveEventById(lua_State* L, Unit* unit)
{
int eventId = Eluna::CHECKVAL<int>(L, 2);
sEluna->m_EventMgr->RemoveEvent(&unit->m_Events, eventId);
return 0;
}
int RemoveEvents(lua_State* /*L*/, Unit* unit)
{
sEluna->m_EventMgr->RemoveEvents(&unit->m_Events);
return 0;
}
int AddUnitState(lua_State* L, Unit* unit) int AddUnitState(lua_State* L, Unit* unit)
{ {
uint32 state = Eluna::CHECKVAL<uint32>(L, 2); uint32 state = Eluna::CHECKVAL<uint32>(L, 2);

View File

@@ -435,26 +435,26 @@ namespace LuaWorldObject
#ifndef TRINITY #ifndef TRINITY
switch (GUID_HIPART(guid)) switch (GUID_HIPART(guid))
{ {
case HIGHGUID_PLAYER: Eluna::Push(L, obj->GetMap()->GetPlayer(ObjectGuid(guid))); break; case HIGHGUID_PLAYER: Eluna::Push(L, obj->GetMap()->GetPlayer(ObjectGuid(guid))); break;
case HIGHGUID_TRANSPORT: case HIGHGUID_TRANSPORT:
case HIGHGUID_MO_TRANSPORT: case HIGHGUID_MO_TRANSPORT:
case HIGHGUID_GAMEOBJECT: Eluna::Push(L, obj->GetMap()->GetGameObject(ObjectGuid(guid))); break; case HIGHGUID_GAMEOBJECT: Eluna::Push(L, obj->GetMap()->GetGameObject(ObjectGuid(guid))); break;
#if (!defined(TBC) && !defined(CLASSIC)) #if (!defined(TBC) && !defined(CLASSIC))
case HIGHGUID_VEHICLE: case HIGHGUID_VEHICLE:
#endif #endif
case HIGHGUID_UNIT: case HIGHGUID_UNIT:
case HIGHGUID_PET: Eluna::Push(L, obj->GetMap()->GetAnyTypeCreature(ObjectGuid(guid))); break; case HIGHGUID_PET: Eluna::Push(L, obj->GetMap()->GetAnyTypeCreature(ObjectGuid(guid))); break;
} }
#else #else
switch (GUID_HIPART(guid)) switch (GUID_HIPART(guid))
{ {
case HIGHGUID_PLAYER: Eluna::Push(L, eObjectAccessor->GetPlayer(*obj, ObjectGuid(guid))); break; case HIGHGUID_PLAYER: Eluna::Push(L, eObjectAccessor->GetPlayer(*obj, ObjectGuid(guid))); break;
case HIGHGUID_TRANSPORT: case HIGHGUID_TRANSPORT:
case HIGHGUID_MO_TRANSPORT: case HIGHGUID_MO_TRANSPORT:
case HIGHGUID_GAMEOBJECT: Eluna::Push(L, eObjectAccessor->GetGameObject(*obj, ObjectGuid(guid))); break; case HIGHGUID_GAMEOBJECT: Eluna::Push(L, eObjectAccessor->GetGameObject(*obj, ObjectGuid(guid))); break;
case HIGHGUID_VEHICLE: case HIGHGUID_VEHICLE:
case HIGHGUID_UNIT: Eluna::Push(L, eObjectAccessor->GetCreature(*obj, ObjectGuid(guid))); break; case HIGHGUID_UNIT: Eluna::Push(L, eObjectAccessor->GetCreature(*obj, ObjectGuid(guid))); break;
case HIGHGUID_PET: Eluna::Push(L, eObjectAccessor->GetPet(*obj, ObjectGuid(guid))); break; case HIGHGUID_PET: Eluna::Push(L, eObjectAccessor->GetPet(*obj, ObjectGuid(guid))); break;
} }
#endif #endif
return 1; return 1;
@@ -604,32 +604,83 @@ namespace LuaWorldObject
TempSummonType type; TempSummonType type;
switch (spawnType) switch (spawnType)
{ {
case 1: case 1:
type = TEMPSUMMON_TIMED_OR_DEAD_DESPAWN; type = TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
break; break;
case 2: case 2:
type = TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN; type = TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN;
break; break;
case 3: case 3:
type = TEMPSUMMON_TIMED_DESPAWN; type = TEMPSUMMON_TIMED_DESPAWN;
break; break;
case 5: case 5:
type = TEMPSUMMON_CORPSE_DESPAWN; type = TEMPSUMMON_CORPSE_DESPAWN;
break; break;
case 6: case 6:
type = TEMPSUMMON_CORPSE_TIMED_DESPAWN; type = TEMPSUMMON_CORPSE_TIMED_DESPAWN;
break; break;
case 7: case 7:
type = TEMPSUMMON_DEAD_DESPAWN; type = TEMPSUMMON_DEAD_DESPAWN;
break; break;
case 8: case 8:
type = TEMPSUMMON_MANUAL_DESPAWN; type = TEMPSUMMON_MANUAL_DESPAWN;
break; break;
default: default:
return luaL_argerror(L, 7, "valid SpawnType expected"); return luaL_argerror(L, 7, "valid SpawnType expected");
} }
Eluna::Push(L, obj->SummonCreature(entry, x, y, z, o, type, despawnTimer)); Eluna::Push(L, obj->SummonCreature(entry, x, y, z, o, type, despawnTimer));
return 1; return 1;
} }
/**
* Registers a timed event to the [WorldObject]
* When the passed function is called, the parameters `(eventId, delay, repeats, worldobject)` are passed to it.
* Repeats will decrease on each call if the event does not repeat indefinitely
*
* Note that for [Creature] and [GameObject] the timed event timer ticks only if the creature is in sight of someone
* For all [WorldObject]s the timed events are removed when the object is destoryed. This means that for example a [Player]'s events are removed on logout.
*
* @param function function : function to trigger when the time has passed
* @param uint32 delay : set time in milliseconds for the event to trigger
* @param uint32 repeats : how many times for the event to repeat, 0 is infinite
* @return int eventId : unique ID for the timed event used to cancel it or nil
*/
int RegisterEvent(lua_State* L, WorldObject* obj)
{
luaL_checktype(L, 2, LUA_TFUNCTION);
uint32 delay = Eluna::CHECKVAL<uint32>(L, 3);
uint32 repeats = Eluna::CHECKVAL<uint32>(L, 4);
lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF)
{
obj->elunaEvents.AddEvent(functionRef, delay, repeats);
Eluna::Push(L, functionRef);
}
return 1;
}
/**
* Removes the timed event from a [WorldObject] by the specified event ID
*
* @param int eventId : event Id to remove
*/
int RemoveEventById(lua_State* L, WorldObject* obj)
{
int eventId = Eluna::CHECKVAL<int>(L, 2);
obj->elunaEvents.RemoveEvent(eventId);
return 0;
}
/**
* Removes all timed events from a [WorldObject]
*
*/
int RemoveEvents(lua_State* /*L*/, WorldObject* obj)
{
obj->elunaEvents.RemoveEvents();
return 0;
}
}; };
#endif #endif