Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11493 was 11103, checked in by landauf, 9 years ago

fixed warnings (release build).
fixed error in GravityBombField

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