Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7546 was 7539, checked in by dafrick, 14 years ago

Some cleanup in PickupManager.

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