Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands3/src/libraries/core/command/ConsoleCommand.cc @ 7230

Last change on this file since 7230 was 7228, checked in by landauf, 14 years ago

re-implemented CommandExecutor and CommandEvaluation. parameter evaluation is currently not implemented, will come soon.

  • Property svn:eol-style set to native
File size: 18.5 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#include "ConsoleCommand.h"
30
31#include "util/Convert.h"
32#include "util/StringUtils.h"
33#include "core/Language.h"
34#include "core/GameMode.h"
35
36namespace orxonox
37{
38    _ConsoleCommand::_ConsoleCommand(const std::string& group, const std::string& name, const ExecutorPtr& executor, bool bInitialized)
39    {
40        this->bActive_ = true;
41        this->bHidden_ = false;
42        this->accessLevel_ = AccessLevel::All;
43
44        this->baseName_ = name;
45        this->baseExecutor_ = executor;
46
47        this->argumentCompleter_[0] = 0;
48        this->argumentCompleter_[1] = 0;
49        this->argumentCompleter_[2] = 0;
50        this->argumentCompleter_[3] = 0;
51        this->argumentCompleter_[4] = 0;
52
53        this->keybindMode_ = KeybindMode::OnPress;
54        this->inputConfiguredParam_ = -1;
55
56        if (bInitialized)
57            this->executor_ = executor;
58
59        _ConsoleCommand::registerCommand(group, name, this);
60    }
61
62    _ConsoleCommand::~_ConsoleCommand()
63    {
64        _ConsoleCommand::unregisterCommand(this);
65    }
66
67    _ConsoleCommand& _ConsoleCommand::addShortcut()
68    {
69        _ConsoleCommand::registerCommand("", this->baseName_, this);
70        return *this;
71    }
72
73    _ConsoleCommand& _ConsoleCommand::addShortcut(const std::string&  name)
74    {
75        _ConsoleCommand::registerCommand("", name, this);
76        return *this;
77    }
78
79    _ConsoleCommand& _ConsoleCommand::addGroup(const std::string& group)
80    {
81        _ConsoleCommand::registerCommand(group, this->baseName_, this);
82        return *this;
83    }
84
85    _ConsoleCommand& _ConsoleCommand::addGroup(const std::string& group, const std::string&  name)
86    {
87        _ConsoleCommand::registerCommand(group, name, this);
88        return *this;
89    }
90
91    bool _ConsoleCommand::isActive() const
92    {
93        return (this->bActive_ && this->executor_ && this->executor_->getFunctor() && (this->executor_->getFunctor()->getType() == Functor::Type::Static || this->executor_->getFunctor()->getRawObjectPointer()));
94    }
95
96    bool _ConsoleCommand::hasAccess() const
97    {
98        switch (this->accessLevel_)
99        {
100            case AccessLevel::All:        return true;
101            case AccessLevel::Standalone: return GameMode::isStandalone();
102            case AccessLevel::Master:     return GameMode::isMaster();
103            case AccessLevel::Server:     return GameMode::hasServer();
104            case AccessLevel::Client:     return GameMode::isClient();
105            case AccessLevel::Online:     return (GameMode::hasServer() || GameMode::isClient());
106            case AccessLevel::Offline:    return GameMode::isStandalone();
107            case AccessLevel::None:       return false;
108            default:                      return false;
109        }
110    }
111
112    bool _ConsoleCommand::headersMatch(const FunctorPtr& functor)
113    {
114        unsigned int minparams = std::min(this->baseExecutor_->getParamCount(), functor->getParamCount());
115
116        if (this->baseExecutor_->getFunctor()->getHeaderIdentifier(minparams) != functor->getHeaderIdentifier(minparams))
117            return false;
118        else if (functor->getParamCount() <= this->baseExecutor_->getParamCount())
119            return true;
120        else if (!this->executor_)
121            return false;
122        else
123        {
124            for (unsigned int i = this->baseExecutor_->getParamCount(); i < functor->getParamCount(); ++i)
125                if (!this->executor_->defaultValueSet(i))
126                    return false;
127
128            return true;
129        }
130    }
131
132    bool _ConsoleCommand::headersMatch(const ExecutorPtr& executor)
133    {
134        unsigned int minparams = std::min(this->baseExecutor_->getParamCount(), executor->getParamCount());
135
136        if (this->baseExecutor_->getFunctor()->getHeaderIdentifier(minparams) != executor->getFunctor()->getHeaderIdentifier(minparams))
137            return false;
138        else if (executor->getParamCount() <= this->baseExecutor_->getParamCount())
139            return true;
140        else
141        {
142            for (unsigned int i = this->baseExecutor_->getParamCount(); i < executor->getParamCount(); ++i)
143                if (!executor->defaultValueSet(i))
144                    return false;
145
146            return true;
147        }
148    }
149
150    bool _ConsoleCommand::setFunction(const ExecutorPtr& executor, bool bForce)
151    {
152        if (!executor || !executor->getFunctor() || bForce || this->headersMatch(executor))
153        {
154            this->executor_ = executor;
155            return true;
156        }
157        else
158        {
159            COUT(1) << "Error: Couldn't assign new executor to console command \"" << this->baseName_ << "\", headers don't match." << std::endl;
160            return false;
161        }
162    }
163
164    bool _ConsoleCommand::setFunction(const FunctorPtr& functor, bool bForce)
165    {
166        if (!functor || bForce || this->headersMatch(functor))
167        {
168            if (this->executor_)
169                this->executor_->setFunctor(functor);
170            else if (functor)
171                this->executor_ = createExecutor(functor);
172
173            return true;
174        }
175        else
176        {
177            COUT(1) << "Error: Couldn't assign new functor to console command \"" << this->baseName_ << "\", headers don't match." << std::endl;
178            return false;
179        }
180    }
181
182    void _ConsoleCommand::pushFunction(const ExecutorPtr& executor, bool bForce)
183    {
184        Command command;
185        command.executor_ = this->getExecutor();
186        if (command.executor_)
187            command.functor_ = this->getExecutor()->getFunctor();
188
189        if (this->setFunction(executor, bForce))
190            this->commandStack_.push(command);
191    }
192
193    void _ConsoleCommand::pushFunction(const FunctorPtr& functor, bool bForce)
194    {
195        Command command;
196        command.executor_ = this->getExecutor();
197        if (command.executor_)
198            command.functor_ = this->getExecutor()->getFunctor();
199
200        if (this->setFunction(functor, bForce))
201            this->commandStack_.push(command);
202    }
203
204    void _ConsoleCommand::pushFunction()
205    {
206        if (this->executor_)
207            this->pushFunction(new Executor(*this->executor_.get()));
208        else
209            COUT(1) << "Error: Couldn't push copy of executor in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
210    }
211
212    void _ConsoleCommand::popFunction()
213    {
214        Command command;
215        if (!this->commandStack_.empty())
216        {
217            command = this->commandStack_.top();
218            this->commandStack_.pop();
219        }
220
221        this->executor_ = command.executor_;
222        if (command.executor_)
223            this->executor_->setFunctor(command.functor_);
224    }
225
226    void _ConsoleCommand::resetFunction()
227    {
228        if (this->executor_)
229            this->executor_->setFunctor(0);
230    }
231
232    const ExecutorPtr& _ConsoleCommand::getExecutor() const
233    {
234        return this->executor_;
235    }
236
237    bool _ConsoleCommand::setObject(void* object)
238    {
239        if (this->executor_)
240        {
241            if (this->executor_->getFunctor())
242            {
243                this->executor_->getFunctor()->setRawObjectPointer(object);
244                return true;
245            }
246            else if (object)
247                COUT(1) << "Error: Can't assign object to console command \"" << this->baseName_ << "\", no functor set." << std::endl;
248        }
249        else if (object)
250            COUT(1) << "Error: Can't assign object to console command \"" << this->baseName_ << "\", no executor set." << std::endl;
251
252        return false;
253    }
254
255    void _ConsoleCommand::pushObject(void* object)
256    {
257        void* oldobject = this->getObject();
258        if (this->setObject(object))
259            this->objectStack_.push(oldobject);
260    }
261
262    void _ConsoleCommand::popObject()
263    {
264        void* newobject = 0;
265        if (!this->objectStack_.empty())
266        {
267            newobject = this->objectStack_.top();
268            this->objectStack_.pop();
269        }
270        this->setObject(newobject);
271    }
272
273    void* _ConsoleCommand::getObject() const
274    {
275        if (this->executor_ && this->executor_->getFunctor())
276            return this->executor_->getFunctor()->getRawObjectPointer();
277        else
278            return 0;
279    }
280
281    _ConsoleCommand& _ConsoleCommand::defaultValues(const MultiType& param1)
282    {
283        if (this->executor_)
284            this->executor_->setDefaultValues(param1);
285        else
286            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
287
288        return *this;
289    }
290
291    _ConsoleCommand& _ConsoleCommand::defaultValues(const MultiType& param1, const MultiType& param2)
292    {
293        if (this->executor_)
294            this->executor_->setDefaultValues(param1, param2);
295        else
296            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
297
298        return *this;
299    }
300
301    _ConsoleCommand& _ConsoleCommand::defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3)
302    {
303        if (this->executor_)
304            this->executor_->setDefaultValues(param1, param2, param3);
305        else
306            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
307
308        return *this;
309    }
310
311    _ConsoleCommand& _ConsoleCommand::defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4)
312    {
313        if (this->executor_)
314            this->executor_->setDefaultValues(param1, param2, param3, param4);
315        else
316            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
317
318        return *this;
319    }
320
321    _ConsoleCommand& _ConsoleCommand::defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5)
322    {
323        if (this->executor_)
324            this->executor_->setDefaultValues(param1, param2, param3, param4, param5);
325        else
326            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
327
328        return *this;
329    }
330
331    _ConsoleCommand& _ConsoleCommand::defaultValue(unsigned int index, const MultiType& param)
332    {
333        if (this->executor_)
334            this->executor_->setDefaultValue(index, param);
335        else
336            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
337
338        return *this;
339    }
340
341    _ConsoleCommand& _ConsoleCommand::argumentCompleter(unsigned int param, ArgumentCompleter* completer)
342    {
343        if (param < 5)
344            this->argumentCompleter_[param] = completer;
345        else
346            COUT(2) << "Warning: Couldn't add autocompletion-function for param " << param << " in console command \"" << this->baseName_ << "\": index out of bound." << std::endl;
347
348        return *this;
349    }
350
351    ArgumentCompleter* _ConsoleCommand::getArgumentCompleter(unsigned int param) const
352    {
353        if (param < 5)
354            return this->argumentCompleter_[param];
355        else
356            return 0;
357    }
358
359    _ConsoleCommand& _ConsoleCommand::description(const std::string& description)
360    {
361        this->description_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::function");
362        AddLanguageEntry(this->description_, description);
363        return *this;
364    }
365
366    const std::string& _ConsoleCommand::getDescription() const
367    {
368        return GetLocalisation_noerror(this->description_);
369    }
370
371    _ConsoleCommand& _ConsoleCommand::descriptionParam(unsigned int param, const std::string& description)
372    {
373        if (param < MAX_FUNCTOR_ARGUMENTS)
374        {
375            this->descriptionParam_[param] = std::string("ConsoleCommandDescription::" + this->baseName_ + "::param" + multi_cast<std::string>(param));
376            AddLanguageEntry(this->descriptionParam_[param], description);
377        }
378        return *this;
379    }
380
381    const std::string& _ConsoleCommand::getDescriptionParam(unsigned int param) const
382    {
383        if (param < MAX_FUNCTOR_ARGUMENTS)
384            return GetLocalisation_noerror(this->descriptionParam_[param]);
385
386        return this->descriptionParam_[0];
387    }
388
389    _ConsoleCommand& _ConsoleCommand::descriptionReturnvalue(const std::string& description)
390    {
391        this->descriptionReturnvalue_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::returnvalue");
392        AddLanguageEntry(this->descriptionReturnvalue_, description);
393        return *this;
394    }
395
396    const std::string& _ConsoleCommand::getDescriptionReturnvalue(int param) const
397    {
398        return GetLocalisation_noerror(this->descriptionReturnvalue_);
399    }
400
401    /* static */ _ConsoleCommand* _ConsoleCommand::getCommand(const std::string& group, const std::string& name, bool bPrintError)
402    {
403        std::map<std::string, std::map<std::string, _ConsoleCommand*> >::const_iterator it_group = _ConsoleCommand::getCommandMap().find(group);
404        if (it_group != _ConsoleCommand::getCommandMap().end())
405        {
406            std::map<std::string, _ConsoleCommand*>::const_iterator it_name = it_group->second.find(name);
407            if (it_name != it_group->second.end())
408            {
409                return it_name->second;
410            }
411        }
412        if (bPrintError)
413        {
414            if (group == "")
415                COUT(1) << "Error: Couldn't find console command with shortcut \"" << name << "\"" << std::endl;
416            else
417                COUT(1) << "Error: Couldn't find console command with group \"" << group << "\" and name \"" << name << "\"" << std::endl;
418        }
419        return 0;
420    }
421
422    /* static */ _ConsoleCommand* _ConsoleCommand::getCommandLC(const std::string& group, const std::string& name, bool bPrintError)
423    {
424        std::string groupLC = getLowercase(group);
425        std::string nameLC = getLowercase(name);
426
427        std::map<std::string, std::map<std::string, _ConsoleCommand*> >::const_iterator it_group = _ConsoleCommand::getCommandMapLC().find(groupLC);
428        if (it_group != _ConsoleCommand::getCommandMapLC().end())
429        {
430            std::map<std::string, _ConsoleCommand*>::const_iterator it_name = it_group->second.find(nameLC);
431            if (it_name != it_group->second.end())
432            {
433                return it_name->second;
434            }
435        }
436        if (bPrintError)
437        {
438            if (group == "")
439                COUT(1) << "Error: Couldn't find console command with shortcut \"" << name << "\"" << std::endl;
440            else
441                COUT(1) << "Error: Couldn't find console command with group \"" << group << "\" and name \"" << name << "\"" << std::endl;
442        }
443        return 0;
444    }
445
446    /* static */ std::map<std::string, std::map<std::string, _ConsoleCommand*> >& _ConsoleCommand::getCommandMap()
447    {
448        static std::map<std::string, std::map<std::string, _ConsoleCommand*> > commandMap;
449        return commandMap;
450    }
451
452    /* static */ std::map<std::string, std::map<std::string, _ConsoleCommand*> >& _ConsoleCommand::getCommandMapLC()
453    {
454        static std::map<std::string, std::map<std::string, _ConsoleCommand*> > commandMapLC;
455        return commandMapLC;
456    }
457
458    /* static */ void _ConsoleCommand::registerCommand(const std::string& group, const std::string& name, _ConsoleCommand* command)
459    {
460        if (name == "")
461            return;
462
463        if (_ConsoleCommand::getCommand(group, name) != 0)
464        {
465            if (group == "")
466                COUT(2) << "Warning: A console command with shortcut \"" << name << "\" already exists." << std::endl;
467            else
468                COUT(2) << "Warning: A console command with name \"" << name << "\" already exists in group \"" << group << "\"." << std::endl;
469        }
470        else
471        {
472            _ConsoleCommand::getCommandMap()[group][name] = command;
473            _ConsoleCommand::getCommandMapLC()[getLowercase(group)][getLowercase(name)] = command;
474        }
475    }
476
477    /* static */ void _ConsoleCommand::unregisterCommand(_ConsoleCommand* command)
478    {
479        for (std::map<std::string, std::map<std::string, _ConsoleCommand*> >::iterator it_group = _ConsoleCommand::getCommandMap().begin(); it_group != _ConsoleCommand::getCommandMap().end(); )
480        {
481            for (std::map<std::string, _ConsoleCommand*>::iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); )
482            {
483                if (it_name->second == command)
484                    it_group->second.erase(it_name++);
485                else
486                    ++it_name;
487            }
488
489            if (it_group->second.empty())
490                _ConsoleCommand::getCommandMap().erase(it_group++);
491            else
492                ++it_group;
493        }
494
495        for (std::map<std::string, std::map<std::string, _ConsoleCommand*> >::iterator it_group = _ConsoleCommand::getCommandMapLC().begin(); it_group != _ConsoleCommand::getCommandMapLC().end(); )
496        {
497            for (std::map<std::string, _ConsoleCommand*>::iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); )
498            {
499                if (it_name->second == command)
500                    it_group->second.erase(it_name++);
501                else
502                    ++it_name;
503            }
504
505            if (it_group->second.empty())
506                _ConsoleCommand::getCommandMapLC().erase(it_group++);
507            else
508                ++it_group;
509        }
510    }
511
512    /* static */ void _ConsoleCommand::destroyAll()
513    {
514        while (!_ConsoleCommand::getCommandMap().empty() && !_ConsoleCommand::getCommandMap().begin()->second.empty())
515            delete _ConsoleCommand::getCommandMap().begin()->second.begin()->second;
516    }
517}
Note: See TracBrowser for help on using the repository browser.