Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/command/ConsoleCommand.cc @ 10346

Last change on this file since 10346 was 10346, checked in by landauf, 9 years ago

moved static contents from ConsoleCommand to ConsoleCommandManager

  • Property svn:eol-style set to native
File size: 21.2 KB
RevLine 
[1505]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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
[7401]29/**
30    @file
31    @brief Implementation of the ConsoleCommand class.
32*/
33
[1505]34#include "ConsoleCommand.h"
35
[7214]36#include "util/Convert.h"
[7203]37#include "core/Language.h"
[7222]38#include "core/GameMode.h"
[7861]39#include "core/input/KeyBinder.h"
40#include "core/input/KeyBinderManager.h"
[7179]41
42namespace orxonox
43{
[7401]44    /**
45        @brief Constructor: Initializes all values and registers the command.
46        @param group The group of the command
47        @param name The name of the command
48        @param executor The executor of the command
49        @param bInitialized If true, the executor is used for both, the definition of the function-header AND to executute the command. If false, the command is inactive and needs to be assigned a function before it can be used.
50    */
[7236]51    ConsoleCommand::ConsoleCommand(const std::string& group, const std::string& name, const ExecutorPtr& executor, bool bInitialized)
[7179]52    {
[7185]53        this->bActive_ = true;
[7215]54        this->bHidden_ = false;
55        this->accessLevel_ = AccessLevel::All;
56
[7214]57        this->baseName_ = name;
[7267]58        this->baseFunctor_ = executor->getFunctor();
[7214]59
[7401]60        for (size_t i = 0; i < MAX_FUNCTOR_ARGUMENTS; ++i)
61            this->argumentCompleter_[i] = 0;
[7215]62
63        this->keybindMode_ = KeybindMode::OnPress;
64        this->inputConfiguredParam_ = -1;
65
[7214]66        if (bInitialized)
67            this->executor_ = executor;
68
[10346]69        ConsoleCommandManager::registerCommand(group, name, this);
[7179]70    }
71
[7401]72    /**
73        @brief Destructor: Unregisters the command.
74    */
[7236]75    ConsoleCommand::~ConsoleCommand()
[7214]76    {
[10346]77        ConsoleCommandManager::unregisterCommand(this);
[7214]78    }
79
[7401]80    /**
81        @brief Registers the command with the same name, but without group, as shortcut.
82    */
[7236]83    ConsoleCommand& ConsoleCommand::addShortcut()
[7179]84    {
[10346]85        ConsoleCommandManager::registerCommand("", this->baseName_, this);
[7179]86        return *this;
87    }
88
[7401]89    /**
90        @brief Registers the command with an alias as shortcut.
91    */
[7236]92    ConsoleCommand& ConsoleCommand::addShortcut(const std::string&  name)
[7179]93    {
[10346]94        ConsoleCommandManager::registerCommand("", name, this);
[7179]95        return *this;
96    }
97
[7401]98    /**
99        @brief Registers the command in a different group but with the same name.
100    */
[7236]101    ConsoleCommand& ConsoleCommand::addGroup(const std::string& group)
[7179]102    {
[10346]103        ConsoleCommandManager::registerCommand(group, this->baseName_, this);
[7179]104        return *this;
105    }
106
[7401]107    /**
108        @brief Registers an alias of the command in a different group with a different name.
109    */
[7236]110    ConsoleCommand& ConsoleCommand::addGroup(const std::string& group, const std::string&  name)
[7179]111    {
[10346]112        ConsoleCommandManager::registerCommand(group, name, this);
[7179]113        return *this;
114    }
115
[7401]116    /**
117        @brief Returns true if the command can be executed right now.
118
119        This returns only true, if the following conditions are met:
120         - The command is active
121         - The command has an executor
122         - The executor has a functor
123         - The functor is static or has an object
124    */
[7236]125    bool ConsoleCommand::isActive() const
[7179]126    {
[7218]127        return (this->bActive_ && this->executor_ && this->executor_->getFunctor() && (this->executor_->getFunctor()->getType() == Functor::Type::Static || this->executor_->getFunctor()->getRawObjectPointer()));
[7214]128    }
129
[7401]130    /**
131        @brief Returns true if the current state of the game matches the required access level.
132    */
[7236]133    bool ConsoleCommand::hasAccess() const
[7222]134    {
135        switch (this->accessLevel_)
136        {
137            case AccessLevel::All:        return true;
138            case AccessLevel::Standalone: return GameMode::isStandalone();
139            case AccessLevel::Master:     return GameMode::isMaster();
[7401]140            case AccessLevel::Server:     return GameMode::isServer();
[7222]141            case AccessLevel::Client:     return GameMode::isClient();
[7401]142            case AccessLevel::Online:     return (GameMode::isServer() || GameMode::isClient());
[7222]143            case AccessLevel::Offline:    return GameMode::isStandalone();
144            case AccessLevel::None:       return false;
145            default:                      return false;
146        }
147    }
148
[7401]149    /**
150        @brief Returns true if the headers of the given functor match the declaration of this command.
151    */
[7236]152    bool ConsoleCommand::headersMatch(const FunctorPtr& functor)
[7214]153    {
[7401]154        // get the minimum of the number of parameters of both commands
[7267]155        unsigned int minparams = std::min(this->baseFunctor_->getParamCount(), functor->getParamCount());
[7214]156
[7401]157        // if the reduced headers don't match -> return false
[7267]158        if (this->baseFunctor_->getHeaderIdentifier(minparams) != functor->getHeaderIdentifier(minparams))
[7214]159            return false;
[7401]160        // if the reduced headers match and the new functor has less or equal parameters -> return true
[7267]161        else if (functor->getParamCount() <= this->baseFunctor_->getParamCount())
[7214]162            return true;
[7401]163        // the headers match but the new functor has more arguments and there is no executor with default-values -> return false
[7214]164        else if (!this->executor_)
165            return false;
[7401]166        // the headers match but the new functor has more arguments, check if the executor has enough default-values
[7214]167        else
[7179]168        {
[7267]169            for (unsigned int i = this->baseFunctor_->getParamCount(); i < functor->getParamCount(); ++i)
170            {
[7214]171                if (!this->executor_->defaultValueSet(i))
[7267]172                {
[8858]173                    orxout(internal_warning, context::commands) << "Default value " << i << " is missing" << endl;
[7214]174                    return false;
[7267]175                }
176            }
[7214]177
[7185]178            return true;
[7179]179        }
[7214]180    }
[7185]181
[7401]182    /**
183        @brief Returns true if the headers of the given executor match the declaration of this command.
184    */
[7236]185    bool ConsoleCommand::headersMatch(const ExecutorPtr& executor)
[7214]186    {
[7401]187        // get the minimum of the number of parameters of both commands
[7267]188        unsigned int minparams = std::min(this->baseFunctor_->getParamCount(), executor->getParamCount());
[7214]189
[7401]190        // if the reduced headers don't match -> return false
[7267]191        if (this->baseFunctor_->getHeaderIdentifier(minparams) != executor->getFunctor()->getHeaderIdentifier(minparams))
[7214]192            return false;
[7401]193        // if the reduced headers match and the new functor has less or equal parameters -> return true
[7267]194        else if (executor->getParamCount() <= this->baseFunctor_->getParamCount())
[7214]195            return true;
[7401]196        // the headers match but the new functor has more arguments, check if the new executor has enough default-values
[7214]197        else
[7179]198        {
[7267]199            for (unsigned int i = this->baseFunctor_->getParamCount(); i < executor->getParamCount(); ++i)
200            {
[7214]201                if (!executor->defaultValueSet(i))
[7267]202                {
[8858]203                    orxout(internal_warning, context::commands) << "Default value " << i << " is missing" << endl;
[7214]204                    return false;
[7267]205                }
206            }
[7214]207
208            return true;
209        }
210    }
211
[7401]212    /**
213        @brief Changes the executor.
214        @param executor The new executor
215        @param bForce If true, the executor is always assigned, even if the headers don't match
216        @return Returns true if the assignment was successful
217    */
[7236]218    bool ConsoleCommand::setFunction(const ExecutorPtr& executor, bool bForce)
[7214]219    {
[7401]220        // assign the executor if a) it's a null-pointer, b) its functor is a null-pointer, c) it's forced, d) the headers match
[7214]221        if (!executor || !executor->getFunctor() || bForce || this->headersMatch(executor))
222        {
[7401]223            // assign the executor and clear the object stack (because it's also a new function)
[7214]224            this->executor_ = executor;
[7272]225            this->objectStack_.clear();
[7214]226            return true;
227        }
228        else
229        {
[8858]230            orxout(internal_error, context::commands) << "Couldn't assign new executor to console command \"" << this->baseName_ << "\", headers don't match." << endl;
[7185]231            return false;
[7179]232        }
[7214]233    }
[7185]234
[7401]235    /**
236        @brief Changes the functor of the current executor.
237        @param functor The new functor
238        @param bForce If true, the functor is always assigned, even if the headers don't match
239        @return Returns true if the assignment was successful
240    */
[7236]241    bool ConsoleCommand::setFunction(const FunctorPtr& functor, bool bForce)
[7214]242    {
[7401]243        // assign the functor if a) it's a null-pointer, b) it's forced, c) the headers match
[7214]244        if (!functor || bForce || this->headersMatch(functor))
245        {
[7401]246            // assign the functor (create a new executor if necessary) and clear the object stack
[7214]247            if (this->executor_)
248                this->executor_->setFunctor(functor);
[7218]249            else if (functor)
[7214]250                this->executor_ = createExecutor(functor);
[7272]251            this->objectStack_.clear();
[7214]252
253            return true;
254        }
255        else
256        {
[8858]257            orxout(internal_error, context::commands) << "Couldn't assign new functor to console command \"" << this->baseName_ << "\", headers don't match." << endl;
[7214]258            return false;
259        }
[7179]260    }
261
[7401]262    /**
263        @brief Pushes a new executor to the command-stack.
264        @param executor The new executor
265        @param bForce If true, the executor is always assigned, even if the headers don't match
266    */
[7236]267    void ConsoleCommand::pushFunction(const ExecutorPtr& executor, bool bForce)
[7179]268    {
[7401]269        // prepare the old function to be put on the stack
[7214]270        Command command;
[7270]271        command.executor_ = this->executor_;
[7214]272        if (command.executor_)
[7270]273            command.functor_ = this->executor_->getFunctor();
[7272]274        command.objectStack_ = this->objectStack_;
[7185]275
[7401]276        // check if the new executor can be assigned and push the old function to the stack
[7214]277        if (this->setFunction(executor, bForce))
278            this->commandStack_.push(command);
[7179]279    }
280
[7401]281    /**
282        @brief Pushes a new functor to the command-stack.
283        @param functor The new functor
284        @param bForce If true, the functor is always assigned, even if the headers don't match
285    */
[7236]286    void ConsoleCommand::pushFunction(const FunctorPtr& functor, bool bForce)
[7179]287    {
[7401]288        // prepare the old function to be put on the stack
[7214]289        Command command;
[7270]290        command.executor_ = this->executor_;
[7214]291        if (command.executor_)
[7270]292            command.functor_ = this->executor_->getFunctor();
[7272]293        command.objectStack_ = this->objectStack_;
[7214]294
[7401]295        // check if the new functor can be assigned and push the old function to the stack
[7214]296        if (this->setFunction(functor, bForce))
297            this->commandStack_.push(command);
[7185]298    }
[7179]299
[7401]300    /**
301        @brief Pushes a copy of the current executor and functor on the stack.
302    */
[7236]303    void ConsoleCommand::pushFunction()
[7185]304    {
[7214]305        if (this->executor_)
306            this->pushFunction(new Executor(*this->executor_.get()));
307        else
[8858]308            orxout(internal_error, context::commands) << "Couldn't push copy of executor in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7179]309    }
310
[7401]311    /**
312        @brief Removes the current function from the stack and restores the old state.
313    */
[7236]314    void ConsoleCommand::popFunction()
[7179]315    {
[7214]316        Command command;
[7401]317
318        // check if there's a function on the stack
[7214]319        if (!this->commandStack_.empty())
[7179]320        {
[7401]321            // yes it is - assign it to command and remove it from the stack
[7214]322            command = this->commandStack_.top();
323            this->commandStack_.pop();
[7179]324        }
[7214]325
[7401]326        // restore the old executor (and also restore its functor in case this was changed in the meantime)
[7214]327        this->executor_ = command.executor_;
328        if (command.executor_)
329            this->executor_->setFunctor(command.functor_);
[7272]330        this->objectStack_ = command.objectStack_;
[7179]331    }
332
[7401]333    /**
334        @brief Sets the functor to NULL (which also deactivates the command).
335    */
[7236]336    void ConsoleCommand::resetFunction()
[7218]337    {
338        if (this->executor_)
339            this->executor_->setFunctor(0);
[7272]340        this->objectStack_.clear();
[7218]341    }
342
[7401]343    /**
344        @brief Returns the current executor which can be used to execute the command.
345    */
[7236]346    const ExecutorPtr& ConsoleCommand::getExecutor() const
[7179]347    {
[7214]348        return this->executor_;
[7179]349    }
350
[7401]351    /**
352        @brief Changes the current object that is used to execute member-functions.
353        @return Returns true if the object was successfully changed
354    */
[7236]355    bool ConsoleCommand::setObject(void* object)
[7214]356    {
[7401]357        // check if there's an executor
[7214]358        if (this->executor_)
[7185]359        {
[7401]360            // check if there's a functor
[7214]361            if (this->executor_->getFunctor())
362            {
[7401]363                // change the object
[7214]364                this->executor_->getFunctor()->setRawObjectPointer(object);
365                return true;
366            }
367            else if (object)
[8858]368                orxout(internal_error, context::commands) << "Can't assign object to console command \"" << this->baseName_ << "\", no functor set." << endl;
[7185]369        }
[7214]370        else if (object)
[8858]371            orxout(internal_error, context::commands) << "Can't assign object to console command \"" << this->baseName_ << "\", no executor set." << endl;
[7214]372
373        return false;
[7179]374    }
375
[7401]376    /**
377        @brief Push a new object to the object-stack.
378    */
[7236]379    void ConsoleCommand::pushObject(void* object)
[7214]380    {
381        void* oldobject = this->getObject();
382        if (this->setObject(object))
[7272]383            this->objectStack_.push_back(oldobject);
[7214]384    }
385
[7401]386    /**
387        @brief Removes the current object from the stack an restores the old object.
388    */
[7236]389    void ConsoleCommand::popObject()
[7185]390    {
391        void* newobject = 0;
392        if (!this->objectStack_.empty())
393        {
[7272]394            newobject = this->objectStack_.back();
395            this->objectStack_.pop_back();
[7185]396        }
397        this->setObject(newobject);
398    }
399
[7401]400    /**
401        @brief Returns the current object pointer that is used to execute member-functions.
402    */
[7236]403    void* ConsoleCommand::getObject() const
[7185]404    {
[7214]405        if (this->executor_ && this->executor_->getFunctor())
406            return this->executor_->getFunctor()->getRawObjectPointer();
[7185]407        else
408            return 0;
409    }
410
[7401]411    /**
412        @brief Changes the default values of the current executor.
413    */
414    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& arg1)
[7215]415    {
416        if (this->executor_)
[7401]417            this->executor_->setDefaultValues(arg1);
[7215]418        else
[8858]419            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]420
421        return *this;
422    }
423
[7401]424    /**
425        @brief Changes the default values of the current executor.
426    */
427    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& arg1, const MultiType& arg2)
[7215]428    {
429        if (this->executor_)
[7401]430            this->executor_->setDefaultValues(arg1, arg2);
[7215]431        else
[8858]432            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]433
434        return *this;
435    }
436
[7401]437    /**
438        @brief Changes the default values of the current executor.
439    */
440    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& arg1, const MultiType& arg2, const MultiType& arg3)
[7215]441    {
442        if (this->executor_)
[7401]443            this->executor_->setDefaultValues(arg1, arg2, arg3);
[7215]444        else
[8858]445            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]446
447        return *this;
448    }
449
[7401]450    /**
451        @brief Changes the default values of the current executor.
452    */
453    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& arg1, const MultiType& arg2, const MultiType& arg3, const MultiType& arg4)
[7215]454    {
455        if (this->executor_)
[7401]456            this->executor_->setDefaultValues(arg1, arg2, arg3, arg4);
[7215]457        else
[8858]458            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]459
460        return *this;
461    }
462
[7401]463    /**
464        @brief Changes the default values of the current executor.
465    */
466    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& arg1, const MultiType& arg2, const MultiType& arg3, const MultiType& arg4, const MultiType& arg5)
[7215]467    {
468        if (this->executor_)
[7401]469            this->executor_->setDefaultValues(arg1, arg2, arg3, arg4, arg5);
[7215]470        else
[8858]471            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]472
473        return *this;
474    }
475
[7401]476    /**
477        @brief Changes the default value of the argument with given index of the current executor.
478        @param index The index of the argument (the first argument has index 0)
479        @param arg The new default value
480    */
481    ConsoleCommand& ConsoleCommand::defaultValue(unsigned int index, const MultiType& arg)
[7215]482    {
483        if (this->executor_)
[7401]484            this->executor_->setDefaultValue(index, arg);
[7215]485        else
[8858]486            orxout(internal_error, context::commands) << "Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << endl;
[7215]487
488        return *this;
489    }
490
[7401]491    /**
492        @brief Changes the argument completer for the given argument.
493        @param index The index of the argument (the first argument has index 0)
494        @param completer The new argument completer
495    */
496    ConsoleCommand& ConsoleCommand::argumentCompleter(unsigned int index, ArgumentCompleter* completer)
[7215]497    {
[7401]498        if (index < 5)
499            this->argumentCompleter_[index] = completer;
[7215]500        else
[8858]501            orxout(internal_warning, context::commands) << "Couldn't add autocompletion-function for index " << index << " in console command \"" << this->baseName_ << "\": index out of bound." << endl;
[7215]502
503        return *this;
504    }
505
[7401]506    /**
507        @brief Returns the argument completer for the argument with given index.
508    */
509    ArgumentCompleter* ConsoleCommand::getArgumentCompleter(unsigned int index) const
[7215]510    {
[7401]511        if (index < 5)
512            return this->argumentCompleter_[index];
[7215]513        else
514            return 0;
515    }
516
[7401]517    /**
518        @brief Sets the description of this command.
519    */
[7236]520    ConsoleCommand& ConsoleCommand::description(const std::string& description)
[7215]521    {
522        this->description_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::function");
523        AddLanguageEntry(this->description_, description);
524        return *this;
525    }
526
[7401]527    /**
528        @brief Returns the description of this command.
529    */
[7236]530    const std::string& ConsoleCommand::getDescription() const
[7215]531    {
532        return GetLocalisation_noerror(this->description_);
533    }
534
[7401]535    /**
536        @brief Sets the description for an argument with given index.
537    */
538    ConsoleCommand& ConsoleCommand::descriptionParam(unsigned int index, const std::string& description)
[7215]539    {
[7401]540        if (index < MAX_FUNCTOR_ARGUMENTS)
[7215]541        {
[7401]542            this->descriptionParam_[index] = std::string("ConsoleCommandDescription::" + this->baseName_ + "::param" + multi_cast<std::string>(index));
543            AddLanguageEntry(this->descriptionParam_[index], description);
[7215]544        }
545        return *this;
546    }
547
[7401]548    /**
549        @brief Returns the description for the argument with given index.
550    */
551    const std::string& ConsoleCommand::getDescriptionParam(unsigned int index) const
[7215]552    {
[7401]553        if (index < MAX_FUNCTOR_ARGUMENTS)
554            return GetLocalisation_noerror(this->descriptionParam_[index]);
[7215]555
556        return this->descriptionParam_[0];
557    }
558
[7401]559    /**
560        @brief Sets the description for the return-value.
561    */
[7236]562    ConsoleCommand& ConsoleCommand::descriptionReturnvalue(const std::string& description)
[7215]563    {
564        this->descriptionReturnvalue_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::returnvalue");
565        AddLanguageEntry(this->descriptionReturnvalue_, description);
566        return *this;
567    }
568
[7401]569    /**
570        @brief Returns the description for the return-value.
571    */
572    const std::string& ConsoleCommand::getDescriptionReturnvalue(int index) const
[7215]573    {
574        return GetLocalisation_noerror(this->descriptionReturnvalue_);
575    }
576
[7401]577    /**
[7861]578        @brief Changes the keybind mode.
579    */
580    ConsoleCommand& ConsoleCommand::changeKeybindMode(KeybindMode::Value mode)
581    {
[8316]582        if( KeyBinderManager::exists() )
583            KeyBinderManager::getInstance().getCurrent()->changeMode(this, mode);
[7861]584
585        this->keybindMode(mode);
586        return *this;
587    }
[7179]588}
Note: See TracBrowser for help on using the repository browser.