Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

wrap ConsoleCommands in StaticallyInitializedInstances

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