Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/ControllableEntity.cc @ 8706

Last change on this file since 8706 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: 23.5 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 *      Reto Grieder
26 *
27 */
28
29#include "ControllableEntity.h"
30
31#include <OgreSceneManager.h>
32#include <OgreSceneNode.h>
33
34#include "core/CoreIncludes.h"
35#include "core/ConfigValueIncludes.h"
36#include "core/GameMode.h"
37#include "core/XMLPort.h"
38#include "network/NetworkFunction.h"
39
40#include "Scene.h"
41#include "infos/PlayerInfo.h"
42#include "controllers/NewHumanController.h"
43#include "graphics/Camera.h"
44#include "worldentities/CameraPosition.h"
45#include "overlays/OverlayGroup.h"
46
47namespace orxonox
48{
49    CreateFactory(ControllableEntity);
50
51    registerMemberNetworkFunction( ControllableEntity, fire );
52    registerMemberNetworkFunction( ControllableEntity, setTargetInternal );
53
54    ControllableEntity::ControllableEntity(BaseObject* creator) : MobileEntity(creator)
55    {
56        RegisterObject(ControllableEntity);
57
58        this->bHasLocalController_ = false;
59        this->bHasHumanController_ = false;
60
61        this->server_overwrite_ = 0;
62        this->client_overwrite_ = 0;
63        this->player_ = 0;
64        this->formerPlayer_ = NULL;
65        this->playerID_ = OBJECTID_UNKNOWN;
66        this->hud_ = 0;
67        this->camera_ = 0;
68        this->xmlcontroller_ = 0;
69        this->controller_ = 0;
70        this->reverseCamera_ = 0;
71        this->bDestroyWhenPlayerLeft_ = false;
72        this->cameraPositionRootNode_ = this->node_->createChildSceneNode();
73        this->currentCameraPosition_ = 0;
74        this->bMouseLook_ = false;
75        this->mouseLookSpeed_ = 200;
76
77        this->server_position_         = Vector3::ZERO;
78        this->client_position_         = Vector3::ZERO;
79        this->server_linear_velocity_  = Vector3::ZERO;
80        this->client_linear_velocity_  = Vector3::ZERO;
81        this->server_orientation_      = Quaternion::IDENTITY;
82        this->client_orientation_      = Quaternion::IDENTITY;
83        this->server_angular_velocity_ = Vector3::ZERO;
84        this->client_angular_velocity_ = Vector3::ZERO;
85
86        this->setConfigValues();
87        this->setPriority( Priority::VeryHigh );
88        this->registerVariables();
89    }
90
91    ControllableEntity::~ControllableEntity()
92    {
93        if (this->isInitialized())
94        {
95            this->bDestroyWhenPlayerLeft_ = false;
96
97            if (this->getPlayer() && this->getPlayer()->getControllableEntity() == this)
98                this->getPlayer()->stopControl();
99
100            if (this->xmlcontroller_)
101                this->xmlcontroller_->destroy();
102
103            if (this->hud_)
104                this->hud_->destroy();
105
106            if (this->camera_)
107                this->camera_->destroy();
108
109            for (std::list<SmartPtr<CameraPosition> >::const_iterator it = this->cameraPositions_.begin(); it != this->cameraPositions_.end(); ++it)
110                (*it)->destroy();
111
112            if (this->getScene()->getSceneManager())
113                this->getScene()->getSceneManager()->destroySceneNode(this->cameraPositionRootNode_->getName());
114        }
115    }
116
117    void ControllableEntity::XMLPort(Element& xmlelement, XMLPort::Mode mode)
118    {
119        SUPER(ControllableEntity, XMLPort, xmlelement, mode);
120
121        XMLPortParam(ControllableEntity, "hudtemplate", setHudTemplate, getHudTemplate, xmlelement, mode);
122        XMLPortParam(ControllableEntity, "camerapositiontemplate", setCameraPositionTemplate, getCameraPositionTemplate, xmlelement, mode);
123
124        XMLPortObject(ControllableEntity, CameraPosition, "camerapositions", addCameraPosition, getCameraPosition, xmlelement, mode);
125        XMLPortObject(ControllableEntity, Controller,     "controller",      setXMLController,  getXMLController,  xmlelement, mode);
126    }
127
128    void ControllableEntity::setConfigValues()
129    {
130        SetConfigValue(mouseLookSpeed_, 3.0f);
131    }
132
133    void ControllableEntity::preDestroy()
134    {
135        // HACK - solve this clean and without preDestroy hook for multiplayer where removePlayer() isn't called
136        if (this->isInitialized() && this->bHasLocalController_ && this->bHasHumanController_)
137            this->stopLocalHumanControl();
138    }
139
140    void ControllableEntity::addCameraPosition(CameraPosition* position)
141    {
142        if (!position->getIsAbsolute())
143        {
144            if (position->getAllowMouseLook())
145                position->attachToNode(this->cameraPositionRootNode_);
146            else
147                this->attach(position);
148        }
149        else
150        {
151            WorldEntity* parent = this->getParent();
152            if (parent)
153                parent->attach(position);
154        }
155
156        if (!position->getRenderCamera())
157            this->cameraPositions_.push_back(position);
158        else
159            this->setReverseCamera(position);
160    }
161
162    CameraPosition* ControllableEntity::getCameraPosition(unsigned int index) const
163    {
164        unsigned int i = 0;
165        for (std::list<SmartPtr<CameraPosition> >::const_iterator it = this->cameraPositions_.begin(); it != this->cameraPositions_.end(); ++it)
166        {
167            if (i == index)
168                return (*it);
169            ++i;
170        }
171        return 0;
172    }
173
174    unsigned int ControllableEntity::getCurrentCameraIndex() const
175    {
176        if (this->cameraPositions_.size() <= 0)
177            return 0;
178
179        unsigned int counter = 0;
180        for (std::list<SmartPtr<CameraPosition> >::const_iterator it = this->cameraPositions_.begin(); it != this->cameraPositions_.end(); ++it)
181        {
182            if ((*it) == this->currentCameraPosition_)
183                break;
184            counter++;
185        }
186        if (counter >= this->cameraPositions_.size())
187            return 0;
188
189        return counter;
190    }
191   
192    bool ControllableEntity::setCameraPosition(unsigned int index)
193    {
194        if(this->camera_ != NULL && this->cameraPositions_.size() > 0)
195        {
196            if(index >= this->cameraPositions_.size())
197                index = 0;
198
199            CameraPosition* position = this->getCameraPosition(index);
200            position->attachCamera(this->camera_);
201            this->currentCameraPosition_ = position;
202            return true;
203        }
204
205        return false;
206    }
207
208    void ControllableEntity::switchCamera()
209    {
210        if (this->camera_)
211        {
212            if (this->camera_->getParent() == this && this->cameraPositions_.size() > 0)
213            {
214                this->cameraPositions_.front()->attachCamera(this->camera_);
215                this->currentCameraPosition_ = this->cameraPositions_.front().get();
216            }
217            else if (this->cameraPositions_.size() > 0)
218            {
219                for (std::list<SmartPtr<CameraPosition> >::const_iterator it = this->cameraPositions_.begin(); it != this->cameraPositions_.end(); ++it)
220                {
221                    if ((*it) == this->camera_->getParent())
222                    {
223                        ++it;
224                        if (it != this->cameraPositions_.end())
225                        {
226                            (*it)->attachCamera(this->camera_);
227                            this->currentCameraPosition_ = *it;
228                        }
229                        else
230                        {
231                            (*this->cameraPositions_.begin())->attachCamera(this->camera_);
232                            this->currentCameraPosition_ = *this->cameraPositions_.begin();
233                        }
234                        break;
235                    }
236                }
237            }
238            else
239            {
240                this->camera_->attachToNode(this->cameraPositionRootNode_);
241                this->currentCameraPosition_ = 0;
242            }
243
244            // disable mouse look if the new camera position doesn't allow it
245            if (this->currentCameraPosition_ && !this->currentCameraPosition_->getAllowMouseLook() && this->bMouseLook_)
246                this->mouseLook();
247
248            // disable drag if in mouse look
249            if (this->bMouseLook_)
250                this->getCamera()->setDrag(false);
251        }
252    }
253
254    void ControllableEntity::mouseLook()
255    {
256        // enable mouse look only if allowed - disabling it works always
257        if (this->currentCameraPosition_ && (this->currentCameraPosition_->getAllowMouseLook() || this->bMouseLook_))
258        {
259            this->bMouseLook_ = !this->bMouseLook_;
260
261            if (!this->bMouseLook_)
262            {
263                this->cameraPositionRootNode_->setOrientation(Quaternion::IDENTITY);
264                this->cameraPositionRootNode_->_update(true, false); // update the camera node because otherwise the camera will drag back in position which looks strange
265
266                NewHumanController* controller = dynamic_cast<NewHumanController*>(this->getController());
267                if (controller)
268                    controller->centerCursor();
269            }
270
271            if (this->getCamera())
272            {
273                if (!this->bMouseLook_ && this->currentCameraPosition_->getDrag())
274                    this->getCamera()->setDrag(true);
275                else
276                    this->getCamera()->setDrag(false);
277            }
278        }
279    }
280
281    void ControllableEntity::rotateYaw(const Vector2& value)
282    {
283        if (this->bMouseLook_)
284            this->cameraPositionRootNode_->yaw(Radian(value.y * this->mouseLookSpeed_), Ogre::Node::TS_LOCAL);
285    }
286
287    void ControllableEntity::rotatePitch(const Vector2& value)
288    {
289        if (this->bMouseLook_)
290            this->cameraPositionRootNode_->pitch(Radian(value.y * this->mouseLookSpeed_), Ogre::Node::TS_LOCAL);
291    }
292
293    void ControllableEntity::rotateRoll(const Vector2& value)
294    {
295        if (this->bMouseLook_)
296            this->cameraPositionRootNode_->roll(Radian(value.y * this->mouseLookSpeed_), Ogre::Node::TS_LOCAL);
297    }
298
299    void ControllableEntity::fire(unsigned int firemode)
300    {
301        if(GameMode::isMaster())
302        {
303            this->fired(firemode);
304        }
305        else
306        {
307            callMemberNetworkFunction(ControllableEntity, fire, this->getObjectID(), 0, firemode);
308        }
309    }
310
311    void ControllableEntity::setTarget( WorldEntity* target )
312    {
313        this->target_ = target;
314        if ( !GameMode::isMaster() )
315        {
316            if ( target != 0 )
317            {
318                callMemberNetworkFunction(ControllableEntity, setTargetInternal, this->getObjectID(), 0, target->getObjectID() );
319            }
320           else
321           {
322                callMemberNetworkFunction(ControllableEntity, setTargetInternal, this->getObjectID(), 0, OBJECTID_UNKNOWN );
323           }
324        }
325    }
326
327    void ControllableEntity::setTargetInternal( uint32_t targetID )
328    {
329        this->setTarget( orxonox_cast<WorldEntity*>(Synchronisable::getSynchronisable(targetID)) );
330    }
331
332    void ControllableEntity::setPlayer(PlayerInfo* player)
333    {
334        if (!player)
335        {
336            this->removePlayer();
337            return;
338        }
339
340        this->player_ = player;
341        this->formerPlayer_ = player;
342        this->playerID_ = player->getObjectID();
343        this->bHasLocalController_ = player->isLocalPlayer();
344        this->bHasHumanController_ = player->isHumanPlayer();
345
346        if (this->bHasLocalController_ && this->bHasHumanController_)
347        {
348            this->startLocalHumanControl();
349
350            if (!GameMode::isMaster())
351            {
352                this->client_overwrite_ = this->server_overwrite_;
353                this->setSyncMode(ObjectDirection::Bidirectional);
354            }
355        }
356
357        this->changedPlayer();
358    }
359
360    void ControllableEntity::removePlayer()
361    {
362        if (this->bHasLocalController_ && this->bHasHumanController_)
363            this->stopLocalHumanControl();
364
365        this->player_ = 0;
366        this->playerID_ = OBJECTID_UNKNOWN;
367        this->bHasLocalController_ = false;
368        this->bHasHumanController_ = false;
369        this->setSyncMode(ObjectDirection::ToClient);
370
371        this->changedPlayer();
372
373        if (this->bDestroyWhenPlayerLeft_)
374            this->destroy();
375    }
376
377    void ControllableEntity::networkcallback_changedplayerID()
378    {
379        // just do this in case the entity wasn't yet synchronized when the corresponding PlayerInfo got our objectID
380        if (this->playerID_ != OBJECTID_UNKNOWN)
381        {
382            this->player_ = orxonox_cast<PlayerInfo*>(Synchronisable::getSynchronisable(this->playerID_));
383            if (this->player_ && (this->player_->getControllableEntity() != this))
384                this->player_->startControl(this);
385        }
386    }
387
388    void ControllableEntity::startLocalHumanControl()
389    {
390        if (!this->camera_ && GameMode::showsGraphics())
391        {
392            this->camera_ = new Camera(this);
393            this->camera_->requestFocus();
394            if (!this->cameraPositionTemplate_.empty())
395                this->addTemplate(this->cameraPositionTemplate_);
396            if (this->cameraPositions_.size() > 0)
397            {
398                this->cameraPositions_.front()->attachCamera(this->camera_);
399                this->currentCameraPosition_ = this->cameraPositions_.front();
400            }
401            else
402            {
403                this->camera_->attachToNode(this->cameraPositionRootNode_);
404                this->currentCameraPosition_ = 0;
405            }
406        }
407
408        this->createHud();
409    }
410
411    // HACK-ish
412    void ControllableEntity::createHud(void)
413    {
414        if (!this->hud_ && GameMode::showsGraphics())
415        {
416            if (!this->hudtemplate_.empty())
417            {
418                this->hud_ = new OverlayGroup(this);
419                this->hud_->addTemplate(this->hudtemplate_);
420                this->hud_->setOwner(this);
421            }
422        }
423    }
424
425    void ControllableEntity::destroyHud(void)
426    {
427        if (this->hud_ != NULL)
428        {
429            this->hud_->destroy();
430            this->hud_ = NULL;
431        }
432    }
433
434    void ControllableEntity::stopLocalHumanControl()
435    {
436        if (this->camera_)
437        {
438            this->camera_->detachFromParent();
439            this->camera_->destroy();
440            this->camera_ = 0;
441        }
442
443        if (this->hud_)
444        {
445            this->hud_->destroy();
446            this->hud_ = 0;
447        }
448    }
449
450    void ControllableEntity::setXMLController(Controller* controller)
451    {
452        if (!this->xmlcontroller_)
453        {
454            this->xmlcontroller_ = controller;
455            this->bHasLocalController_ = true;
456            this->xmlcontroller_->setControllableEntity(this);
457        }
458        else
459            COUT(2) << "Warning: ControllableEntity \"" << this->getName() << "\" already has a Controller." << std::endl;
460    }
461
462    void ControllableEntity::parentChanged()
463    {
464        WorldEntity::parentChanged();
465
466        WorldEntity* parent = this->getParent();
467        if (parent)
468        {
469            for (std::list<SmartPtr<CameraPosition> >::iterator it = this->cameraPositions_.begin(); it != this->cameraPositions_.end(); ++it)
470                if ((*it)->getIsAbsolute())
471                    parent->attach((*it));
472        }
473    }
474
475    void ControllableEntity::tick(float dt)
476    {
477        MobileEntity::tick(dt);
478
479        if (this->isActive())
480        {
481            // Check whether Bullet doesn't do the physics for us
482            if (!this->isDynamic())
483            {
484                if (GameMode::isMaster())
485                {
486                    this->server_position_ = this->getPosition();
487                    this->server_orientation_ = this->getOrientation();
488                    this->server_linear_velocity_ = this->getVelocity();
489                    this->server_angular_velocity_ = this->getAngularVelocity();
490                }
491                else if (this->bHasLocalController_)
492                {
493                    this->client_position_ = this->getPosition();
494                    this->client_orientation_ = this->getOrientation();
495                    this->client_linear_velocity_ = this->getVelocity();
496                    this->client_angular_velocity_ = this->getAngularVelocity();
497                }
498            }
499        }
500    }
501
502    void ControllableEntity::registerVariables()
503    {
504        registerVariable(this->cameraPositionTemplate_,  VariableDirection::ToClient);
505        registerVariable(this->hudtemplate_,             VariableDirection::ToClient);
506
507        registerVariable(this->server_position_,         VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processServerPosition));
508        registerVariable(this->server_linear_velocity_,  VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processServerLinearVelocity));
509        registerVariable(this->server_orientation_,      VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processServerOrientation));
510        registerVariable(this->server_angular_velocity_, VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processServerAngularVelocity));
511
512        registerVariable(this->server_overwrite_,        VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processOverwrite));
513        registerVariable(this->client_overwrite_,        VariableDirection::ToServer);
514
515        registerVariable(this->client_position_,         VariableDirection::ToServer, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processClientPosition));
516        registerVariable(this->client_linear_velocity_,  VariableDirection::ToServer, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processClientLinearVelocity));
517        registerVariable(this->client_orientation_,      VariableDirection::ToServer, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processClientOrientation));
518        registerVariable(this->client_angular_velocity_, VariableDirection::ToServer, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::processClientAngularVelocity));
519
520
521        registerVariable(this->playerID_,                VariableDirection::ToClient, new NetworkCallback<ControllableEntity>(this, &ControllableEntity::networkcallback_changedplayerID));
522    }
523
524    void ControllableEntity::processServerPosition()
525    {
526        if (!this->bHasLocalController_)
527            MobileEntity::setPosition(this->server_position_);
528    }
529
530    void ControllableEntity::processServerLinearVelocity()
531    {
532        if (!this->bHasLocalController_)
533            MobileEntity::setVelocity(this->server_linear_velocity_);
534    }
535
536    void ControllableEntity::processServerOrientation()
537    {
538        if (!this->bHasLocalController_)
539            MobileEntity::setOrientation(this->server_orientation_);
540    }
541
542    void ControllableEntity::processServerAngularVelocity()
543    {
544        if (!this->bHasLocalController_)
545            MobileEntity::setAngularVelocity(this->server_angular_velocity_);
546    }
547
548    void ControllableEntity::processOverwrite()
549    {
550        if (this->bHasLocalController_)
551        {
552            this->setPosition(this->server_position_);
553            this->setOrientation(this->server_orientation_);
554            this->setVelocity(this->server_linear_velocity_);
555            this->setAngularVelocity(this->server_angular_velocity_);
556
557            this->client_overwrite_ = this->server_overwrite_;
558        }
559    }
560
561    void ControllableEntity::processClientPosition()
562    {
563        if (this->server_overwrite_ == this->client_overwrite_)
564        {
565            MobileEntity::setPosition(this->client_position_);
566            this->server_position_ = this->getPosition();
567        }
568    }
569
570    void ControllableEntity::processClientLinearVelocity()
571    {
572        if (this->server_overwrite_ == this->client_overwrite_)
573        {
574            MobileEntity::setVelocity(this->client_linear_velocity_);
575            this->server_linear_velocity_ = this->getVelocity();
576        }
577    }
578
579    void ControllableEntity::processClientOrientation()
580    {
581        if (this->server_overwrite_ == this->client_overwrite_)
582        {
583            MobileEntity::setOrientation(this->client_orientation_);
584            this->server_orientation_ = this->getOrientation();
585        }
586    }
587
588    void ControllableEntity::processClientAngularVelocity()
589    {
590        if (this->server_overwrite_ == this->client_overwrite_)
591        {
592            MobileEntity::setAngularVelocity(this->client_angular_velocity_);
593            this->server_angular_velocity_ = this->getAngularVelocity();
594        }
595    }
596
597    void ControllableEntity::setPosition(const Vector3& position)
598    {
599        if (GameMode::isMaster())
600        {
601            MobileEntity::setPosition(position);
602            this->server_position_ = this->getPosition();
603            ++this->server_overwrite_;
604        }
605        else if (this->bHasLocalController_)
606        {
607            MobileEntity::setPosition(position);
608            this->client_position_ = this->getPosition();
609        }
610    }
611
612    void ControllableEntity::setOrientation(const Quaternion& orientation)
613    {
614        if (GameMode::isMaster())
615        {
616            MobileEntity::setOrientation(orientation);
617            this->server_orientation_ = this->getOrientation();
618            ++this->server_overwrite_;
619        }
620        else if (this->bHasLocalController_)
621        {
622            MobileEntity::setOrientation(orientation);
623            this->client_orientation_ = this->getOrientation();
624        }
625    }
626
627    void ControllableEntity::setVelocity(const Vector3& velocity)
628    {
629        if (GameMode::isMaster())
630        {
631            MobileEntity::setVelocity(velocity);
632            this->server_linear_velocity_ = this->getVelocity();
633            ++this->server_overwrite_;
634        }
635        else if (this->bHasLocalController_)
636        {
637            MobileEntity::setVelocity(velocity);
638            this->client_linear_velocity_ = this->getVelocity();
639        }
640    }
641
642    void ControllableEntity::setAngularVelocity(const Vector3& velocity)
643    {
644        if (GameMode::isMaster())
645        {
646            MobileEntity::setAngularVelocity(velocity);
647            this->server_angular_velocity_ = this->getAngularVelocity();
648            ++this->server_overwrite_;
649        }
650        else if (this->bHasLocalController_)
651        {
652            MobileEntity::setAngularVelocity(velocity);
653            this->client_angular_velocity_ = this->getAngularVelocity();
654        }
655    }
656
657    void ControllableEntity::setWorldTransform(const btTransform& worldTrans)
658    {
659        MobileEntity::setWorldTransform(worldTrans);
660        if (GameMode::isMaster())
661        {
662            this->server_position_ = this->getPosition();
663            this->server_orientation_ = this->getOrientation();
664            this->server_linear_velocity_ = this->getVelocity();
665            this->server_angular_velocity_ = this->getAngularVelocity();
666        }
667        else if (this->bHasLocalController_)
668        {
669            this->client_position_ = this->getPosition();
670            this->client_orientation_ = this->getOrientation();
671            this->client_linear_velocity_ = this->getVelocity();
672            this->client_angular_velocity_ = this->getAngularVelocity();
673        }
674    }
675}
Note: See TracBrowser for help on using the repository browser.