Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/BaseObject.cc @ 10576

Last change on this file since 10576 was 10576, checked in by landauf, 10 years ago

removed changedGametype and getOldGametype from BaseObject. the gametype is never supposed to change anyway. the only exception is PlayerInfo which may change a gametype. but this happens in a completely controlled manner and can be done with a separate new function (switchGametype).

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