Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Fixing bug, that caused segfault in pickups with multiplayer.

  • Property svn:eol-style set to native
File size: 17.6 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 "util/Convert.h"
37#include "util/ScopedSingletonManager.h"
38#include "core/CoreIncludes.h"
39#include "core/LuaState.h"
40#include "core/GUIManager.h"
41#include "core/Identifier.h"
42#include "network/Host.h"
43#include "network/NetworkFunction.h"
44#include "interfaces/PickupCarrier.h"
45#include "infos/PlayerInfo.h"
46#include "worldentities/pawns/Pawn.h"
47#include "CollectiblePickup.h"
48#include "PickupRepresentation.h"
49
50#include "ToluaBindPickup.h"
51
52namespace orxonox
53{
54    // Register tolua_open function when loading the library
55    DeclareToluaInterface(Pickup);
56
57    ManageScopedSingleton(PickupManager, ScopeID::Root, false);
58
59    /*static*/ const std::string PickupManager::guiName_s = "PickupInventory";
60
61    registerStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork);
62    registerStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork);
63    registerStaticNetworkFunction(PickupManager::dropPickupNetworked);
64    registerStaticNetworkFunction(PickupManager::usePickupNetworked);
65
66    /**
67    @brief
68        Constructor. Registers the PickupManager and creates the default PickupRepresentation.
69    */
70    PickupManager::PickupManager() : guiLoaded_(false), pickupIndex_(0), defaultRepresentation_(NULL)
71    {
72        RegisterObject(PickupManager);
73
74        this->defaultRepresentation_ = new PickupRepresentation();
75
76        COUT(3) << "PickupManager created." << std::endl;
77    }
78
79    /**
80    @brief
81        Destructor.
82        Destroys the default PickupRepresentation.
83    */
84    PickupManager::~PickupManager()
85    {
86        if(this->defaultRepresentation_ != NULL)
87            this->defaultRepresentation_->destroy();
88
89        this->representations_.clear();
90
91        //TODO: Destroy properly...
92
93        COUT(3) << "PickupManager destroyed." << std::endl;
94    }
95
96    /**
97    @brief
98        Registers a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents.
99        For every type of Pickupable (uniquely idnetified by a PickupIdentifier) there can be one (and just one) PickupRepresentation registered.
100    @param identifier
101        The PickupIdentifier identifying the Pickupable.
102    @param representation
103        A pointer to the PickupRepresentation.
104    @return
105        Returns true if successful and false if not.
106    */
107    bool PickupManager::registerRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
108    {
109        assert(identifier);
110        assert(representation);
111
112        if(!this->representations_.empty() && this->representations_.find(identifier) != this->representations_.end()) // If the Pickupable already has a Representation registered.
113            return false;
114
115        this->representations_[identifier] = representation;
116
117        COUT(4) << "PickupRepresentation &" << representation << " registered with the PickupManager." << std::endl;
118        return true;
119    }
120
121    bool PickupManager::registerRepresentation(PickupRepresentation* representation)
122    {
123        assert(representation);
124
125        if(!this->representationsNetworked_.empty() && this->representationsNetworked_.find(representation->getObjectID()) != this->representationsNetworked_.end()) // If the PickupRepresentation is already registered.
126            return false;
127
128        this->representationsNetworked_[representation->getObjectID()] = representation;
129        return true;
130    }
131
132    /**
133    @brief
134        Unegisters a PickupRepresentation together with the PickupIdentifier of the Pickupable the PickupRepresentation represents.
135    @param identifier
136        The PickupIdentifier identifying the Pickupable.
137    @param representation
138        A pointer to the PickupRepresentation.
139    @return
140        Returns true if successful and false if not.
141    */
142    bool PickupManager::unregisterRepresentation(const PickupIdentifier* identifier, PickupRepresentation* representation)
143    {
144        assert(identifier);
145        assert(representation);
146
147        std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
148        if(it == this->representations_.end()) //!< If the Pickupable is not registered in the first place.
149            return false;
150
151        this->representations_.erase(it);
152
153        COUT(4) << "PickupRepresentation &" << representation << " unregistered with the PickupManager." << std::endl;
154        return true;
155    }
156
157    bool PickupManager::unregisterRepresentation(PickupRepresentation* representation)
158    {
159        assert(representation);
160
161        std::map<uint32_t, PickupRepresentation*>::iterator it = this->representationsNetworked_.find(representation->getObjectID());
162        if(it == this->representationsNetworked_.end()) //!< If the Pickupable is not registered in the first place.
163            return false;
164
165        this->representationsNetworked_.erase(it);
166        return true;
167    }
168
169    /**
170    @brief
171        Get the PickupRepresentation representing the Pickupable with the input PickupIdentifier.
172    @param identifier
173        The PickupIdentifier.
174    @return
175        Returns a pointer to the PickupRepresentation.
176    */
177    PickupRepresentation* PickupManager::getRepresentation(const PickupIdentifier* identifier)
178    {
179        std::map<const PickupIdentifier*, PickupRepresentation*, PickupIdentifierCompare>::iterator it = this->representations_.find(identifier);
180        if(it == this->representations_.end())
181        {
182            COUT(4) << "PickupManager::getRepresentation() returned default representation." << std::endl;
183            return this->defaultRepresentation_;
184        }
185
186        return it->second;
187    }
188
189    /**
190    @brief
191        Get the PickupRepresentation of an input Pickupable.
192        This method spares us the hassle to export the PickupIdentifier class to lua.
193    @param pickup
194        The Pickupable whose PickupRepresentation should be returned.
195    @return
196        Returns the PickupRepresentation of the input Pickupable or NULL if an error occurred.
197    */
198    orxonox::PickupRepresentation* PickupManager::getPickupRepresentation(uint64_t pickup)
199    {
200        this->representationsNetworked_.clear();
201        for(ObjectList<PickupRepresentation>::iterator it = ObjectList<PickupRepresentation>::begin(); it != ObjectList<PickupRepresentation>::end(); ++it)
202            this->representationsNetworked_[it->getObjectID()] = *it;
203
204        std::map<uint64_t, PickupInventoryContainer*>::iterator it = this->pickupInventoryContainers_.find(pickup);
205        if(it == this->pickupInventoryContainers_.end())
206            return this->defaultRepresentation_;
207
208        std::map<uint32_t, PickupRepresentation*>::iterator it2 = this->representationsNetworked_.find(it->second->representationObjectId);
209        if(it2 == this->representationsNetworked_.end())
210            return this->defaultRepresentation_;
211
212        return it2->second;
213    }
214
215    /**
216    @brief
217        Update the list of picked up Pickupables and get the number of Pickupables in the list.
218        This method is used in lua to populate the PickupInventory. The intended usage is to call this method to update the list of Pickupables and then use popPickup() to get the individual Pickupables.
219    @return
220        Returns the number of the players picked up Pickupables.
221    */
222    int PickupManager::getNumPickups(void)
223    {
224        this->pickupsIterator_ = this->pickupInventoryContainers_.begin();
225        return this->pickupInventoryContainers_.size();
226    }
227
228    /**
229    @brief
230        Drop the input Pickupable.
231        This method checks whether the inout Pickupable still exists and drops it, if so.
232    @param pickup
233        The Pickupable to be dropped.
234    */
235    void PickupManager::dropPickup(uint64_t pickup)
236    {
237        if(GameMode::isMaster() && !this->pickups_.empty())
238        {
239            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
240            if(pickupable != NULL)
241                pickupable->drop();
242        }
243        else
244        {
245            callStaticNetworkFunction(PickupManager::dropPickupNetworked, 0, pickup);
246        }
247    }
248
249    /*static*/ void PickupManager::dropPickupNetworked(uint64_t pickup)
250    {
251        if(GameMode::isServer())
252        {
253            PickupManager& manager = PickupManager::getInstance();
254            if(manager.pickups_.empty())
255                return;
256            Pickupable* pickupable = manager.pickups_.find(pickup)->second->get();
257            if(pickupable != NULL)
258                pickupable->drop();
259        }
260    }
261
262    /**
263    @brief
264        Use (or unuse) the input Pickupable.
265        This method checks whether the input Pickupable still exists and uses (or unuses) it, if so,
266    @param pickup
267        The Pickupable to be used (or unused).
268    @param use
269        If true the input Pickupable is used, if false it is unused.
270    */
271    void PickupManager::usePickup(uint64_t pickup, bool use)
272    {
273        if(GameMode::isMaster() && !this->pickups_.empty())
274        {
275            Pickupable* pickupable = this->pickups_.find(pickup)->second->get();
276            if(pickupable != NULL)
277                pickupable->setUsed(use);
278        }
279        else
280        {
281            callStaticNetworkFunction(PickupManager::usePickupNetworked, 0, pickup, use);
282        }
283    }
284
285    /*static*/ void PickupManager::usePickupNetworked(uint64_t pickup, bool use)
286    {
287        if(GameMode::isServer())
288        {
289            PickupManager& manager = PickupManager::getInstance();
290            if(manager.pickups_.empty())
291                return;
292            Pickupable* pickupable = manager.pickups_.find(pickup)->second->get();
293            if(pickupable != NULL)
294                pickupable->setUsed(use);
295        }
296    }
297
298    /**
299    @brief
300        Check whether the input Pickupable is valid, meaning that it is in the PickupManager's list and still exists.
301    @param pickup
302        The Pickupable.
303    @return
304        Returns true if the input Pickupable is still valid, false if not.
305    */
306    bool PickupManager::isValidPickup(uint64_t pickup)
307    {
308        return this->pickups_.find(pickup) != this->pickups_.end();
309    }
310
311    void PickupManager::pickupChangedUsed(Pickupable* pickup, bool used)
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 Picupable 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        PickupCarrier* carrier = pickup->getCarrier();
324        while(carrier->getCarrierParent() != NULL)
325            carrier = carrier->getCarrierParent();
326        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
327        if(pawn == NULL)
328            return;
329        PlayerInfo* info = pawn->getPlayer();
330        if(info == NULL)
331            return;
332        unsigned int clientId = info->getClientID();
333
334        std::map<Pickupable*, uint64_t>::iterator it = this->indexes_.find(pickup);
335        assert(it != this->indexes_.end());
336
337        uint64_t index = it->second;
338        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
339        {
340            PickupManager::pickupChangedUsedNetwork(index, used, pickup->isUsable(), pickup->isUnusable());
341        }
342        else
343        {
344            callStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork, clientId, index, used, pickup->isUsable(), pickup->isUnusable());
345        }
346    }
347
348    /*static*/ void PickupManager::pickupChangedUsedNetwork(uint64_t pickup, bool inUse, bool usable, bool unusable)
349    {
350        PickupManager& manager = PickupManager::getInstance();
351        if(manager.pickupInventoryContainers_.find(pickup) == manager.pickupInventoryContainers_.end())
352        {
353            COUT(1) << "Error: Pickupable &(" << pickup << ") was not registered with PickupManager for the PickupInventory, when it changed used." << std::endl;
354            return;
355        }
356
357        manager.pickupInventoryContainers_[pickup]->inUse = inUse;
358        manager.pickupInventoryContainers_[pickup]->usable = usable;
359        manager.pickupInventoryContainers_[pickup]->unusable = unusable;
360
361        manager.updateGUI();
362    }
363
364    void PickupManager::pickupChangedPickedUp(Pickupable* pickup, bool pickedUp)
365    {
366        assert(pickup);
367
368        if(!GameMode::isMaster())
369            return;
370
371        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
372        // If the Picupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
373        if(collectible != NULL && collectible->isInCollection())
374            return;
375
376        PickupCarrier* carrier = pickup->getCarrier();
377        while(carrier->getCarrierParent() != NULL)
378            carrier = carrier->getCarrierParent();
379        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
380        if(pawn == NULL)
381            return;
382        PlayerInfo* info = pawn->getPlayer();
383        if(info == NULL)
384            return;
385        unsigned int clientId = info->getClientID();
386
387        uint64_t index = 0;
388        if(pickedUp)
389        {
390            index = this->getPickupIndex();
391            this->indexes_[pickup] = index;
392            this->pickups_[index] = new WeakPtr<Pickupable>(pickup);
393        }
394        else
395        {
396            std::map<Pickupable*, uint64_t>::iterator it = this->indexes_.find(pickup);
397            index = it->second;
398            WeakPtr<Pickupable>* ptr = this->pickups_[index];
399            this->indexes_.erase(it);
400            this->pickups_.erase(index);
401            delete ptr;
402        }
403
404        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
405        {
406            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
407                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
408            else
409                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
410        }
411        else
412        {
413            if(this->representations_.find(pickup->getPickupIdentifier()) == this->representations_.end())
414            {
415                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
416            }
417            else
418            {
419                callStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->representations_[pickup->getPickupIdentifier()]->getObjectID(), pickedUp);
420            }
421        }
422
423    }
424
425    /*static*/ void PickupManager::pickupChangedPickedUpNetwork(uint64_t pickup, bool usable, uint32_t representationObjectId, bool pickedUp)
426    {
427        PickupManager& manager = PickupManager::getInstance();
428        if(pickedUp)
429        {
430            PickupInventoryContainer* container = new PickupInventoryContainer;
431            container->pickup = pickup;
432            container->inUse = false;
433            container->pickedUp = pickedUp;
434            container->usable = usable;
435            container->unusable = false;
436            container->representationObjectId = representationObjectId;
437            manager.pickupInventoryContainers_.insert(std::pair<uint64_t, PickupInventoryContainer*>(pickup, container));
438
439            if(GameMode::showsGraphics())
440            {
441                if(!manager.guiLoaded_)
442                {
443                    GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
444                    manager.guiLoaded_ = true;
445                }
446                GUIManager::getInstance().getLuaState()->doString(PickupManager::guiName_s + ".update()");
447            }
448        }
449        else
450        {
451            std::map<uint64_t, PickupInventoryContainer*>::iterator it = manager.pickupInventoryContainers_.find(pickup);
452            if(it != manager.pickupInventoryContainers_.end())
453                delete it->second;
454            manager.pickupInventoryContainers_.erase(pickup);
455
456            manager.updateGUI();
457        }
458    }
459
460    inline void PickupManager::updateGUI(void)
461    {
462        if(GameMode::showsGraphics())
463        {
464            if(!this->guiLoaded_)
465            {
466                GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
467                this->guiLoaded_ = true;
468            }
469            GUIManager::getInstance().getLuaState()->doString(PickupManager::guiName_s + ".update()");
470        }
471    }
472
473    uint64_t PickupManager::getPickupIndex(void)
474    {
475        if(this->pickupIndex_ == uint64_t(~0x0)-1)
476            this->pickupIndex_ = 0;
477        return this->pickupIndex_++;
478    }
479
480}
Note: See TracBrowser for help on using the repository browser.