Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Resolving some TODO's.

  • Property svn:eol-style set to native
File size: 25.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      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    PickupRepresentation* PickupManager::getRepresentation(const PickupIdentifier* identifier)
212    {
213        std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
214        if(it == this->representations_.end()) // If there is no PickupRepresentation associated with the input PickupIdentifier.
215        {
216            COUT(4) << "PickupManager::getRepresentation() returned default representation." << std::endl;
217            return this->defaultRepresentation_;
218        }
219
220        return it->second;
221    }
222
223    /**
224    @brief
225        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input used state.
226    @param pickup
227        The Pickupable whose used status changed.
228    @param used
229        The used status the Pickupable changed to.
230    */
231    void PickupManager::pickupChangedUsed(Pickupable* pickup, bool used)
232    {
233        assert(pickup);
234
235        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
236            return;
237
238        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
239        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
240        if(collectible != NULL && collectible->isInCollection())
241            return;
242
243        // Getting clientId of the host this change of the pickup's used status concerns.
244        PickupCarrier* carrier = pickup->getCarrier();
245        while(carrier->getCarrierParent() != NULL)
246            carrier = carrier->getCarrierParent();
247        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
248        if(pawn == NULL)
249            return;
250        PlayerInfo* info = pawn->getPlayer();
251        if(info == NULL)
252            return;
253        unsigned int clientId = info->getClientID();
254
255        // Get the number identifying the pickup.
256        std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
257        assert(it != this->indexes_.end());
258        uint32_t index = it->second;
259
260        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
261        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
262        {
263            PickupManager::pickupChangedUsedNetwork(index, used, pickup->isUsable(), pickup->isUnusable());
264        }
265        // If the concerned host is somewhere in the network, we call pickupChangedUsedNetwork() on its PickupManager.
266        else
267        {
268            callStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork, clientId, index, used, pickup->isUsable(), pickup->isUnusable());
269        }
270    }
271
272    /**
273    @brief
274        Helper method to react to the change in the used status of a Pickupable.
275        Static method that is used by the server to inform the client it concerns about the status change.
276        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
277    @param pickup
278        A number identifying the Pickupable that changed its used status.
279    @param inUse
280        The used status the Pickupable changed to. (i.e. whether the Pickupable is in use or not).
281    @param usable
282        Whether the Pickupable's used status can be changed used in the PickupInventory.
283    @param unusable
284        Whether the Pickupable's used status can be changed to unused in the PickupInventory.
285    */
286    /*static*/ void PickupManager::pickupChangedUsedNetwork(uint32_t pickup, bool inUse, bool usable, bool unusable)
287    {
288        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
289        // If the input Pickupable (i.e its identifier) is not present in the list the PickupManager has.
290        if(manager.pickupInventoryContainers_.find(pickup) == manager.pickupInventoryContainers_.end())
291        {
292            COUT(1) << "Error: Pickupable &(" << pickup << ") was not registered with PickupManager for the PickupInventory, when it changed used." << std::endl;
293            return;
294        }
295
296        // Update the Pickupable's container with the information transferred.
297        manager.pickupInventoryContainers_[pickup]->inUse = inUse;
298        manager.pickupInventoryContainers_[pickup]->usable = usable;
299        manager.pickupInventoryContainers_[pickup]->unusable = unusable;
300
301        manager.updateGUI(); // Tell the PickupInventory that something has changed.
302    }
303
304    /**
305    @brief
306        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input pickedUp state.
307    @param pickup
308        The Pickupable whose pickedUp status changed.
309    @param pickedUp
310        The pickedUp status the Pickupable changed to.
311    */
312    void PickupManager::pickupChangedPickedUp(Pickupable* pickup, bool pickedUp)
313    {
314        assert(pickup);
315
316        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
317            return;
318
319        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
320        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
321        if(collectible != NULL && collectible->isInCollection())
322            return;
323
324        // Getting clientId of the host this change of the pickup's pickedUp status concerns.
325        PickupCarrier* carrier = pickup->getCarrier();
326        while(carrier->getCarrierParent() != NULL)
327            carrier = carrier->getCarrierParent();
328        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
329        if(pawn == NULL)
330            return;
331        PlayerInfo* info = pawn->getFormerPlayer();
332        if(info == NULL)
333            return;
334        unsigned int clientId = info->getClientID();
335
336        uint32_t index = 0;
337        if(pickedUp) // If the Pickupable has changed to picked up, it is added to the required lists.
338        {
339            index = this->getPickupIndex(); // Ge a new identifier (index) for the Pickupable.
340            // Add the Pickupable to the indexes_ and pickups_ lists.
341            this->indexes_[pickup] = index;
342            this->pickups_[index] = new WeakPtr<Pickupable>(pickup);
343        }
344        else // If it was dropped, it is removed from the required lists.
345        {
346            // Get the indentifier (index) that identifies the input Pickupable.
347            std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
348            index = it->second;
349
350            // Remove the Pickupable form the indexes_ and pickups_ list.
351            WeakPtr<Pickupable>* ptr = this->pickups_[index];
352            this->indexes_.erase(it);
353            this->pickups_.erase(index);
354            delete ptr;
355        }
356
357        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
358        //TODO: Needs to be added to server even if is was not picked up by it?
359        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
360        {
361            // If there is no PickupRepresentation registered the default representation is used.
362            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
363                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
364            else
365                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
366        }
367        // If the concerned host is somewhere in the network, we call pickupChangedPickedUpNetwork() on its PickupManager.
368        else
369        {
370            // If there is no PickupRepresentation registered the default representation is used.
371            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
372            {
373                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
374            }
375            else
376            {
377                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
378            }
379        }
380
381    }
382
383    /**
384    @brief
385        Helper method to react to the change in the pickedUp status of a Pickupable.
386        Static method that is used by the server to inform the client it concerns about the status change.
387        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
388    @param pickup
389        A number identifying the Pickupable that changed its pickedUp status.
390    @param usable
391        Whether the Pickupable's used status can be changed to used in the PickupInventory.
392    @param representationObjectId
393        The objectId identifying (over the network) the PickupRepresentation that represents this Pickupable.
394    @param pickedUp
395        The pickedUp status the Pickupable changed to.
396    */
397    /*static*/ void PickupManager::pickupChangedPickedUpNetwork(uint32_t pickup, bool usable, uint32_t representationObjectId, bool pickedUp)
398    {
399        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
400        // If the Pickupable has been picked up, we create a new PickupInventoryContainer for it.
401        if(pickedUp)
402        {
403            // Create a new PickupInventoryContainer for the Pickupable and set all the necessary information.
404            PickupInventoryContainer* container = new PickupInventoryContainer;
405            container->pickup = pickup;
406            container->inUse = false;
407            container->pickedUp = pickedUp;
408            container->usable = usable;
409            container->unusable = false;
410            container->representationObjectId = representationObjectId;
411            // Insert the container into the pickupInventoryContainers_ list.
412            manager.pickupInventoryContainers_.insert(std::pair<uint32_t, PickupInventoryContainer*>(pickup, container));
413
414            manager.updateGUI(); // Tell the PickupInventory that something has changed.
415        }
416        // If the Pickupable has been dropped, we remove it from the pickupInventoryContainers_ list.
417        else
418        {
419            std::map<uint32_t, PickupInventoryContainer*>::iterator it = manager.pickupInventoryContainers_.find(pickup);
420            if(it != manager.pickupInventoryContainers_.end())
421                delete it->second;
422            manager.pickupInventoryContainers_.erase(pickup);
423
424            manager.updateGUI(); // Tell the PickupInventory that something has changed.
425        }
426    }
427
428    /**
429    @brief
430        Get the PickupRepresentation of an input Pickupable.
431        This method spares us the hassle to export the PickupIdentifier class to lua.
432    @param pickup
433        The number identifying the Pickupable whose PickupRepresentation should be returned.
434    @return
435        Returns the PickupRepresentation of the input Pickupable or NULL if an error occurred.
436    */
437    orxonox::PickupRepresentation* PickupManager::getPickupRepresentation(uint32_t pickup)
438    {
439        // Clear and rebuild the representationsNetworked_ list.
440        //TODO: Better solution?
441        this->representationsNetworked_.clear();
442        for(ObjectList<PickupRepresentation>::iterator it = ObjectList<PickupRepresentation>::begin(); it != ObjectList<PickupRepresentation>::end(); ++it)
443            this->representationsNetworked_[it->getObjectID()] = *it;
444
445        // Get the container belonging to the input pickup, if not found return the default representation.
446        std::map<uint32_t, PickupInventoryContainer*>::iterator it = this->pickupInventoryContainers_.find(pickup);
447        if(it == this->pickupInventoryContainers_.end())
448            return this->defaultRepresentation_;
449
450        // 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.
451        std::map<uint32_t, PickupRepresentation*>::iterator it2 = this->representationsNetworked_.find(it->second->representationObjectId);
452        if(it2 == this->representationsNetworked_.end())
453            return this->defaultRepresentation_;
454
455        return it2->second;
456    }
457
458    /**
459    @brief
460        Get the number of pickups currently picked up by the player.
461        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.
462    @return
463        Returns the number of the players picked up Pickupables.
464    */
465    int PickupManager::getNumPickups(void)
466    {
467        this->pickupsIterator_ = this->pickupInventoryContainers_.begin(); // Reset iterator.
468
469        return this->pickupInventoryContainers_.size();
470    }
471
472    /**
473    @brief
474        Drop the input Pickupable.
475        This method checks whether the input Pickupable still exists and drops it, if so.
476    @param pickup
477        The identifier of the Pickupable to be dropped.
478    */
479    void PickupManager::dropPickup(uint32_t pickup)
480    {
481        // If we're either server or standalone and the list of pickups is not empty, we find and drop the input pickup.
482        if(GameMode::isMaster())
483        {
484            if(this->pickups_.empty())
485                return;
486            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
487            if(pickupable != NULL)
488                pickupable->drop();
489        }
490        // If we're neither server nor standalone we drop the pickup by calling dropPickupNetworked() of the PickupManager on the server.
491        else
492        {
493            callStaticNetworkFunction(PickupManager::dropPickupNetworked, 0, pickup);
494        }
495    }
496
497    /**
498    @brief
499        Helper method to drop the input pickup on the server.
500        Static method that is used by clients to instruct the server to drop the input pickup.
501    @param pickup
502        The identifier of the Pickupable to be dropped.
503    */
504    /*static*/ void PickupManager::dropPickupNetworked(uint32_t pickup)
505    {
506        if(GameMode::isServer()) // Obviously we only want to do this on the server.
507        {
508            PickupManager& manager = PickupManager::getInstance();
509            manager.dropPickup(pickup);
510        }
511    }
512
513    /**
514    @brief
515        Use (or unuse) the input Pickupable.
516        This method checks whether the input Pickupable still exists and uses (or unuses) it, if so,
517    @param pickup
518        The identifier of the Pickupable to be used (or unused).
519    @param use
520        If true the input Pickupable is used, if false it is unused.
521    */
522    void PickupManager::usePickup(uint32_t pickup, bool use)
523    {
524        // 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.
525        if(GameMode::isMaster())
526        {
527            if(this->pickups_.empty())
528                return;
529            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
530            if(pickupable != NULL)
531                pickupable->setUsed(use);
532        }
533        // If we're neither server nor standalone we change the used status of the pickup by calling usePickupNetworked() of the PickupManager on the server.
534        else
535        {
536            callStaticNetworkFunction(PickupManager::usePickupNetworked, 0, pickup, use);
537        }
538    }
539
540    /**
541    @brief
542        Helper method to use (or unuse) the input Pickupable on the server.
543        Static method that is used by clients to instruct the server to use (or unuse) the input pickup.
544    @param pickup
545        The identifier of the Pickupable to be used (or unused).
546    @param use
547        If true the input Pickupable is used, if false it is unused.
548    */
549    /*static*/ void PickupManager::usePickupNetworked(uint32_t pickup, bool use)
550    {
551        if(GameMode::isServer())
552        {
553            PickupManager& manager = PickupManager::getInstance();
554            manager.usePickup(pickup, use);
555        }
556    }
557
558    /**
559    @brief
560        Updates the PickupInventory GUI.
561        Also loads the PickupInventory GUI if is hasn't been done already.
562    */
563    inline void PickupManager::updateGUI(void)
564    {
565        // We only need to update (and load) the GUI if this host shows graphics.
566        if(GameMode::showsGraphics())
567        {
568            if(!this->guiLoaded_) // If the GUI hasn't been loaded, yet, we load it.
569            {
570                GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
571                this->guiLoaded_ = true;
572            }
573
574            // Update the GUI.
575            GUIManager::getInstance().getLuaState()->doString(PickupManager::guiName_s + ".update()");
576        }
577    }
578
579    /**
580    @brief
581        Get a new index for a Pickupable.
582        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.
583    @return
584        Returns the new index.
585    */
586    uint32_t PickupManager::getPickupIndex(void)
587    {
588        if(this->pickupHighestIndex_ == uint32_t(~0x0)-1) // If we've reached the highest possible number, we wrap around.
589            this->pickupHighestIndex_ = 0;
590        return this->pickupHighestIndex_++;
591    }
592
593}
Note: See TracBrowser for help on using the repository browser.