Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9675 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

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