Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/BaseObject.cc @ 6800

Last change on this file since 6800 was 6800, checked in by dafrick, 14 years ago

Created a new class of triggers called Multitriggers.
MultiTriggers are triggers which (as opposed to normal triggers) have a state for each object triggering the MultiTrigger, that means, that a MultiTrigger can be triggered for two different Players, while not being triggered for a third.
To go with this MultiTrigger I created a data structure (MultitriggerContainer), which helps relaying important information to the objects, that receive the Events of the trigger.
Also there is a MultiDistanceTrigger, which is just the DistanceTrigger as a MultiTrigger.

To make this work I had to make some adjustements to the eventsystem, namely an EventState can now be either an EventState (as it was before) or an EventSink, which means that every efent arriving at the EventState is processed as opposed to just the ones which change the state.
There is a new makro (XMLPortEventSink) to create an EventState with sink behaviour. It can be used exacly as the XMLPortEventState makro.

  • Property svn:eol-style set to native
File size: 17.2 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of the BaseObject class.
32*/
33
34#include "BaseObject.h"
35
36#include <tinyxml/tinyxml.h>
37
38#include "CoreIncludes.h"
39#include "Event.h"
40#include "EventIncludes.h"
41#include "Functor.h"
42#include "Iterator.h"
43#include "Template.h"
44#include "XMLFile.h"
45#include "XMLNameListener.h"
46#include "XMLPort.h"
47
48namespace orxonox
49{
50    CreateFactory(BaseObject);
51
52    /**
53        @brief Constructor: Registers the object in the BaseObject-list.
54    */
55    BaseObject::BaseObject(BaseObject* creator) : bInitialized_(false)
56    {
57        RegisterRootObject(BaseObject);
58
59        this->bInitialized_ = true;
60
61        this->bActive_ = true;
62        this->bVisible_ = true;
63        this->oldGametype_ = 0;
64        this->bRegisteredEventStates_ = false;
65
66        this->lastLoadedXMLElement_ = 0;
67
68        this->mainStateFunctor_ = 0;
69
70        this->setCreator(creator);
71        if (this->creator_)
72        {
73            this->setFile(this->creator_->getFile());
74            this->setNamespace(this->creator_->getNamespace());
75            this->setScene(this->creator_->getScene(), this->creator_->getSceneID());
76            this->setGametype(this->creator_->getGametype());
77        }
78        else
79        {
80            this->file_ = 0;
81            this->namespace_ = 0;
82            this->scene_ = 0;
83            this->sceneID_ = OBJECTID_UNKNOWN;
84            this->gametype_ = 0;
85        }
86    }
87
88    /**
89        @brief Destructor
90    */
91    BaseObject::~BaseObject()
92    {
93        if (this->isInitialized())
94        {
95            for (std::map<BaseObject*, std::string>::const_iterator it = this->eventSources_.begin(); it != this->eventSources_.end(); )
96                this->removeEventSource((it++)->first);
97
98            for (std::set<BaseObject*>::const_iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); )
99                (*(it++))->removeEventSource(this);
100
101            for (std::map<std::string, EventState*>::const_iterator it = this->eventStates_.begin(); it != this->eventStates_.end(); ++it)
102                delete it->second;
103        }
104    }
105   
106    /** @brief Adds an object which listens to the events of this object. */
107    void BaseObject::registerEventListener(BaseObject* object)
108    {
109        COUT(4) << "New EventListener: " << object->getIdentifier()->getName() << " &(" << object << ")." << std::endl;
110        this->eventListeners_.insert(object);
111    }
112
113    /**
114        @brief XML loading and saving.
115        @param xmlelement The XML-element
116        @param loading Loading (true) or saving (false)
117    */
118    void BaseObject::XMLPort(Element& xmlelement, XMLPort::Mode mode)
119    {
120        XMLPortParam(BaseObject, "name", setXMLName, getName, xmlelement, mode);
121        XMLPortParam(BaseObject, "visible", setVisible, isVisible, xmlelement, mode);
122        XMLPortParam(BaseObject, "active", setActive, isActive, xmlelement, mode);
123        XMLPortParam(BaseObject, "mainstate", setMainStateName, getMainStateName, xmlelement, mode);
124        XMLPortParamTemplate(BaseObject, "template", addTemplate, getSingleTemplate, xmlelement, mode, const std::string&);
125       
126        XMLPortObjectTemplate(BaseObject, Template, "templates", addTemplate, getTemplate, xmlelement, mode, Template*);
127        XMLPortObject(BaseObject, BaseObject, "eventlisteners", addEventListener, getEventListener, xmlelement, mode);
128
129        Element* events = 0;
130        if (mode == XMLPort::LoadObject || mode == XMLPort::ExpandObject)
131            events = xmlelement.FirstChildElement("events", false);
132        else if (mode == XMLPort::SaveObject)
133            {}
134        if (events)
135            this->XMLEventPort(*events, mode);
136    }
137
138    /**
139        @brief Defines the possible event states of this object and parses eventsources from an XML file.
140        @param xmlelement The XML-element
141        @param loading Loading (true) or saving (false)
142    */
143    void BaseObject::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
144    {
145        XMLPortEventState(BaseObject, BaseObject, "activity", setActive, xmlelement, mode);
146        XMLPortEventState(BaseObject, BaseObject, "visibility", setVisible, xmlelement, mode);
147        XMLPortEventState(BaseObject, BaseObject, "mainstate", setMainState, xmlelement, mode);
148
149        this->bRegisteredEventStates_ = true;
150    }
151
152    /**
153        @brief Loads the name of the object through XML and calls all XMLNameListener.
154        @param name The name of the object
155    */
156    void BaseObject::setXMLName(const std::string& name)
157    {
158        this->setName(name);
159
160        for (ObjectList<XMLNameListener>::iterator it = ObjectList<XMLNameListener>::begin(); it != ObjectList<XMLNameListener>::end(); ++it)
161            it->loadedNewXMLName(this);
162    }
163
164    /**
165        @brief Returns the levelfile that loaded this object.
166        @return The levelfile
167    */
168    const std::string& BaseObject::getFilename() const
169    {
170        if (this->file_)
171            return this->file_->getFilename();
172        else
173            return BLANKSTRING;
174    }
175
176    /**
177        @brief Adds a Template to the object.
178        @param name The name of the Template
179    */
180    void BaseObject::addTemplate(const std::string& name)
181    {
182        Template* temp = Template::getTemplate(name);
183        if (temp)
184            this->addTemplate(temp);
185        else
186            COUT(1) << "Error: \"" << name << "\" is not a valid Template name (in class: " << this->getIdentifier()->getName() << ", name: " << this->getName() << ")." << std::endl;
187    }
188
189    /**
190        @brief Adds a Template to the object.
191        @param temp The Template
192    */
193    void BaseObject::addTemplate(Template* temp)
194    {
195        this->templates_.insert(temp);
196        temp->applyOn(this);
197    }
198
199    /**
200        @brief Returns the name of the first Template.
201        @return The name as string.
202    */
203    const std::string& BaseObject::getSingleTemplate(void) const
204    {
205        if(this->templates_.empty())
206            return BLANKSTRING;
207
208        return (*this->templates_.begin())->getName();
209    }
210
211    /**
212        @brief Returns the Template with the given index.
213        @param index The index
214    */
215    Template* BaseObject::getTemplate(unsigned int index) const
216    {
217        unsigned int i = 0;
218        for (std::set<Template*>::const_iterator it = this->templates_.begin(); it != this->templates_.end(); ++it)
219        {
220            if (i == index)
221                return (*it);
222            i++;
223        }
224        return 0;
225    }
226
227    /**
228        @brief Adds a new event source for a specific state.
229        @param source The object which sends events to this object
230        @param state The state of this object which will be affected by the events
231    */
232    void BaseObject::addEventSource(BaseObject* source, const std::string& state)
233    {
234        this->eventSources_[source] = state;
235        source->registerEventListener(this);
236    }
237
238    /**
239        @brief Removes an eventsource (but doesn't unregister itself at the source).
240    */
241    void BaseObject::removeEventSource(BaseObject* source)
242    {
243        this->eventSources_.erase(source);
244        source->unregisterEventListener(this);
245    }
246
247    /**
248        @brief Returns an eventsource with a given index.
249    */
250    BaseObject* BaseObject::getEventSource(unsigned int index, const std::string& state) const
251    {
252        unsigned int i = 0;
253        for (std::map<BaseObject*, std::string>::const_iterator it = this->eventSources_.begin(); it != this->eventSources_.end(); ++it)
254        {
255            if (it->second != state)
256                continue;
257
258            if (i == index)
259                return it->first;
260            ++i;
261        }
262        return 0;
263    }
264
265    /**
266        @brief Adds an object which listens to the events of this object. The events are sent to the other objects mainstate.
267    */
268    void BaseObject::addEventListener(BaseObject* listener)
269    {
270        this->eventListenersXML_.insert(listener);
271        listener->addEventSource(this, "mainstate");
272    }
273
274    /**
275        @brief Returns an event listener with a given index.
276    */
277    BaseObject* BaseObject::getEventListener(unsigned int index) const
278    {
279        unsigned int i = 0;
280        for (std::set<BaseObject*>::const_iterator it = this->eventListenersXML_.begin(); it != this->eventListenersXML_.end(); ++it)
281        {
282            if (i == index)
283                return *it;
284            ++i;
285        }
286        return 0;
287    }
288
289    /**
290        @brief Adds a new event-state to the object. Event-states are states which can be changed by events.
291        @param name  The name of the event
292        @param state The object containing information about the event-state
293    */
294    void BaseObject::addEventState(const std::string& name, EventState* state)
295    {
296        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(name);
297        if (it != this->eventStates_.end())
298        {
299            COUT(2) << "Warning: Overwriting EventState in class " << this->getIdentifier()->getName() << '.' << std::endl;
300            delete (it->second);
301        }
302
303        this->eventStates_[name] = state;
304    }
305
306    /**
307        @brief Returns the event-state with the given name.
308    */
309    EventState* BaseObject::getEventState(const std::string& name) const
310    {
311        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(name);
312        if (it != this->eventStates_.end())
313            return (it->second);
314        else
315            return 0;
316    }
317
318    /**
319        @brief Fires an event (without a state).
320    */
321    void BaseObject::fireEvent(const std::string& name)
322    {
323        this->fireEvent(true, name);
324        this->fireEvent(false, name);
325    }
326
327    /**
328        @brief Fires an event which activates or deactivates a state.
329    */
330    void BaseObject::fireEvent(bool activate, const std::string& name)
331    {
332        this->fireEvent(activate, this, name);
333    }
334
335    /**
336        @brief Fires an event which activates or deactivates a state with agiven originator (the object which triggered the event).
337    */
338    void BaseObject::fireEvent(bool activate, BaseObject* originator, const std::string& name)
339    {
340        Event event(activate, originator, name);
341
342        for (std::set<BaseObject*>::iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); ++it)
343        {
344            event.statename_ = (*it)->eventSources_[this];
345            (*it)->processEvent(event);
346        }
347    }
348
349    /**
350        @brief Fires an event, using the Event struct.
351    */
352    void BaseObject::fireEvent(Event& event)
353    {
354        for (std::set<BaseObject*>::iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); ++it)
355            (*it)->processEvent(event);
356    }
357
358    /**
359        @brief Processing an event by calling the right main state.
360        @param event The event struct which contains the information about the event
361    */
362    void BaseObject::processEvent(Event& event)
363    {
364        this->registerEventStates();
365       
366        COUT(4) << this->getIdentifier()->getName() << " (&" << this << ") processing event. originator: " << event.originator_->getIdentifier()->getName() << " (&" << event.originator_ << "), activate: " << event.activate_ << ", name: " << event.name_ << ", statename: " << event.statename_ << "." << std::endl;
367
368        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(event.statename_);
369        if (it != this->eventStates_.end())
370            it->second->process(event, this);
371        else if (!event.statename_.empty())
372            COUT(2) << "Warning: \"" << event.statename_ << "\" is not a valid state in object \"" << this->getName() << "\" of class " << this->getIdentifier()->getName() << "." << std::endl;
373        else
374            COUT(2) << "Warning: Event with invalid source sent to object \"" << this->getName() << "\" of class " << this->getIdentifier()->getName() << "." << std::endl;
375    }
376
377    /**
378        @brief Sets the main state of the object to a given boolean value.
379
380        Note: The main state of an object can be set with the @ref setMainStateName function.
381        It's part of the eventsystem and used for event forwarding (when the target object can't specify a specific state,
382        the main state is used by default).
383    */
384    void BaseObject::setMainState(bool state)
385    {
386        if (this->mainStateFunctor_)
387        {
388            if (this->mainStateFunctor_->getParamCount() == 0)
389            {
390                if (state)
391                    (*this->mainStateFunctor_)();
392            }
393            else
394            {
395                (*this->mainStateFunctor_)(state);
396            }
397        }
398        else
399            COUT(2) << "Warning: No MainState defined in object \"" << this->getName() << "\" (" << this->getIdentifier()->getName() << ")" << std::endl;
400    }
401
402    /**
403        @brief This function gets called if the main state name of the object changes.
404    */
405    void BaseObject::changedMainStateName()
406    {
407        this->mainStateFunctor_ = 0;
408
409        if (!this->mainStateName_.empty())
410        {
411            this->registerEventStates();
412
413            std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(this->mainStateName_);
414            if (it != this->eventStates_.end() && it->second->getFunctor())
415            {
416                if (it->second->getFunctor()->getParamCount() <= 1)
417                    this->mainStateFunctor_ = it->second->getFunctor();
418                else
419                    COUT(2) << "Warning: Can't use \"" << this->mainStateName_ << "\" as MainState because it needs a second argument." << std::endl;
420            }
421            else
422                COUT(2) << "Warning: \"" << this->mainStateName_ << "\" is not a valid MainState." << std::endl;
423        }
424    }
425
426    /**
427        @brief Calls XMLEventPort with an empty XML-element to register the event states if necessary.
428    */
429    void BaseObject::registerEventStates()
430    {
431        if (!this->bRegisteredEventStates_)
432        {
433            Element xmlelement;
434            this->XMLEventPort(xmlelement, XMLPort::NOP);
435        }
436    }
437
438    /**
439        @brief Manually loads all event states, even if the class doesn't officially support them. This is needed by some classes like @ref EventDispatcher or @ref EventTarget.
440    */
441    void BaseObject::loadAllEventStates(Element& xmlelement, XMLPort::Mode mode, BaseObject* object, Identifier* identifier)
442    {
443        Element* events = xmlelement.FirstChildElement("events", false);
444        if (events)
445        {
446            // get the list of all states present
447            std::list<std::string> eventnames;
448            if (mode == XMLPort::LoadObject || mode == XMLPort::ExpandObject)
449            {
450                for (ticpp::Iterator<ticpp::Element> child = events->FirstChildElement(false); child != child.end(); child++)
451                    eventnames.push_back(child->Value());
452            }
453            else if (mode == XMLPort::SaveObject)
454            {
455            }
456
457            // iterate through all states and get the event sources
458            for (std::list<std::string>::iterator it = eventnames.begin(); it != eventnames.end(); ++it)
459            {
460                const std::string& statename = (*it);
461
462                // if the event state is already known, continue with the next state
463                orxonox::EventState* eventstate = object->getEventState(statename);
464                if (eventstate)
465                    continue;
466
467                XMLPortClassObjectContainer<BaseObject, BaseObject>* container = (XMLPortClassObjectContainer<BaseObject, BaseObject>*)(identifier->getXMLPortObjectContainer(statename));
468                if (!container)
469                {
470                    ExecutorMember<BaseObject>* setfunctor = createExecutor(createFunctor(&BaseObject::addEventSource), std::string( "BaseObject" ) + "::" + "addEventSource" + '(' + statename + ')');
471                    ExecutorMember<BaseObject>* getfunctor = createExecutor(createFunctor(&BaseObject::getEventSource), std::string( "BaseObject" ) + "::" + "getEventSource" + '(' + statename + ')');
472                    setfunctor->setDefaultValue(1, statename);
473                    getfunctor->setDefaultValue(1, statename);
474
475                    container = new XMLPortClassObjectContainer<BaseObject, BaseObject>(statename, identifier, setfunctor, getfunctor, false, true);
476                    identifier->addXMLPortObjectContainer(statename, container);
477                }
478                container->port(object, *events, mode);
479            }
480        }
481    }
482}
Note: See TracBrowser for help on using the repository browser.