Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Resolving some more TODO's.

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