Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8734 was 8706, checked in by dafrick, 13 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

  • Property svn:eol-style set to native
File size: 17.8 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 "Iterator.h"
42#include "Template.h"
43#include "XMLFile.h"
44#include "XMLNameListener.h"
45#include "XMLPort.h"
46#include "command/Functor.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            this->setLevel(this->creator_->getLevel());
78        }
79        else
80        {
81            this->file_ = 0;
82            this->namespace_ = 0;
83            this->scene_ = 0;
84            this->sceneID_ = OBJECTID_UNKNOWN;
85            this->gametype_ = 0;
86            this->level_ = 0;
87        }
88    }
89
90    /**
91        @brief Destructor
92    */
93    BaseObject::~BaseObject()
94    {
95        if (this->isInitialized())
96        {
97            for (std::map<BaseObject*, std::string>::const_iterator it = this->eventSources_.begin(); it != this->eventSources_.end(); )
98                this->removeEventSource((it++)->first);
99
100            for (std::set<BaseObject*>::const_iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); )
101                (*(it++))->removeEventSource(this);
102
103            for (std::map<std::string, EventState*>::const_iterator it = this->eventStates_.begin(); it != this->eventStates_.end(); ++it)
104                delete it->second;
105        }
106    }
107
108    /** @brief Adds an object which listens to the events of this object. */
109    void BaseObject::registerEventListener(BaseObject* object)
110    {
111        COUT(4) << "New EventListener: " << object->getIdentifier()->getName() << " &(" << object << ")." << std::endl;
112        this->eventListeners_.insert(object);
113    }
114
115    /**
116        @brief XML loading and saving.
117        @param xmlelement The XML-element
118        @param mode The mode defines the operation that is being executed: loading or saving the object (from or to XML respectively)
119    */
120    void BaseObject::XMLPort(Element& xmlelement, XMLPort::Mode mode)
121    {
122        XMLPortParam(BaseObject, "name", setXMLName, getName, xmlelement, mode);
123        XMLPortParam(BaseObject, "visible", setVisible, isVisible, xmlelement, mode);
124        XMLPortParam(BaseObject, "active", setActive, isActive, xmlelement, mode);
125        XMLPortParam(BaseObject, "mainstate", setMainStateName, getMainStateName, xmlelement, mode);
126        XMLPortParamTemplate(BaseObject, "template", addTemplate, getSingleTemplate, xmlelement, mode, const std::string&);
127
128        XMLPortObjectTemplate(BaseObject, Template, "templates", addTemplate, getTemplate, xmlelement, mode, Template*);
129        XMLPortObject(BaseObject, BaseObject, "eventlisteners", addEventListener, getEventListener, xmlelement, mode);
130
131        Element* events = 0;
132        if (mode == XMLPort::LoadObject || mode == XMLPort::ExpandObject)
133            events = xmlelement.FirstChildElement("events", false);
134        else if (mode == XMLPort::SaveObject)
135            {}
136        if (events)
137            this->XMLEventPort(*events, mode);
138    }
139
140    /**
141        @brief Defines the possible event states of this object and parses eventsources from an XML file.
142        @param xmlelement The XML-element
143        @param mode The mode defines the operation that is being executed: loading or saving the object (from or to XML respectively)
144    */
145    void BaseObject::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
146    {
147        XMLPortEventState(BaseObject, BaseObject, "activity", setActive, xmlelement, mode);
148        XMLPortEventState(BaseObject, BaseObject, "visibility", setVisible, xmlelement, mode);
149        XMLPortEventState(BaseObject, BaseObject, "mainstate", setMainState, xmlelement, mode);
150
151        this->bRegisteredEventStates_ = true;
152    }
153
154    /**
155        @brief Loads the name of the object through XML and calls all XMLNameListener.
156        @param name The name of the object
157    */
158    void BaseObject::setXMLName(const std::string& name)
159    {
160        this->setName(name);
161
162        for (ObjectList<XMLNameListener>::iterator it = ObjectList<XMLNameListener>::begin(); it != ObjectList<XMLNameListener>::end(); ++it)
163            it->loadedNewXMLName(this);
164    }
165
166    /**
167        @brief Returns the levelfile that loaded this object.
168        @return The levelfile
169    */
170    const std::string& BaseObject::getFilename() const
171    {
172        if (this->file_)
173            return this->file_->getFilename();
174        else
175            return BLANKSTRING;
176    }
177
178    /**
179        @brief Adds a Template to the object.
180        @param name The name of the Template
181    */
182    void BaseObject::addTemplate(const std::string& name)
183    {
184        Template* temp = Template::getTemplate(name);
185        if (temp)
186            this->addTemplate(temp);
187        else
188            COUT(1) << "Error: \"" << name << "\" is not a valid Template name (in class: " << this->getIdentifier()->getName() << ", name: " << this->getName() << ")." << std::endl;
189    }
190
191    /**
192        @brief Adds a Template to the object.
193        @param temp The Template
194    */
195    void BaseObject::addTemplate(Template* temp)
196    {
197        // network
198        if (temp->isLink())
199        {
200            this->networkTemplateNames_.insert(temp->getLink());
201           
202            Template* link;
203            assert(!(link = Template::getTemplate(temp->getLink())) || !link->isLink());
204            link = NULL;
205        }
206        else
207            this->networkTemplateNames_.insert(temp->getName());
208
209        // add template
210        this->templates_.insert(temp);
211        temp->applyOn(this);
212    }
213
214    /**
215        @brief Returns the name of the first Template.
216        @return The name as string.
217    */
218    const std::string& BaseObject::getSingleTemplate(void) const
219    {
220        if(this->templates_.empty())
221            return BLANKSTRING;
222
223        return (*this->templates_.begin())->getName();
224    }
225
226    /**
227        @brief Returns the Template with the given index.
228        @param index The index
229    */
230    Template* BaseObject::getTemplate(unsigned int index) const
231    {
232        unsigned int i = 0;
233        for (std::set<Template*>::const_iterator it = this->templates_.begin(); it != this->templates_.end(); ++it)
234        {
235            if (i == index)
236                return (*it);
237            i++;
238        }
239        return 0;
240    }
241
242    /**
243        @brief Adds a new event source for a specific state.
244        @param source The object which sends events to this object
245        @param state The state of this object which will be affected by the events
246    */
247    void BaseObject::addEventSource(BaseObject* source, const std::string& state)
248    {
249        this->eventSources_[source] = state;
250        source->registerEventListener(this);
251    }
252
253    /**
254        @brief Removes an eventsource (but doesn't unregister itself at the source).
255    */
256    void BaseObject::removeEventSource(BaseObject* source)
257    {
258        this->eventSources_.erase(source);
259        source->unregisterEventListener(this);
260    }
261
262    /**
263        @brief Returns an eventsource with a given index.
264    */
265    BaseObject* BaseObject::getEventSource(unsigned int index, const std::string& state) const
266    {
267        unsigned int i = 0;
268        for (std::map<BaseObject*, std::string>::const_iterator it = this->eventSources_.begin(); it != this->eventSources_.end(); ++it)
269        {
270            if (it->second != state)
271                continue;
272
273            if (i == index)
274                return it->first;
275            ++i;
276        }
277        return 0;
278    }
279
280    /**
281        @brief Adds an object which listens to the events of this object. The events are sent to the other objects mainstate.
282    */
283    void BaseObject::addEventListener(BaseObject* listener)
284    {
285        this->eventListenersXML_.insert(listener);
286        listener->addEventSource(this, "mainstate");
287    }
288
289    /**
290        @brief Returns an event listener with a given index.
291    */
292    BaseObject* BaseObject::getEventListener(unsigned int index) const
293    {
294        unsigned int i = 0;
295        for (std::set<BaseObject*>::const_iterator it = this->eventListenersXML_.begin(); it != this->eventListenersXML_.end(); ++it)
296        {
297            if (i == index)
298                return *it;
299            ++i;
300        }
301        return 0;
302    }
303
304    /**
305        @brief Adds a new event-state to the object. Event-states are states which can be changed by events.
306        @param name  The name of the event
307        @param state The object containing information about the event-state
308    */
309    void BaseObject::addEventState(const std::string& name, EventState* state)
310    {
311        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(name);
312        if (it != this->eventStates_.end())
313        {
314            COUT(2) << "Warning: Overwriting EventState in class " << this->getIdentifier()->getName() << '.' << std::endl;
315            delete (it->second);
316        }
317
318        this->eventStates_[name] = state;
319    }
320
321    /**
322        @brief Returns the event-state with the given name.
323    */
324    EventState* BaseObject::getEventState(const std::string& name) const
325    {
326        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(name);
327        if (it != this->eventStates_.end())
328            return (it->second);
329        else
330            return 0;
331    }
332
333    /**
334        @brief Fires an event (without a state).
335    */
336    void BaseObject::fireEvent(const std::string& name)
337    {
338        this->fireEvent(true, name);
339        this->fireEvent(false, name);
340    }
341
342    /**
343        @brief Fires an event which activates or deactivates a state.
344    */
345    void BaseObject::fireEvent(bool activate, const std::string& name)
346    {
347        this->fireEvent(activate, this, name);
348    }
349
350    /**
351        @brief Fires an event which activates or deactivates a state with agiven originator (the object which triggered the event).
352    */
353    void BaseObject::fireEvent(bool activate, BaseObject* originator, const std::string& name)
354    {
355        Event event(activate, originator, name);
356
357        for (std::set<BaseObject*>::iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); ++it)
358        {
359            event.statename_ = (*it)->eventSources_[this];
360            (*it)->processEvent(event);
361        }
362    }
363
364    /**
365        @brief Fires an event, using the Event struct.
366    */
367    void BaseObject::fireEvent(Event& event)
368    {
369        for (std::set<BaseObject*>::iterator it = this->eventListeners_.begin(); it != this->eventListeners_.end(); ++it)
370            (*it)->processEvent(event);
371    }
372
373    /**
374        @brief Processing an event by calling the right main state.
375        @param event The event struct which contains the information about the event
376    */
377    void BaseObject::processEvent(Event& event)
378    {
379        this->registerEventStates();
380
381        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;
382
383        std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(event.statename_);
384        if (it != this->eventStates_.end())
385            it->second->process(event, this);
386        else if (!event.statename_.empty())
387            COUT(2) << "Warning: \"" << event.statename_ << "\" is not a valid state in object \"" << this->getName() << "\" of class " << this->getIdentifier()->getName() << "." << std::endl;
388        else
389            COUT(2) << "Warning: Event with invalid source sent to object \"" << this->getName() << "\" of class " << this->getIdentifier()->getName() << "." << std::endl;
390    }
391
392    /**
393        @brief Sets the main state of the object to a given boolean value.
394
395        Note: The main state of an object can be set with the @ref setMainStateName function.
396        It's part of the eventsystem and used for event forwarding (when the target object can't specify a specific state,
397        the main state is used by default).
398    */
399    void BaseObject::setMainState(bool state)
400    {
401        if (this->mainStateFunctor_)
402        {
403            if (this->mainStateFunctor_->getParamCount() == 0)
404            {
405                if (state)
406                    (*this->mainStateFunctor_)();
407            }
408            else
409            {
410                (*this->mainStateFunctor_)(state);
411            }
412        }
413        else
414            COUT(2) << "Warning: No MainState defined in object \"" << this->getName() << "\" (" << this->getIdentifier()->getName() << ")" << std::endl;
415    }
416
417    /**
418        @brief This function gets called if the main state name of the object changes.
419    */
420    void BaseObject::changedMainStateName()
421    {
422        this->mainStateFunctor_ = 0;
423
424        if (!this->mainStateName_.empty())
425        {
426            this->registerEventStates();
427
428            std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(this->mainStateName_);
429            if (it != this->eventStates_.end() && it->second->getFunctor())
430            {
431                if (it->second->getFunctor()->getParamCount() <= 1)
432                    this->mainStateFunctor_ = it->second->getFunctor();
433                else
434                    COUT(2) << "Warning: Can't use \"" << this->mainStateName_ << "\" as MainState because it needs a second argument." << std::endl;
435            }
436            else
437                COUT(2) << "Warning: \"" << this->mainStateName_ << "\" is not a valid MainState." << std::endl;
438        }
439    }
440
441    /**
442        @brief Calls XMLEventPort with an empty XML-element to register the event states if necessary.
443    */
444    void BaseObject::registerEventStates()
445    {
446        if (!this->bRegisteredEventStates_)
447        {
448            Element xmlelement;
449            this->XMLEventPort(xmlelement, XMLPort::NOP);
450        }
451    }
452
453    /**
454        @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.
455    */
456    void BaseObject::loadAllEventStates(Element& xmlelement, XMLPort::Mode mode, BaseObject* object, Identifier* identifier)
457    {
458        Element* events = xmlelement.FirstChildElement("events", false);
459        if (events)
460        {
461            // get the list of all states present
462            std::list<std::string> eventnames;
463            if (mode == XMLPort::LoadObject || mode == XMLPort::ExpandObject)
464            {
465                for (ticpp::Iterator<ticpp::Element> child = events->FirstChildElement(false); child != child.end(); child++)
466                    eventnames.push_back(child->Value());
467            }
468            else if (mode == XMLPort::SaveObject)
469            {
470            }
471
472            // iterate through all states and get the event sources
473            for (std::list<std::string>::iterator it = eventnames.begin(); it != eventnames.end(); ++it)
474            {
475                const std::string& statename = (*it);
476
477                // if the event state is already known, continue with the next state
478                orxonox::EventState* eventstate = object->getEventState(statename);
479                if (eventstate)
480                    continue;
481
482                XMLPortClassObjectContainer<BaseObject, BaseObject>* container = (XMLPortClassObjectContainer<BaseObject, BaseObject>*)(identifier->getXMLPortObjectContainer(statename));
483                if (!container)
484                {
485                    const ExecutorMemberPtr<BaseObject>& setfunctor = createExecutor(createFunctor(&BaseObject::addEventSource), std::string( "BaseObject" ) + "::" + "addEventSource" + '(' + statename + ')');
486                    const ExecutorMemberPtr<BaseObject>& getfunctor = createExecutor(createFunctor(&BaseObject::getEventSource), std::string( "BaseObject" ) + "::" + "getEventSource" + '(' + statename + ')');
487                    setfunctor->setDefaultValue(1, statename);
488                    getfunctor->setDefaultValue(1, statename);
489
490                    container = new XMLPortClassObjectContainer<BaseObject, BaseObject>(statename, identifier, setfunctor, getfunctor, false, true);
491                    identifier->addXMLPortObjectContainer(statename, container);
492                }
493                container->port(object, *events, mode);
494            }
495        }
496    }
497}
Note: See TracBrowser for help on using the repository browser.