Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

made ConsoleCommandManager a singleton.

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