Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/HUD_HS16/src/modules/pickup/PickupManager.cc @ 11253

Last change on this file since 11253 was 11253, checked in by patricwi, 8 years ago

core system of keybindings fully functional, graphics still have to be implemented

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