Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/core/command/ConsoleCommand.cc @ 10916

Last change on this file since 10916 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

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