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