Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/pickup/PickupManager.cc @ 8783

Last change on this file since 8783 was 8729, checked in by rgrieder, 13 years ago

Merged unity_build branch back to trunk.

Features:

  • Implemented fully automatic build units to speed up compilation if requested
  • Added DOUT macro for quick debug output
  • Activated text colouring in the POSIX IOConsole
  • DeclareToluaInterface is not necessary anymore

Improvements:

  • Output levels now change appropriately when switch back and forth from dev mode
  • Log level for the file output is now also correct during startup
  • Removed some header file dependencies in core and tools to speed up compilation

no more file for command line options

  • Improved util::tribool by adapting some concepts from boost::tribool

Regressions:

  • It is not possible anymore to specify command line arguments in an extra file because we've got config values for that purpose.
  • Property svn:eol-style set to native
File size: 24.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      ...
26 *
27*/
28
29/**
30    @file PickupManager.cc
31    @brief Implementation of the PickupManager class.
32*/
33
34#include "PickupManager.h"
35
36#include "core/CoreIncludes.h"
37#include "core/LuaState.h"
38#include "core/GUIManager.h"
39#include "core/Identifier.h"
40#include "network/Host.h"
41#include "network/NetworkFunction.h"
42#include "util/ScopedSingletonManager.h"
43
44#include "infos/PlayerInfo.h"
45#include "interfaces/PickupCarrier.h"
46#include "worldentities/pawns/Pawn.h"
47
48#include "CollectiblePickup.h"
49#include "PickupRepresentation.h"
50
51namespace orxonox
52{
53    ManageScopedSingleton(PickupManager, ScopeID::Root, false);
54
55    // Initialization of the name of the PickupInventory GUI.
56    /*static*/ const std::string PickupManager::guiName_s = "PickupInventory";
57
58    // Register static network functions that are used to communicate changes to pickups over the network, such that the PickupInventory can display the information about the pickups properly.
59    registerStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork);
60    registerStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork);
61    registerStaticNetworkFunction(PickupManager::dropPickupNetworked);
62    registerStaticNetworkFunction(PickupManager::usePickupNetworked);
63
64    /**
65    @brief
66        Constructor. Registers the PickupManager and creates the default PickupRepresentation.
67    */
68    PickupManager::PickupManager() : guiLoaded_(false), pickupHighestIndex_(0), defaultRepresentation_(NULL)
69    {
70        RegisterObject(PickupManager);
71
72        this->defaultRepresentation_ = new PickupRepresentation();
73
74        COUT(3) << "PickupManager created." << std::endl;
75    }
76
77    /**
78    @brief
79        Destructor.
80        Destroys the default PickupRepresentation and does some cleanup.
81    */
82    PickupManager::~PickupManager()
83    {
84        // Destroying the default representation.
85        if(this->defaultRepresentation_ != NULL)
86            this->defaultRepresentation_->destroy();
87
88        this->representations_.clear();
89        this->representationsNetworked_.clear();
90
91        // Destroying all the PickupInventoryContainers that are still there.
92        for(std::map<uint32_t, PickupInventoryContainer*>::iterator it = this->pickupInventoryContainers_.begin(); it != this->pickupInventoryContainers_.end(); it++)
93            delete it->second;
94        this->pickupInventoryContainers_.clear();
95
96        // Destroying all the WeakPointers that are still there.
97        for(std::map<uint32_t, WeakPtr<Pickupable>*>::iterator it = this->pickups_.begin(); it != this->pickups_.end(); it++)
98            delete it->second;
99        this->pickups_.clear();
100
101        this->indexes_.clear();
102
103        COUT(3) << "PickupManager destroyed." << std::endl;
104    }
105
106    /**
107    @brief
108        Registers a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents, on the server (or in standalone mode).
109        For every type of Pickupable (uniquely identified by a PickupIdentifier) there can be one (and just one) PickupRepresentation registered.
110    @param identifier
111        The PickupIdentifier identifying the Pickupable.
112    @param representation
113        A pointer to the PickupRepresentation.
114    @return
115        Returns true if successful and false if not.
116    */
117    bool PickupManager::registerRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
118    {
119        assert(identifier);
120        assert(representation);
121
122        // If the list is not empty and Pickupable already has a Representation registered.
123        if(!this->representations_.empty() && this->representations_.find(identifier) != this->representations_.end())
124            return false;
125
126        this->representations_[identifier] = representation;
127
128        COUT(4) << "PickupRepresentation &" << representation << " registered with the PickupManager." << std::endl;
129        return true;
130    }
131
132    /**
133    @brief
134        Unegisters a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents, on the server (or in standalone mode).
135    @param identifier
136        The PickupIdentifier identifying the Pickupable.
137    @param representation
138        A pointer to the PickupRepresentation.
139    @return
140        Returns true if successful and false if not.
141    */
142    bool PickupManager::unregisterRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
143    {
144        assert(identifier);
145        assert(representation);
146
147        std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
148        if(it == this->representations_.end()) // If the Pickupable is not registered in the first place.
149            return false;
150
151        this->representations_.erase(it);
152
153        COUT(4) << "PickupRepresentation &" << representation << " unregistered with the PickupManager." << std::endl;
154        return true;
155    }
156
157    /**
158    @brief
159        Registers a PickupRepresentation on the host it was created.
160    @param representation
161        A pointer to the PickupRepresentation.
162    @return
163        Returns true if successful, false if not.
164    */
165    bool PickupManager::registerRepresentation(PickupRepresentation* representation)
166    {
167        assert(representation);
168
169        // If the list is not empty and PickupRepresentation is already registered.
170        if(!this->representationsNetworked_.empty() && this->representationsNetworked_.find(representation->getObjectID()) != this->representationsNetworked_.end())
171            return false;
172
173        this->representationsNetworked_[representation->getObjectID()] = representation;
174        return true;
175    }
176
177    /**
178    @brief
179        Unregisters a PickupRepresentation on the host it is being destroyed (which is the same host on which it was created).
180    @param representation
181        A pointer to the Pickuprepresentation.
182    @return
183        Returns true if successful, false if not.
184    */
185    bool PickupManager::unregisterRepresentation(PickupRepresentation* representation)
186    {
187        assert(representation);
188
189        std::map<uint32_t, PickupRepresentation*>::iterator it = this->representationsNetworked_.find(representation->getObjectID());
190        if(it == this->representationsNetworked_.end()) // If the Pickupable is not registered in the first place.
191            return false;
192
193        this->representationsNetworked_.erase(it);
194        return true;
195    }
196
197    /**
198    @brief
199        Get the PickupRepresentation representing the Pickupable with the input PickupIdentifier.
200    @param identifier
201        The PickupIdentifier.
202    @return
203        Returns a pointer to the PickupRepresentation.
204    */
205    PickupRepresentation* PickupManager::getRepresentation(const PickupIdentifier* identifier)
206    {
207        std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
208        if(it == this->representations_.end()) // If there is no PickupRepresentation associated with the input PickupIdentifier.
209        {
210            COUT(4) << "PickupManager::getRepresentation() returned default representation." << std::endl;
211            return this->defaultRepresentation_;
212        }
213
214        return it->second;
215    }
216
217    /**
218    @brief
219        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input used state.
220    @param pickup
221        The Pickupable whose used status changed.
222    @param used
223        The used status the Pickupable changed to.
224    */
225    void PickupManager::pickupChangedUsed(Pickupable* pickup, bool used)
226    {
227        assert(pickup);
228
229        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
230            return;
231
232        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
233        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
234        if(collectible != NULL && collectible->isInCollection())
235            return;
236
237        // Getting clientId of the host this change of the pickup's used status concerns.
238        PickupCarrier* carrier = pickup->getCarrier();
239        while(carrier->getCarrierParent() != NULL)
240            carrier = carrier->getCarrierParent();
241        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
242        if(pawn == NULL)
243            return;
244        PlayerInfo* info = pawn->getPlayer();
245        if(info == NULL)
246            return;
247        unsigned int clientId = info->getClientID();
248
249        // Get the number identifying the pickup.
250        std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
251        assert(it != this->indexes_.end());
252        uint32_t index = it->second;
253
254        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
255        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
256        {
257            PickupManager::pickupChangedUsedNetwork(index, used, pickup->isUsable(), pickup->isUnusable());
258        }
259        // If the concerned host is somewhere in the network, we call pickupChangedUsedNetwork() on its PickupManager.
260        else
261        {
262            callStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork, clientId, index, used, pickup->isUsable(), pickup->isUnusable());
263        }
264    }
265
266    /**
267    @brief
268        Helper method to react to the change in the used status of a Pickupable.
269        Static method that is used by the server to inform the client it concerns about the status change.
270        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
271    @param pickup
272        A number identifying the Pickupable that changed its used status.
273    @param inUse
274        The used status the Pickupable changed to. (i.e. whether the Pickupable is in use or not).
275    @param usable
276        Whether the Pickupable's used status can be changed used in the PickupInventory.
277    @param unusable
278        Whether the Pickupable's used status can be changed to unused in the PickupInventory.
279    */
280    /*static*/ void PickupManager::pickupChangedUsedNetwork(uint32_t pickup, bool inUse, bool usable, bool unusable)
281    {
282        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
283        // If the input Pickupable (i.e its identifier) is not present in the list the PickupManager has.
284        if(manager.pickupInventoryContainers_.find(pickup) == manager.pickupInventoryContainers_.end())
285        {
286            COUT(1) << "Error: Pickupable &(" << pickup << ") was not registered with PickupManager for the PickupInventory, when it changed used." << std::endl;
287            return;
288        }
289
290        // Update the Pickupable's container with the information transferred.
291        manager.pickupInventoryContainers_[pickup]->inUse = inUse;
292        manager.pickupInventoryContainers_[pickup]->usable = usable;
293        manager.pickupInventoryContainers_[pickup]->unusable = unusable;
294
295        manager.updateGUI(); // Tell the PickupInventory that something has changed.
296    }
297
298    /**
299    @brief
300        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input pickedUp state.
301    @param pickup
302        The Pickupable whose pickedUp status changed.
303    @param pickedUp
304        The pickedUp status the Pickupable changed to.
305    */
306    void PickupManager::pickupChangedPickedUp(Pickupable* pickup, bool pickedUp)
307    {
308        assert(pickup);
309
310        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
311            return;
312
313        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
314        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
315        if(collectible != NULL && collectible->isInCollection())
316            return;
317
318        // Getting clientId of the host this change of the pickup's pickedUp status concerns.
319        PickupCarrier* carrier = pickup->getCarrier();
320        while(carrier->getCarrierParent() != NULL)
321            carrier = carrier->getCarrierParent();
322        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
323        if(pawn == NULL)
324            return;
325        PlayerInfo* info = pawn->getFormerPlayer();
326        if(info == NULL)
327            return;
328        unsigned int clientId = info->getClientID();
329
330        uint32_t index = 0;
331        if(pickedUp) // If the Pickupable has changed to picked up, it is added to the required lists.
332        {
333            index = this->getPickupIndex(); // Ge a new identifier (index) for the Pickupable.
334            // Add the Pickupable to the indexes_ and pickups_ lists.
335            this->indexes_[pickup] = index;
336            this->pickups_[index] = new WeakPtr<Pickupable>(pickup);
337        }
338        else // If it was dropped, it is removed from the required lists.
339        {
340            // Get the indentifier (index) that identifies the input Pickupable.
341            std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
342            index = it->second;
343
344            // Remove the Pickupable form the indexes_ and pickups_ list.
345            WeakPtr<Pickupable>* ptr = this->pickups_[index];
346            this->indexes_.erase(it);
347            this->pickups_.erase(index);
348            delete ptr;
349        }
350
351        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
352        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
353        {
354            // If there is no PickupRepresentation registered the default representation is used.
355            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
356                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
357            else
358                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
359        }
360        // If the concerned host is somewhere in the network, we call pickupChangedPickedUpNetwork() on its PickupManager.
361        else
362        {
363            // If there is no PickupRepresentation registered the default representation is used.
364            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
365            {
366                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
367            }
368            else
369            {
370                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
371            }
372        }
373
374    }
375
376    /**
377    @brief
378        Helper method to react to the change in the pickedUp status of a Pickupable.
379        Static method that is used by the server to inform the client it concerns about the status change.
380        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
381    @param pickup
382        A number identifying the Pickupable that changed its pickedUp status.
383    @param usable
384        Whether the Pickupable's used status can be changed to used in the PickupInventory.
385    @param representationObjectId
386        The objectId identifying (over the network) the PickupRepresentation that represents this Pickupable.
387    @param pickedUp
388        The pickedUp status the Pickupable changed to.
389    */
390    /*static*/ void PickupManager::pickupChangedPickedUpNetwork(uint32_t pickup, bool usable, uint32_t representationObjectId, bool pickedUp)
391    {
392        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
393        // If the Pickupable has been picked up, we create a new PickupInventoryContainer for it.
394        if(pickedUp)
395        {
396            // Create a new PickupInventoryContainer for the Pickupable and set all the necessary information.
397            PickupInventoryContainer* container = new PickupInventoryContainer;
398            container->pickup = pickup;
399            container->inUse = false;
400            container->pickedUp = pickedUp;
401            container->usable = usable;
402            container->unusable = false;
403            container->representationObjectId = representationObjectId;
404            // Insert the container into the pickupInventoryContainers_ list.
405            manager.pickupInventoryContainers_.insert(std::pair<uint32_t, PickupInventoryContainer*>(pickup, container));
406
407            manager.updateGUI(); // Tell the PickupInventory that something has changed.
408        }
409        // If the Pickupable has been dropped, we remove it from the pickupInventoryContainers_ list.
410        else
411        {
412            std::map<uint32_t, PickupInventoryContainer*>::iterator it = manager.pickupInventoryContainers_.find(pickup);
413            if(it != manager.pickupInventoryContainers_.end())
414                delete it->second;
415            manager.pickupInventoryContainers_.erase(pickup);
416
417            manager.updateGUI(); // Tell the PickupInventory that something has changed.
418        }
419    }
420
421    /**
422    @brief
423        Get the PickupRepresentation of an input Pickupable.
424        This method spares us the hassle to export the PickupIdentifier class to lua.
425    @param pickup
426        The number identifying the Pickupable whose PickupRepresentation should be returned.
427    @return
428        Returns the PickupRepresentation of the input Pickupable or NULL if an error occurred.
429    */
430    orxonox::PickupRepresentation* PickupManager::getPickupRepresentation(uint32_t pickup)
431    {
432        // Clear and rebuild the representationsNetworked_ list.
433        //TODO: Better solution?
434        this->representationsNetworked_.clear();
435        for(ObjectList<PickupRepresentation>::iterator it = ObjectList<PickupRepresentation>::begin(); it != ObjectList<PickupRepresentation>::end(); ++it)
436            this->representationsNetworked_[it->getObjectID()] = *it;
437
438        // Get the container belonging to the input pickup, if not found return the default representation.
439        std::map<uint32_t, PickupInventoryContainer*>::iterator it = this->pickupInventoryContainers_.find(pickup);
440        if(it == this->pickupInventoryContainers_.end())
441            return this->defaultRepresentation_;
442
443        // Get the PickupRepresentation of the input pickup (through the objecId of the representation stored in the PickupInventoryContainer belonging to the pickup), if not found return the default representation.
444        std::map<uint32_t, PickupRepresentation*>::iterator it2 = this->representationsNetworked_.find(it->second->representationObjectId);
445        if(it2 == this->representationsNetworked_.end())
446            return this->defaultRepresentation_;
447
448        return it2->second;
449    }
450
451    /**
452    @brief
453        Get the number of pickups currently picked up by the player.
454        This method is used in lua to populate the PickupInventory. The intended usage is to call this method to reset the iterator of the list of PickupInventoryContainers and then use popPickup() to get the individual PickupInventoryContainers.
455    @return
456        Returns the number of the players picked up Pickupables.
457    */
458    int PickupManager::getNumPickups(void)
459    {
460        this->pickupsIterator_ = this->pickupInventoryContainers_.begin(); // Reset iterator.
461
462        return this->pickupInventoryContainers_.size();
463    }
464
465    /**
466    @brief
467        Drop the input Pickupable.
468        This method checks whether the input Pickupable still exists and drops it, if so.
469    @param pickup
470        The identifier of the Pickupable to be dropped.
471    */
472    void PickupManager::dropPickup(uint32_t pickup)
473    {
474        // If we're either server or standalone and the list of pickups is not empty, we find and drop the input pickup.
475        if(GameMode::isMaster())
476        {
477            if(this->pickups_.empty())
478                return;
479            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
480            if(pickupable != NULL)
481                pickupable->drop();
482        }
483        // If we're neither server nor standalone we drop the pickup by calling dropPickupNetworked() of the PickupManager on the server.
484        else
485        {
486            callStaticNetworkFunction(PickupManager::dropPickupNetworked, 0, pickup);
487        }
488    }
489
490    /**
491    @brief
492        Helper method to drop the input pickup on the server.
493        Static method that is used by clients to instruct the server to drop the input pickup.
494    @param pickup
495        The identifier of the Pickupable to be dropped.
496    */
497    /*static*/ void PickupManager::dropPickupNetworked(uint32_t pickup)
498    {
499        if(GameMode::isServer()) // Obviously we only want to do this on the server.
500        {
501            PickupManager& manager = PickupManager::getInstance();
502            manager.dropPickup(pickup);
503        }
504    }
505
506    /**
507    @brief
508        Use (or unuse) the input Pickupable.
509        This method checks whether the input Pickupable still exists and uses (or unuses) it, if so,
510    @param pickup
511        The identifier of the Pickupable to be used (or unused).
512    @param use
513        If true the input Pickupable is used, if false it is unused.
514    */
515    void PickupManager::usePickup(uint32_t pickup, bool use)
516    {
517        // If we're either server or standalone and the list of pickups is not empty, we find and change the used status of the input pickup.
518        if(GameMode::isMaster())
519        {
520            if(this->pickups_.empty())
521                return;
522            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
523            if(pickupable != NULL)
524                pickupable->setUsed(use);
525        }
526        // If we're neither server nor standalone we change the used status of the pickup by calling usePickupNetworked() of the PickupManager on the server.
527        else
528        {
529            callStaticNetworkFunction(PickupManager::usePickupNetworked, 0, pickup, use);
530        }
531    }
532
533    /**
534    @brief
535        Helper method to use (or unuse) the input Pickupable on the server.
536        Static method that is used by clients to instruct the server to use (or unuse) the input pickup.
537    @param pickup
538        The identifier of the Pickupable to be used (or unused).
539    @param use
540        If true the input Pickupable is used, if false it is unused.
541    */
542    /*static*/ void PickupManager::usePickupNetworked(uint32_t pickup, bool use)
543    {
544        if(GameMode::isServer())
545        {
546            PickupManager& manager = PickupManager::getInstance();
547            manager.usePickup(pickup, use);
548        }
549    }
550
551    /**
552    @brief
553        Updates the PickupInventory GUI.
554        Also loads the PickupInventory GUI if is hasn't been done already.
555    */
556    inline void PickupManager::updateGUI(void)
557    {
558        // We only need to update (and load) the GUI if this host shows graphics.
559        if(GameMode::showsGraphics())
560        {
561            if(!this->guiLoaded_) // If the GUI hasn't been loaded, yet, we load it.
562            {
563                GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
564                this->guiLoaded_ = true;
565            }
566
567            // Update the GUI.
568            GUIManager::getInstance().getLuaState()->doString(PickupManager::guiName_s + ".update()");
569        }
570    }
571
572    /**
573    @brief
574        Get a new index for a Pickupable.
575        This will work as long as the number of Pickupables that are picked up is sufficiently small and as long as they don't exist forever.
576    @return
577        Returns the new index.
578    */
579    uint32_t PickupManager::getPickupIndex(void)
580    {
581        if(this->pickupHighestIndex_ == uint32_t(~0x0)-1) // If we've reached the highest possible number, we wrap around.
582            this->pickupHighestIndex_ = 0;
583        return this->pickupHighestIndex_++;
584    }
585
586}
Note: See TracBrowser for help on using the repository browser.