/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * 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 3 of the License, or * 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 . * */ #include "StdAfx.h" #include "EventableObject.h" EventableObject::~EventableObject() { /* decrement event count on all events */ EventMap::iterator itr = m_events.begin(); for(; itr != m_events.end(); ++itr) { itr->second->deleted = true; itr->second->DecRef(); } m_events.clear(); } EventableObject::EventableObject() { /* commented, these will be allocated when the first event is added. */ //m_event_Instanceid = event_GetInstanceID(); //m_holder = sEventMgr.GetEventHolder(m_event_Instanceid); m_holder = 0; m_event_Instanceid = -1; } void EventableObject::event_AddEvent(TimedEvent * ptr) { m_lock.Acquire(); if(!m_holder) { m_event_Instanceid = event_GetInstanceID(); m_holder = sEventMgr.GetEventHolder(m_event_Instanceid); } ptr->IncRef(); ptr->instanceId = m_event_Instanceid; pair p(ptr->eventType, ptr); m_events.insert( p ); m_lock.Release(); /* Add to event manager */ if(!m_holder) { /* relocate to -1 eventholder :/ */ m_event_Instanceid = -1; m_holder = sEventMgr.GetEventHolder(m_event_Instanceid); ASSERT(m_holder); } m_holder->AddEvent(ptr); } void EventableObject::event_RemoveByPointer(TimedEvent * ev) { m_lock.Acquire(); EventMap::iterator itr = m_events.find(ev->eventType); EventMap::iterator it2; if(itr != m_events.end()) { do { it2 = itr++; if(it2->second == ev) { it2->second->deleted = true; it2->second->DecRef(); m_events.erase(it2); m_lock.Release(); return; } } while(itr != m_events.upper_bound(ev->eventType)); } m_lock.Release(); } void EventableObject::event_RemoveEvents(uint32 EventType) { m_lock.Acquire(); if(!m_events.size()) { m_lock.Release(); return; } if(EventType == EVENT_REMOVAL_FLAG_ALL) { EventMap::iterator itr = m_events.begin(); for(; itr != m_events.end(); ++itr) { itr->second->deleted = true; itr->second->DecRef(); } m_events.clear(); } else { EventMap::iterator itr = m_events.find(EventType); EventMap::iterator it2; if(itr != m_events.end()) { do { it2 = itr++; it2->second->deleted = true; it2->second->DecRef(); m_events.erase(it2); } while(itr != m_events.upper_bound(EventType)); } } m_lock.Release(); } void EventableObject::event_RemoveEvents() { event_RemoveEvents(EVENT_REMOVAL_FLAG_ALL); } void EventableObject::event_ModifyTimeLeft(uint32 EventType, uint32 TimeLeft,bool unconditioned) { m_lock.Acquire(); if(!m_events.size()) { m_lock.Release(); return; } EventMap::iterator itr = m_events.find(EventType); if(itr != m_events.end()) { do { if(unconditioned) itr->second->currTime = TimeLeft; else itr->second->currTime = ((int32)TimeLeft > itr->second->msTime) ? itr->second->msTime : (int32)TimeLeft; ++itr; } while(itr != m_events.upper_bound(EventType)); } m_lock.Release(); } void EventableObject::event_ModifyTime(uint32 EventType, uint32 Time) { m_lock.Acquire(); if(!m_events.size()) { m_lock.Release(); return; } EventMap::iterator itr = m_events.find(EventType); if(itr != m_events.end()) { do { itr->second->msTime = Time; ++itr; } while(itr != m_events.upper_bound(EventType)); } m_lock.Release(); } void EventableObject::event_ModifyTimeAndTimeLeft(uint32 EventType, uint32 Time) { m_lock.Acquire(); if(!m_events.size()) { m_lock.Release(); return; } EventMap::iterator itr = m_events.find(EventType); if(itr != m_events.end()) { do { itr->second->currTime = itr->second->msTime = Time; ++itr; } while(itr != m_events.upper_bound(EventType)); } m_lock.Release(); } bool EventableObject::event_HasEvent(uint32 EventType) { bool ret = false; m_lock.Acquire(); if(!m_events.size()) { m_lock.Release(); return false; } //ret = m_events.find(EventType) == m_events.end() ? false : true; EventMap::iterator itr = m_events.find(EventType); if(itr != m_events.end()) { do { if(!itr->second->deleted) { ret = true; break; } ++itr; } while(itr != m_events.upper_bound(EventType)); } m_lock.Release(); return ret; } EventableObjectHolder::EventableObjectHolder(int32 instance_id) : mInstanceId(instance_id) { sEventMgr.AddEventHolder(this, instance_id); } EventableObjectHolder::~EventableObjectHolder() { sEventMgr.RemoveEventHolder(this); /* decrement events reference count */ m_lock.Acquire(); EventList::iterator itr = m_events.begin(); for(; itr != m_events.end(); ++itr) (*itr)->DecRef(); m_lock.Release(); } void EventableObjectHolder::Update(uint32 time_difference) { m_lock.Acquire(); // <<<< /* Insert any pending objects in the insert pool. */ m_insertPoolLock.Acquire(); InsertableQueue::iterator iqi; InsertableQueue::iterator iq2 = m_insertPool.begin(); while(iq2 != m_insertPool.end()) { iqi = iq2++; if((*iqi)->deleted || (*iqi)->instanceId != mInstanceId) (*iqi)->DecRef(); else m_events.push_back( (*iqi) ); m_insertPool.erase(iqi); } m_insertPoolLock.Release(); /* Now we can proceed normally. */ EventList::iterator itr = m_events.begin(); EventList::iterator it2; TimedEvent * ev; while(itr != m_events.end()) { it2 = itr++; if((*it2)->instanceId != mInstanceId || (*it2)->deleted || ( mInstanceId == WORLD_INSTANCE && (*it2)->eventFlag & EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT)) { // remove from this list. (*it2)->DecRef(); m_events.erase(it2); continue; } // Event Update Procedure ev = *it2; if((uint32)ev->currTime <= time_difference) { // execute the callback ev->cb->execute(); // check if the event is expired now. if(ev->repeats && --ev->repeats == 0) { // Event expired :> /* remove the event from the object */ /*obj = (EventableObject*)ev->obj; obj->event_RemoveByPointer(ev);*/ /* remove the event from here */ ev->deleted = true; ev->DecRef(); m_events.erase(it2); continue; } else if(ev->deleted) { // event is now deleted ev->DecRef(); m_events.erase(it2); continue; } // event has to repeat again, reset the timer ev->currTime = ev->msTime; } else { // event is still "waiting", subtract time difference ev->currTime -= time_difference; } } m_lock.Release(); } void EventableObject::event_Relocate() { /* prevent any new stuff from getting added */ m_lock.Acquire(); EventableObjectHolder * nh = sEventMgr.GetEventHolder(event_GetInstanceID()); if(nh != m_holder) { // whee, we changed event holder :> // doing this will change the instanceid on all the events, as well as add to the new holder. // no need to do this if we don't have any events, though. if(m_events.size()) { /* shitty sanity check. xUdd sucks. */ if(!nh) nh = sEventMgr.GetEventHolder(-1); nh->AddObject(this); } // reset our m_holder pointer and instance id m_event_Instanceid = nh->GetInstanceID(); m_holder = nh; } /* safe again to add */ m_lock.Release(); } uint32 EventableObject::event_GetEventPeriod(uint32 EventType) { uint32 ret = 0; m_lock.Acquire(); EventMap::iterator itr = m_events.find(EventType); if(itr != m_events.end()) ret = itr->second->msTime; m_lock.Release(); return ret; } void EventableObjectHolder::AddEvent(TimedEvent * ev) { // m_lock NEEDS TO BE A RECURSIVE MUTEX ev->IncRef(); if(!m_lock.AttemptAcquire()) { m_insertPoolLock.Acquire(); m_insertPool.push_back( ev ); m_insertPoolLock.Release(); } else { m_events.push_back( ev ); m_lock.Release(); } } void EventableObjectHolder::AddObject(EventableObject * obj) { // transfer all of this objects events into our holder if(!m_lock.AttemptAcquire()) { // The other thread is obviously occupied. We have to use an insert pool here, otherwise // if 2 threads relocate at once we'll hit a deadlock situation. m_insertPoolLock.Acquire(); EventMap::iterator it2; for(EventMap::iterator itr = obj->m_events.begin(); itr != obj->m_events.end(); ++itr) { // ignore deleted events (shouldn't be any in here, actually) if(itr->second->deleted) { /*it2 = itr++; itr->second->DecRef(); obj->m_events.erase(it2);*/ continue; } if(mInstanceId == WORLD_INSTANCE && itr->second->eventFlag & EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT) continue; itr->second->IncRef(); itr->second->instanceId = mInstanceId; m_insertPool.push_back(itr->second); } // Release the insert pool. m_insertPoolLock.Release(); // Ignore the rest of this stuff return; } for(EventMap::iterator itr = obj->m_events.begin(); itr != obj->m_events.end(); ++itr) { // ignore deleted events if(itr->second->deleted) continue; if(mInstanceId == WORLD_INSTANCE && itr->second->eventFlag & EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT) continue; itr->second->IncRef(); itr->second->instanceId = mInstanceId; m_events.push_back( itr->second ); } m_lock.Release(); }