~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/components/ogre/EmberEntity.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2004  Erik Hjortsberg
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
*/
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include "config.h"
 
21
#endif
 
22
#include "EmberEntity.h"
 
23
 
 
24
#include "framework/Service.h"
 
25
#include "framework/ConsoleBackend.h"
 
26
#include "services/EmberServices.h"
 
27
#include "services/sound/SoundService.h"
 
28
#include "EmberEntityFactory.h"
 
29
#include "MotionManager.h"
 
30
#include "GUIManager.h"
 
31
#include "terrain/TerrainArea.h"
 
32
#include "terrain/TerrainMod.h"
 
33
#include "MathConverter.h"
 
34
 
 
35
#include "EmberOgre.h"
 
36
#include <OgreWireBoundingBox.h>
 
37
#include <OgreException.h>
 
38
 
 
39
#include "terrain/TerrainGenerator.h"
 
40
#include "terrain/TerrainPage.h"
 
41
 
 
42
#include <Mercator/Area.h>
 
43
#include <Mercator/TerrainMod.h>
 
44
//#include <Atlas/Objects/ObjectsFwd.h>
 
45
#include <Eris/TypeInfo.h>
 
46
#include <Eris/View.h>
 
47
#include <Atlas/Formatter.h>
 
48
#include <Atlas/Objects/Decoder.h>
 
49
#include <Atlas/Codecs/XML.h>
 
50
#include <Atlas/Message/MEncoder.h>
 
51
#include <Atlas/Message/QueuedDecoder.h>
 
52
 
 
53
 
 
54
#include "model/Model.h"
 
55
 
 
56
using namespace Ogre;
 
57
 
 
58
 
 
59
namespace Ogre {
 
60
 
 
61
        /**
 
62
        This is just like a WireBoundBox but not aligned to the axes, hence it will correctly line up according to it's orientation.
 
63
        */
 
64
        class OOBBWireBoundingBox  : public WireBoundingBox
 
65
        {
 
66
                public:
 
67
        
 
68
                void getWorldTransforms( Matrix4* xform ) const
 
69
                {
 
70
                        SimpleRenderable::getWorldTransforms(xform);
 
71
                }
 
72
        };
 
73
 
 
74
};
 
75
 
 
76
 
 
77
 
 
78
 
 
79
 
 
80
 
 
81
 
 
82
 
 
83
 
 
84
 
 
85
 
 
86
 
 
87
 
 
88
 
 
89
namespace EmberOgre {
 
90
 
 
91
 
 
92
const std::string EmberEntity::MODE_STANDING("standing");
 
93
const std::string EmberEntity::MODE_RUNNING("running");
 
94
const std::string EmberEntity::MODE_WALKING("walking");
 
95
const std::string EmberEntity::MODE_SWIMMING("swimming");
 
96
const std::string EmberEntity::MODE_FLOATING("floating");
 
97
const std::string EmberEntity::MODE_FIXED("fixed");
 
98
 
 
99
const std::string EmberEntity::BboxMaterialName("BaseYellowNoLightning");
 
100
 
 
101
 
 
102
EmberEntity::EmberEntity(const std::string& id, Eris::TypeInfo* ty, Eris::View* vw,Ogre::SceneManager* sceneManager)
 
103
:
 
104
Eris::Entity(id, ty, vw) 
 
105
, mIsInitialized(false)
 
106
, mIsInMotionManager(false)
 
107
, mErisEntityBoundingBox(0)
 
108
, mOgreNode(0)
 
109
, mTerrainArea(0)
 
110
, mTerrainMod(0)
 
111
, mMovementMode(MM_DEFAULT)
 
112
{
 
113
        createSceneNode(sceneManager);
 
114
}
 
115
 
 
116
EmberEntity::~EmberEntity()
 
117
{
 
118
        ///detach all children so we don't destroy them
 
119
        while (getSceneNode()->numChildren()) {
 
120
                getSceneNode()->removeChild((short unsigned int)0);
 
121
        }
 
122
        Ogre::SceneNode* parent = static_cast<Ogre::SceneNode*>(getSceneNode()->getParent());
 
123
        if (parent) {
 
124
                parent->removeAndDestroyChild(getSceneNode()->getName());
 
125
        } else {
 
126
                getSceneNode()->getCreator()->destroySceneNode(getSceneNode()->getName());
 
127
        }
 
128
        ///make sure it's not in the MotionManager
 
129
        ///TODO: keep a marker in the entity so we don't need to call this for all entities
 
130
        MotionManager::getSingleton().removeEntity(this);
 
131
 
 
132
        if (mErisEntityBoundingBox) {
 
133
                mErisEntityBoundingBox->getParentSceneNode()->getCreator()->destroySceneNode(mErisEntityBoundingBox->getParentSceneNode()->getName());
 
134
        }
 
135
        OGRE_DELETE mErisEntityBoundingBox;
 
136
        
 
137
        //mSceneManager->destroySceneNode(getSceneNode()->getName());
 
138
}
 
139
 
 
140
void EmberEntity::init(const Atlas::Objects::Entity::RootEntity &ge, bool fromCreateOp)
 
141
{
 
142
        Eris::Entity::init(ge, fromCreateOp);
 
143
        
 
144
        synchronizeWithServer();
 
145
        
 
146
        // set the Ogre node position and orientation based on Atlas data
 
147
        std::stringstream ss;
 
148
        if (getPredictedPos().isValid()) {
 
149
                ss << "Entity " << getId() << "(" << getName() << ") placed at (" << getPredictedPos().x() << "," << getPredictedPos().y() << "," << getPredictedPos().x() << ")";
 
150
        }
 
151
        S_LOG_VERBOSE( ss.str());
 
152
        
 
153
        mIsInitialized = true;
 
154
        
 
155
        ///Delay the checking and creation of area and terrainmod, since if we do it in onAttrChanged before the entity is properly initialized we'll get problems with multiple reparsings, as well as problems with placing the areas or terrainmod before the entity has been moved to it's proper place.
 
156
        ///Another way of doing this would be by attaching listeners, but that require more memory. It might be in the end that that's a better approach, depending on how much memory is needed, contrasted with the extra cycles spent here for every entity.
 
157
        if (hasAttr("area")) {
 
158
                createDependentObject("area");
 
159
        }
 
160
        
 
161
        if (hasAttr("terrainmod")) {
 
162
                createDependentObject("terrainmod");
 
163
        }
 
164
 
 
165
}
 
166
 
 
167
bool EmberEntity::createDependentObject(const std::string& attributeName)
 
168
{
 
169
        ///if the area attribute has changed, and we _don't_ have any mTerrainArea instance, try to create one such.
 
170
        ///if we do have an mTerrainArea instance, all updates will be taken care of by that instead and we can ignore this
 
171
        if (attributeName == "area" && !mTerrainArea.get()) {
 
172
                mTerrainArea = std::auto_ptr<Terrain::TerrainArea>(new Terrain::TerrainArea(this));
 
173
                if (mTerrainArea->init()) {
 
174
                        addArea(mTerrainArea.get());
 
175
                        return true;
 
176
                } else {
 
177
                        ///if we couldn't properly initialize, delete the instance now, and then hopefully the next time the "area" attribute is changed we'll be able to properly create an area
 
178
                        mTerrainArea.reset();
 
179
                }
 
180
        }
 
181
        
 
182
        ///if the area attribute has changed, and we _don't_ have any mTerrainMod instance, try to create one such.
 
183
        ///if we do have an mTerrainMod instance, all updates will be taken care of by that instead and we can ignore this
 
184
        if (attributeName == "terrainmod" && !mTerrainMod.get()) {
 
185
                mTerrainMod = std::auto_ptr<Terrain::TerrainMod>(new Terrain::TerrainMod(this));
 
186
                if (mTerrainMod->init()) {
 
187
                        addTerrainMod(mTerrainMod.get());
 
188
                        return true;
 
189
                } else {
 
190
                        ///if we couldn't properly initialize, delete the instance now, and then hopefully the next time the "area" attribute is changed we'll be able to properly create a mod
 
191
                        mTerrainMod.reset();
 
192
                }
 
193
        }
 
194
        return false;
 
195
}
 
196
 
 
197
 
 
198
void EmberEntity::synchronizeWithServer()
 
199
{
 
200
        if (getPosition().isValid()) {
 
201
                getSceneNode()->setPosition(Atlas2Ogre(getPredictedPos()));
 
202
                adjustPosition();
 
203
        }
 
204
        if (getOrientation().isValid()) {
 
205
                getSceneNode()->setOrientation(Atlas2Ogre(getOrientation()));
 
206
        }
 
207
}
 
208
 
 
209
void EmberEntity::createSceneNode(Ogre::SceneManager* sceneManager)
 
210
{
 
211
        EmberEntity* container = getEmberLocation();
 
212
        if (container == 0) {
 
213
                mOgreNode = sceneManager->createSceneNode(getId());
 
214
        } else {
 
215
                Ogre::SceneNode * node = container->getSceneNode();
 
216
                mOgreNode = node->createChildSceneNode(getId());
 
217
        }
 
218
}
 
219
 
 
220
void EmberEntity::updateMotion(Ogre::Real timeSlice)
 
221
{
 
222
        getSceneNode()->setPosition(Atlas2Ogre(getPredictedPos()));
 
223
        adjustPosition();
 
224
        
 
225
        //if there's a debug bounding box for the eris entity, update it's position
 
226
        if (mErisEntityBoundingBox) {
 
227
                mErisEntityBoundingBox->getParentSceneNode()->setPosition(getSceneNode()->getPosition());
 
228
                mErisEntityBoundingBox->getParentSceneNode()->setOrientation(getSceneNode()->getOrientation());
 
229
        }
 
230
 
 
231
}
 
232
 
 
233
void EmberEntity::onMoved()
 
234
{
 
235
        Eris::Entity::onMoved();
 
236
        const WFMath::Quaternion& orient = getOrientation();
 
237
        getSceneNode()->setOrientation(Atlas2Ogre(orient));
 
238
        updateMotion(0);
 
239
}
 
240
 
 
241
void EmberEntity::setMoving(bool moving)
 
242
{
 
243
        // Call the overridden method 
 
244
        Eris::Entity::setMoving(moving);
 
245
        
 
246
        MotionManager* motionManager = &MotionManager::getSingleton();
 
247
        if (moving) {
 
248
                //the entity is moving
 
249
                if (!mIsInMotionManager) {
 
250
                        motionManager->addEntity(this);
 
251
                        mIsInMotionManager = true;
 
252
                }
 
253
        } else {
 
254
                //the entity has stopped moving
 
255
                if (mIsInMotionManager) {
 
256
                        motionManager->removeEntity(this);
 
257
                        mIsInMotionManager = false;
 
258
                }
 
259
        }
 
260
}
 
261
 
 
262
void EmberEntity::onTalk(const Atlas::Objects::Operation::RootOperation& talkArgs)
 
263
{
 
264
        const std::vector<Atlas::Objects::Root>& args = talkArgs->getArgs();
 
265
        if (args.empty()) {
 
266
        Eris::Entity::onTalk(talkArgs);
 
267
                return;
 
268
        }
 
269
 
 
270
        const Atlas::Objects::Root& talk = args.front();
 
271
        
 
272
        
 
273
    if (!talk->hasAttr("say")) {
 
274
        Eris::Entity::onTalk(talkArgs);
 
275
                return;
 
276
    }
 
277
 
 
278
 
 
279
        ///some talk operations come with a predefined set of suitable responses, so we'll store those so that they can later on be queried by the GUI for example
 
280
        mSuggestedResponses.clear();
 
281
        if (talk->hasAttr("responses")) {
 
282
                if (talk->getAttr("responses").isList()) {
 
283
                        const Atlas::Message::ListType & responseList = talk->getAttr("responses").asList();
 
284
                        Atlas::Message::ListType::const_iterator I = responseList.begin();
 
285
                        for(; I != responseList.end(); ++I) {
 
286
                                mSuggestedResponses.push_back(I->asString());
 
287
                        }
 
288
                
 
289
                }
 
290
        }
 
291
        
 
292
        const std::string& msg = talk->getAttr("say").asString();
 
293
    
 
294
 
 
295
 
 
296
        
 
297
        std::string message = "<";
 
298
        message.append(getName());
 
299
        message.append(",");
 
300
        const std::string& type = getType()->getName(); // Eris type as a string
 
301
        message.append(type);
 
302
        message.append("> ");
 
303
        message.append(msg);
 
304
        S_LOG_VERBOSE( "Entity says: [" << message << "]\n" );
 
305
 
 
306
        /// Make the message appear in the chat box
 
307
        GUIManager::getSingleton().AppendIGChatLine.emit(msg, this);
 
308
 
 
309
        /// Make a sound in OpenAL
 
310
//      Ember::EmberServices::getSingleton().getSoundService()->playTalk(msg,
 
311
//              getPosition(),getOrientation());
 
312
 
 
313
        /// Call the method of the base class (since we've overloaded it)
 
314
        Eris::Entity::onTalk(talkArgs);
 
315
}
 
316
 
 
317
 
 
318
void EmberEntity::onSoundAction( const Atlas::Objects::Operation::RootOperation & op )
 
319
{
 
320
        ///We'll just catch the call and write something to both the log and the console, and then pass it on.
 
321
        const std::list<std::string> &p = op->getParents();
 
322
        std::list<std::string>::const_iterator I = p.begin();
 
323
        
 
324
        if (I != p.end()) {
 
325
        
 
326
                const std::string& name = *I;
 
327
                std::string message = getName() + " emits a " + name + ".";
 
328
                
 
329
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage(message);
 
330
                
 
331
                S_LOG_VERBOSE( "Entity: " << this->getId() << " (" << this->getName() << ") sound action: " << name);
 
332
        }
 
333
        
 
334
        Eris::Entity::onSoundAction(op);
 
335
}
 
336
 
 
337
 
 
338
void EmberEntity::onVisibilityChanged(bool vis)
 
339
{
 
340
        checkClientVisibility(vis);
 
341
        Eris::Entity::onVisibilityChanged(vis);
 
342
}
 
343
 
 
344
void EmberEntity::checkClientVisibility(bool vis)
 
345
{
 
346
        ///since we don't want to show all entities solely by their server flags (for example, an inventory item belonging to a character might not be shown even though the server thinks it's visible) we have to some more checks before we decide whether to show this or not
 
347
        EmberEntity* container = static_cast<EmberEntity*>(getLocation());
 
348
        if (container) {
 
349
                ///check with the parent first if we should show ourselves
 
350
                if (vis && container->allowVisibilityOfMember(this)) {
 
351
                        ///don't cascade, only change the top node
 
352
                        setClientVisible(true); 
 
353
                } else {
 
354
                        setClientVisible(false);        
 
355
                }
 
356
                
 
357
        } else {
 
358
                setClientVisible(vis);
 
359
        }
 
360
}
 
361
 
 
362
 
 
363
void EmberEntity::setClientVisible(bool visible)
 
364
{
 
365
        ///when entities are hidden, we detach them from the rendering scene graph altogether. this speeds up Ogre since it doesn't have to calculate visibility for nodes that are hidden anyway
 
366
        if (!visible) {
 
367
                if (getSceneNode()->getParent()) {
 
368
                        getSceneNode()->getParent()->removeChild(getSceneNode());
 
369
                }
 
370
        } else {
 
371
                if (getLocation()) {
 
372
                        if (!getSceneNode()->getParent()) {
 
373
                                getEmberLocation()->getSceneNode()->addChild(getSceneNode());
 
374
                        }
 
375
                }
 
376
        }
 
377
        EventClientVisibilityChanged.emit(visible);
 
378
//      getSceneNode()->setVisible(visible && getLocation(), false);    
 
379
}
 
380
 
 
381
 
 
382
void EmberEntity::adjustPosition()
 
383
{
 
384
        if (getPredictedPos().isValid()) {
 
385
                adjustPosition(Atlas2Ogre( getPredictedPos() ));
 
386
        }
 
387
}
 
388
 
 
389
void EmberEntity::adjustPosition(const Ogre::Vector3& position)
 
390
{
 
391
        if (mMovementMode == MM_FIXED) {
 
392
 
 
393
        } else {
 
394
                EmberEntity* container = getEmberLocation();
 
395
                if (container) {
 
396
                        container->adjustPositionForContainedNode(this, position);
 
397
                }
 
398
        }       
 
399
}
 
400
 
 
401
const Ogre::Vector3& EmberEntity::getOffsetForContainedNode(const Ogre::Vector3& localPosition, EmberEntity* const entity)
 
402
{
 
403
        ///send it upwards until we get a an entity which knows how to set the position (we'll in most cases end up in the world which will adjust the height a bit)
 
404
        EmberEntity* container = getEmberLocation();
 
405
        if (container) {
 
406
                //TerrainPosition derivedPosition(getPredictedPos().x() + position.x(), getPredictedPos().y() + position.y());
 
407
                return container->getOffsetForContainedNode(localPosition + getSceneNode()->getPosition(), entity);
 
408
        } else {
 
409
                return Ogre::Vector3::ZERO;
 
410
        }
 
411
        
 
412
        
 
413
}
 
414
 
 
415
 
 
416
 
 
417
void EmberEntity::adjustPositionForContainedNode(EmberEntity* const entity, const Ogre::Vector3& position) 
 
418
{
 
419
 
 
420
        Ogre::SceneNode* sceneNode = entity->getSceneNode();
 
421
        //Ogre::Vector3 position = sceneNode->getPosition();
 
422
        const Ogre::Vector3& offset = getOffsetForContainedNode(position, entity);
 
423
        if (offset != Ogre::Vector3::ZERO) {
 
424
        
 
425
                sceneNode->setPosition(position + offset);
 
426
        }
 
427
        
 
428
}
 
429
 
 
430
void EmberEntity::onLocationChanged(Eris::Entity *oldLocation)
 
431
{
 
432
        
 
433
        if (getLocation() == oldLocation)
 
434
        {
 
435
                ///If it's the same location, don't do anything, but do add a warning to the log since this isn't supposed to happen.
 
436
                S_LOG_WARNING( "Same new location as old for entity: " << this->getId() << " (" << this->getName() << ")" );
 
437
                return Eris::Entity::onLocationChanged(oldLocation);
 
438
        }
 
439
        Eris::Entity::onLocationChanged(oldLocation);
 
440
        
 
441
        ///Ff we're attached to something, detach from it.
 
442
        detachFromModel();
 
443
 
 
444
        ///Before we detach ourselves from our current parent, we need to record our current position in the world. This will come in handy later on when we need to determine if we actually moved in the world space.
 
445
        const Ogre::Vector3 oldWorldPosition = getSceneNode()->_getDerivedPosition();
 
446
        
 
447
        ///Get the new location. We use getEmberLocation() since we always know that all entities are of type EmberEntity.
 
448
        EmberEntity* newLocationEntity = getEmberLocation();
 
449
        if (getSceneNode()->getParentSceneNode()) {
 
450
                ///Detach from our current parent scene node, removing us from the scene node graph.
 
451
                getSceneNode()->getParentSceneNode()->removeChild(getSceneNode()->getName());
 
452
        }
 
453
        if (!newLocationEntity) {
 
454
                ///If there's no new location, just leave now. We've already removed ourselves from the scene node graph, so this entity is in effect in limbo.
 
455
                return; 
 
456
        } else {
 
457
                
 
458
                ///Add ourselves to the scene node of our parent.
 
459
                newLocationEntity->getSceneNode()->addChild(getSceneNode());
 
460
                S_LOG_VERBOSE( "Entity: " << this->getId() << " (" << this->getName() << ") relocated to: "<< newLocationEntity->getId() << " (" << newLocationEntity->getName() << ")" );
 
461
                if (getPosition().isValid()) {
 
462
                        ///Note that in some instances, for instance when the avatar enters the sty, the position isn't updated yet, which will make the avatar "snap" to an incorrect position (since the parent node has changed) until next frame, when the position should have been updated.
 
463
                        getSceneNode()->setPosition(Atlas2Ogre(getPredictedPos()));
 
464
                        adjustPosition();
 
465
                        std::stringstream ss;
 
466
                        ss << getPredictedPos();
 
467
                        S_LOG_VERBOSE("New position for entity: "  << this->getId() << " (" << this->getName() << " ) :" << ss.str());
 
468
                }
 
469
                if (getOrientation().isValid()) {
 
470
                        getSceneNode()->setOrientation(Atlas2Ogre(getOrientation()));
 
471
                        std::stringstream ss;
 
472
                        ss << getOrientation();
 
473
                        S_LOG_VERBOSE("New orientation for entity: "  << this->getId() << " (" << this->getName() << " ) :" << ss.str());
 
474
                }
 
475
        
 
476
                checkClientVisibility(isVisible());
 
477
        
 
478
                ///we'll adjust the entity so it retains it's former position in the world, but only for moving entities
 
479
                ///since else we'll get a "gap" when we're waiting on updated positions from the server
 
480
                ///this isn't optimal
 
481
                if (isMoving()) {
 
482
                        const Ogre::Vector3& newWorldPosition = getSceneNode()->_getDerivedPosition();
 
483
                        getSceneNode()->translate(oldWorldPosition - newWorldPosition);
 
484
                }
 
485
        }
 
486
        
 
487
}
 
488
 
 
489
void EmberEntity::onAction(const Atlas::Objects::Operation::RootOperation& act)
 
490
{
 
491
        const std::list<std::string> &p = act->getParents();
 
492
        std::list<std::string>::const_iterator I = p.begin();
 
493
        
 
494
        if (I != p.end()) {
 
495
        
 
496
                const std::string& name = *I;
 
497
                std::string message = getName() + " performs a " + name + ".";
 
498
                
 
499
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage(message);
 
500
                
 
501
                S_LOG_VERBOSE( "Entity: " << this->getId() << " (" << this->getName() << ") action: " << name);
 
502
        }
 
503
        Entity::onAction(act);
 
504
}
 
505
 
 
506
void EmberEntity::onImaginary(const Atlas::Objects::Root& act)
 
507
{
 
508
    Atlas::Message::Element attr;
 
509
    if (act->copyAttr("description", attr) && attr.isString()) {
 
510
                std::string message = getName() + " " + attr.asString() + ".";
 
511
                
 
512
                Ember::ConsoleBackend::getSingletonPtr()->pushMessage(message);
 
513
                        
 
514
                S_LOG_VERBOSE("Entity: " << this->getId() << " (" << this->getName() << ") imaginary: " << attr.String());
 
515
    }
 
516
 
 
517
        Entity::onImaginary(act);
 
518
 
 
519
}
 
520
 
 
521
bool EmberEntity::allowVisibilityOfMember(EmberEntity* entity) {
 
522
        return true;
 
523
}
 
524
 
 
525
const std::vector< std::string >& EmberEntity::getSuggestedResponses( ) const
 
526
{
 
527
        return mSuggestedResponses;
 
528
}
 
529
 
 
530
bool EmberEntity::hasSuggestedResponses( ) const
 
531
{
 
532
        return mSuggestedResponses.size() > 0;
 
533
}
 
534
 
 
535
 
 
536
void EmberEntity::addArea(Terrain::TerrainArea* area)
 
537
{
 
538
        ///A normal EmberEntity shouldn't know anything about the terrain, so we can't handle the area here.
 
539
        ///Intead we just pass it on to the parent until we get to someone who knows how to handle this (preferrably the terrain).
 
540
        if (getEmberLocation()) {
 
541
                getEmberLocation()->addArea(area);
 
542
        }
 
543
}
 
544
 
 
545
void EmberEntity::addTerrainMod(Terrain::TerrainMod* mod)
 
546
{
 
547
///Same as addArea: pass it on to the parent until it gets to someone who knows how to handle this
 
548
    if (getEmberLocation()) {
 
549
        getEmberLocation()->addTerrainMod(mod);
 
550
    }
 
551
}
 
552
 
 
553
void EmberEntity::onAttrChanged(const std::string& str, const Atlas::Message::Element& v)
 
554
{
 
555
    if (str == "mode") {
 
556
        parseModeChange(v);
 
557
        } else if (str == "bbox") {
 
558
                Entity::onAttrChanged(str, v);
 
559
                onBboxChanged();
 
560
                return;
 
561
        }
 
562
        
 
563
        ///call this before checking for areas and terrainmods, since those instances created to handle that (TerrainMod and TerrainArea) will listen to the AttrChanged event, which would then be emitted after those have been created, causing duplicate regeneration from the same data
 
564
        Entity::onAttrChanged(str, v);
 
565
        
 
566
        ///Only to this if the entity has been propely initialized, to avoid using incomplete entity data (for example an entity which haven't yet been moved to it's proper place, as well as avoiding duplicate parsing of the same data.
 
567
        if (mIsInitialized) {
 
568
                createDependentObject(str);
 
569
        }
 
570
 
 
571
        
 
572
}
 
573
 
 
574
void EmberEntity::parseModeChange(const Atlas::Message::Element& v)
 
575
{
 
576
        const std::string& mode = v.asString();
 
577
        MovementMode newMode;
 
578
        if (mode.empty()) {
 
579
                newMode = MM_DEFAULT;
 
580
        } else if (mode == MODE_STANDING) {
 
581
                newMode = MM_STANDING;
 
582
        } else if (mode == MODE_RUNNING) {
 
583
                newMode = MM_RUNNING;
 
584
        } else if (mode == MODE_WALKING) {
 
585
                newMode = MM_WALKING;
 
586
        } else if (mode == MODE_SWIMMING) {
 
587
                newMode = MM_SWIMMING;
 
588
        } else if (mode == MODE_FLOATING) {
 
589
                newMode = MM_FLOATING;
 
590
        } else if (mode == MODE_FIXED) {
 
591
                newMode = MM_FIXED;
 
592
        } else {
 
593
                newMode = MM_DEFAULT;
 
594
        }
 
595
        
 
596
        onModeChanged(newMode);
 
597
}
 
598
 
 
599
void EmberEntity::onModeChanged(MovementMode newMode)
 
600
{
 
601
        if (newMode == MM_FIXED) {
 
602
                adjustPosition();
 
603
        }
 
604
        EventModeChanged.emit(newMode);
 
605
        mMovementMode = newMode;
 
606
}
 
607
 
 
608
void EmberEntity::setVisualize(const std::string& visualization, bool visualize)
 
609
{
 
610
        if (visualization == "OgreBBox") {
 
611
                showOgreBoundingBox(visualize);
 
612
        } else if (visualization == "ErisBBox") {
 
613
                showErisBoundingBox(visualize);
 
614
        }
 
615
}
 
616
 
 
617
bool EmberEntity::getVisualize(const std::string& visualization) const
 
618
{
 
619
        if (visualization == "OgreBBox") {
 
620
                return getShowOgreBoundingBox();
 
621
        } else if (visualization == "ErisBBox") {
 
622
                return getShowErisBoundingBox();
 
623
        }
 
624
        return false;
 
625
}
 
626
 
 
627
 
 
628
void EmberEntity::showOgreBoundingBox(bool show)
 
629
{
 
630
        getSceneNode()->showBoundingBox(show);
 
631
}
 
632
 
 
633
void EmberEntity::showErisBoundingBox(bool show)
 
634
{
 
635
 
 
636
        createErisBboxMaterial();
 
637
        
 
638
        ///if there's no bounding box, create one now
 
639
        ///allowing for some lazy loading
 
640
        if (!mErisEntityBoundingBox) {
 
641
                mErisEntityBoundingBox = OGRE_NEW Ogre::OOBBWireBoundingBox();
 
642
                mErisEntityBoundingBox->setMaterial(BboxMaterialName);
 
643
                Ogre::SceneNode* boundingBoxNode = EmberOgre::getSingleton().getWorldSceneNode()->createChildSceneNode();
 
644
                boundingBoxNode->attachObject(mErisEntityBoundingBox);
 
645
                
 
646
                ///if there's no bounding box defined for this entity, show one that is 0.2 meters across in all direction
 
647
                if (hasBBox()) {
 
648
                        mErisEntityBoundingBox->setupBoundingBox(Atlas2Ogre(getBBox()));
 
649
                } else {
 
650
                        mErisEntityBoundingBox->setupBoundingBox(Ogre::AxisAlignedBox(-0.1, -0.1, -0.1, 0.1, 0.1, 0.1));
 
651
                }
 
652
                
 
653
                boundingBoxNode->setPosition(Atlas2Ogre(getPredictedPos()));
 
654
                boundingBoxNode->setOrientation(Atlas2Ogre(getOrientation()));
 
655
        }
 
656
        mErisEntityBoundingBox->setVisible(show);
 
657
        
 
658
}
 
659
 
 
660
void EmberEntity::createErisBboxMaterial()
 
661
{
 
662
        if (!Ogre::MaterialManager::getSingleton().resourceExists(BboxMaterialName)) {
 
663
                Ogre::MaterialPtr baseYellowNoLighting = Ogre::MaterialManager::getSingleton().create(BboxMaterialName, 
 
664
                        Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
 
665
                baseYellowNoLighting->setLightingEnabled(false);
 
666
                baseYellowNoLighting->setAmbient(Ogre::ColourValue(1, 1, 0.7));
 
667
                baseYellowNoLighting->setDiffuse(Ogre::ColourValue(1, 1, 0.7));
 
668
        }
 
669
}
 
670
 
 
671
void EmberEntity::onBboxChanged()
 
672
{
 
673
        if (mErisEntityBoundingBox) {
 
674
                mErisEntityBoundingBox->setupBoundingBox(Atlas2Ogre(getBBox()));
 
675
        }
 
676
}
 
677
 
 
678
 
 
679
bool EmberEntity::getShowOgreBoundingBox() const
 
680
{
 
681
        return getSceneNode()->getShowBoundingBox();
 
682
}
 
683
bool EmberEntity::getShowErisBoundingBox() const
 
684
{
 
685
        return (mErisEntityBoundingBox && mErisEntityBoundingBox->isVisible());
 
686
        
 
687
}
 
688
 
 
689
Ogre::SceneNode* EmberEntity::getSceneNode() const 
 
690
{
 
691
        return mOgreNode;       
 
692
}
 
693
 
 
694
EmberEntity* EmberEntity::getEmberLocation() const
 
695
 
696
        return static_cast<EmberEntity*>(getLocation());
 
697
}
 
698
 
 
699
 
 
700
const Ogre::AxisAlignedBox& EmberEntity::getWorldBoundingBox(bool derive) const
 
701
{
 
702
        static Ogre::AxisAlignedBox boundingBox(0,0,0,0,0,0);
 
703
        return boundingBox;
 
704
}
 
705
        
 
706
const Ogre::Sphere & EmberEntity::getWorldBoundingSphere (bool derive) const
 
707
{
 
708
        static Ogre::Sphere sphere;
 
709
        return sphere;
 
710
}
 
711
 
 
712
std::vector<std::string> EmberEntity::getActions()
 
713
{
 
714
        ///get the actions from Eris and return them a simple vector of strings
 
715
        std::vector<std::string> actions;
 
716
        
 
717
        if (hasAttr("actions")) {
 
718
                const Atlas::Message::Element& operations = valueOfAttr("actions");
 
719
                if (operations.isList()) {
 
720
                        const Atlas::Message::ListType& list = operations.asList();
 
721
                        actions.reserve(list.size());
 
722
                        Atlas::Message::ListType::const_iterator J = list.begin();
 
723
                        for (; J != list.end(); ++J) {
 
724
                                if (J->isString()) {
 
725
                                        actions.push_back(J->asString());
 
726
                                }
 
727
                        }
 
728
                }
 
729
        }
 
730
 
 
731
        return actions;
 
732
}
 
733
 
 
734
std::vector<std::string> EmberEntity::getDefaultUseOperators()
 
735
{
 
736
        ///get the use operations from Eris and return them a simple vector of strings
 
737
        std::vector<std::string> operators;
 
738
        
 
739
        Eris::TypeInfoArray types = getUseOperations();
 
740
        
 
741
        for (Eris::TypeInfoArray::iterator I = types.begin(); I != types.end(); ++I) {
 
742
                operators.push_back((*I)->getName());
 
743
        }
 
744
        
 
745
        return operators;
 
746
}
 
747
 
 
748
Ogre::SceneManager* EmberEntity::getSceneManager()
 
749
{
 
750
        assert(mOgreNode);
 
751
        return mOgreNode->getCreator();
 
752
}
 
753
 
 
754
void EmberEntity::dumpAttributes(std::iostream& outstream, std::ostream& logOutstream) const 
 
755
{
 
756
        logOutstream << "Dumping attributes for entity " << getId() << "(" << getName() << ")" << std::endl;
 
757
        
 
758
        Atlas::Message::QueuedDecoder decoder;
 
759
        //std::fstream file;
 
760
        
 
761
        Atlas::Codecs::XML codec(outstream, decoder);
 
762
        Atlas::Formatter formatter(outstream, codec);
 
763
        Atlas::Message::Encoder encoder(formatter);
 
764
        formatter.streamBegin();
 
765
        encoder.streamMessageElement(getAttributes());
 
766
                
 
767
        formatter.streamEnd();
 
768
}
 
769
 
 
770
}
 
771
 
 
772
 
 
773
 
 
774
 
 
775