Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

use a base-functor instead of a base-executor in ConsoleCommand because the functor of a static executor changes if new functions are assigned to the command.

  • Property svn:eol-style set to native
File size: 18.6 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->baseFunctor_ = executor->getFunctor();
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->baseFunctor_->getParamCount(), functor->getParamCount());
115
116        if (this->baseFunctor_->getHeaderIdentifier(minparams) != functor->getHeaderIdentifier(minparams))
117            return false;
118        else if (functor->getParamCount() <= this->baseFunctor_->getParamCount())
119            return true;
120        else if (!this->executor_)
121            return false;
122        else
123        {
124            for (unsigned int i = this->baseFunctor_->getParamCount(); i < functor->getParamCount(); ++i)
125            {
126                if (!this->executor_->defaultValueSet(i))
127                {
128                    COUT(2) << "Default value " << i << " is missing" << std::endl;
129                    return false;
130                }
131            }
132
133            return true;
134        }
135    }
136
137    bool ConsoleCommand::headersMatch(const ExecutorPtr& executor)
138    {
139        unsigned int minparams = std::min(this->baseFunctor_->getParamCount(), executor->getParamCount());
140
141        if (this->baseFunctor_->getHeaderIdentifier(minparams) != executor->getFunctor()->getHeaderIdentifier(minparams))
142            return false;
143        else if (executor->getParamCount() <= this->baseFunctor_->getParamCount())
144            return true;
145        else
146        {
147            for (unsigned int i = this->baseFunctor_->getParamCount(); i < executor->getParamCount(); ++i)
148            {
149                if (!executor->defaultValueSet(i))
150                {
151                    COUT(2) << "Default value " << i << " is missing" << std::endl;
152                    return false;
153                }
154            }
155
156            return true;
157        }
158    }
159
160    bool ConsoleCommand::setFunction(const ExecutorPtr& executor, bool bForce)
161    {
162        if (!executor || !executor->getFunctor() || bForce || this->headersMatch(executor))
163        {
164            this->executor_ = executor;
165            return true;
166        }
167        else
168        {
169            COUT(1) << "Error: Couldn't assign new executor to console command \"" << this->baseName_ << "\", headers don't match." << std::endl;
170            return false;
171        }
172    }
173
174    bool ConsoleCommand::setFunction(const FunctorPtr& functor, bool bForce)
175    {
176        if (!functor || bForce || this->headersMatch(functor))
177        {
178            if (this->executor_)
179                this->executor_->setFunctor(functor);
180            else if (functor)
181                this->executor_ = createExecutor(functor);
182
183            return true;
184        }
185        else
186        {
187            COUT(1) << "Error: Couldn't assign new functor to console command \"" << this->baseName_ << "\", headers don't match." << std::endl;
188            return false;
189        }
190    }
191
192    void ConsoleCommand::pushFunction(const ExecutorPtr& executor, bool bForce)
193    {
194        Command command;
195        command.executor_ = this->getExecutor();
196        if (command.executor_)
197            command.functor_ = this->getExecutor()->getFunctor();
198
199        if (this->setFunction(executor, bForce))
200            this->commandStack_.push(command);
201    }
202
203    void ConsoleCommand::pushFunction(const FunctorPtr& functor, bool bForce)
204    {
205        Command command;
206        command.executor_ = this->getExecutor();
207        if (command.executor_)
208            command.functor_ = this->getExecutor()->getFunctor();
209
210        if (this->setFunction(functor, bForce))
211            this->commandStack_.push(command);
212    }
213
214    void ConsoleCommand::pushFunction()
215    {
216        if (this->executor_)
217            this->pushFunction(new Executor(*this->executor_.get()));
218        else
219            COUT(1) << "Error: Couldn't push copy of executor in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
220    }
221
222    void ConsoleCommand::popFunction()
223    {
224        Command command;
225        if (!this->commandStack_.empty())
226        {
227            command = this->commandStack_.top();
228            this->commandStack_.pop();
229        }
230
231        this->executor_ = command.executor_;
232        if (command.executor_)
233            this->executor_->setFunctor(command.functor_);
234    }
235
236    void ConsoleCommand::resetFunction()
237    {
238        if (this->executor_)
239            this->executor_->setFunctor(0);
240    }
241
242    const ExecutorPtr& ConsoleCommand::getExecutor() const
243    {
244        return this->executor_;
245    }
246
247    bool ConsoleCommand::setObject(void* object)
248    {
249        if (this->executor_)
250        {
251            if (this->executor_->getFunctor())
252            {
253                this->executor_->getFunctor()->setRawObjectPointer(object);
254                return true;
255            }
256            else if (object)
257                COUT(1) << "Error: Can't assign object to console command \"" << this->baseName_ << "\", no functor set." << std::endl;
258        }
259        else if (object)
260            COUT(1) << "Error: Can't assign object to console command \"" << this->baseName_ << "\", no executor set." << std::endl;
261
262        return false;
263    }
264
265    void ConsoleCommand::pushObject(void* object)
266    {
267        void* oldobject = this->getObject();
268        if (this->setObject(object))
269            this->objectStack_.push(oldobject);
270    }
271
272    void ConsoleCommand::popObject()
273    {
274        void* newobject = 0;
275        if (!this->objectStack_.empty())
276        {
277            newobject = this->objectStack_.top();
278            this->objectStack_.pop();
279        }
280        this->setObject(newobject);
281    }
282
283    void* ConsoleCommand::getObject() const
284    {
285        if (this->executor_ && this->executor_->getFunctor())
286            return this->executor_->getFunctor()->getRawObjectPointer();
287        else
288            return 0;
289    }
290
291    ConsoleCommand& ConsoleCommand::defaultValues(const MultiType& param1)
292    {
293        if (this->executor_)
294            this->executor_->setDefaultValues(param1);
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)
302    {
303        if (this->executor_)
304            this->executor_->setDefaultValues(param1, param2);
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)
312    {
313        if (this->executor_)
314            this->executor_->setDefaultValues(param1, param2, param3);
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)
322    {
323        if (this->executor_)
324            this->executor_->setDefaultValues(param1, param2, param3, param4);
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::defaultValues(const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5)
332    {
333        if (this->executor_)
334            this->executor_->setDefaultValues(param1, param2, param3, param4, param5);
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::defaultValue(unsigned int index, const MultiType& param)
342    {
343        if (this->executor_)
344            this->executor_->setDefaultValue(index, param);
345        else
346            COUT(1) << "Error: Can't set default values in console command \"" << this->baseName_ << "\", no executor set." << std::endl;
347
348        return *this;
349    }
350
351    ConsoleCommand& ConsoleCommand::argumentCompleter(unsigned int param, ArgumentCompleter* completer)
352    {
353        if (param < 5)
354            this->argumentCompleter_[param] = completer;
355        else
356            COUT(2) << "Warning: Couldn't add autocompletion-function for param " << param << " in console command \"" << this->baseName_ << "\": index out of bound." << std::endl;
357
358        return *this;
359    }
360
361    ArgumentCompleter* ConsoleCommand::getArgumentCompleter(unsigned int param) const
362    {
363        if (param < 5)
364            return this->argumentCompleter_[param];
365        else
366            return 0;
367    }
368
369    ConsoleCommand& ConsoleCommand::description(const std::string& description)
370    {
371        this->description_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::function");
372        AddLanguageEntry(this->description_, description);
373        return *this;
374    }
375
376    const std::string& ConsoleCommand::getDescription() const
377    {
378        return GetLocalisation_noerror(this->description_);
379    }
380
381    ConsoleCommand& ConsoleCommand::descriptionParam(unsigned int param, const std::string& description)
382    {
383        if (param < MAX_FUNCTOR_ARGUMENTS)
384        {
385            this->descriptionParam_[param] = std::string("ConsoleCommandDescription::" + this->baseName_ + "::param" + multi_cast<std::string>(param));
386            AddLanguageEntry(this->descriptionParam_[param], description);
387        }
388        return *this;
389    }
390
391    const std::string& ConsoleCommand::getDescriptionParam(unsigned int param) const
392    {
393        if (param < MAX_FUNCTOR_ARGUMENTS)
394            return GetLocalisation_noerror(this->descriptionParam_[param]);
395
396        return this->descriptionParam_[0];
397    }
398
399    ConsoleCommand& ConsoleCommand::descriptionReturnvalue(const std::string& description)
400    {
401        this->descriptionReturnvalue_ = std::string("ConsoleCommandDescription::" + this->baseName_ + "::returnvalue");
402        AddLanguageEntry(this->descriptionReturnvalue_, description);
403        return *this;
404    }
405
406    const std::string& ConsoleCommand::getDescriptionReturnvalue(int param) const
407    {
408        return GetLocalisation_noerror(this->descriptionReturnvalue_);
409    }
410
411    /* static */ ConsoleCommand* ConsoleCommand::getCommand(const std::string& group, const std::string& name, bool bPrintError)
412    {
413        std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandMap().find(group);
414        if (it_group != ConsoleCommand::getCommandMap().end())
415        {
416            std::map<std::string, ConsoleCommand*>::const_iterator it_name = it_group->second.find(name);
417            if (it_name != it_group->second.end())
418            {
419                return it_name->second;
420            }
421        }
422        if (bPrintError)
423        {
424            if (group == "")
425                COUT(1) << "Error: Couldn't find console command with shortcut \"" << name << "\"" << std::endl;
426            else
427                COUT(1) << "Error: Couldn't find console command with group \"" << group << "\" and name \"" << name << "\"" << std::endl;
428        }
429        return 0;
430    }
431
432    /* static */ ConsoleCommand* ConsoleCommand::getCommandLC(const std::string& group, const std::string& name, bool bPrintError)
433    {
434        std::string groupLC = getLowercase(group);
435        std::string nameLC = getLowercase(name);
436
437        std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommandMapLC().find(groupLC);
438        if (it_group != ConsoleCommand::getCommandMapLC().end())
439        {
440            std::map<std::string, ConsoleCommand*>::const_iterator it_name = it_group->second.find(nameLC);
441            if (it_name != it_group->second.end())
442            {
443                return it_name->second;
444            }
445        }
446        if (bPrintError)
447        {
448            if (group == "")
449                COUT(1) << "Error: Couldn't find console command with shortcut \"" << name << "\"" << std::endl;
450            else
451                COUT(1) << "Error: Couldn't find console command with group \"" << group << "\" and name \"" << name << "\"" << std::endl;
452        }
453        return 0;
454    }
455
456    /* static */ std::map<std::string, std::map<std::string, ConsoleCommand*> >& ConsoleCommand::getCommandMap()
457    {
458        static std::map<std::string, std::map<std::string, ConsoleCommand*> > commandMap;
459        return commandMap;
460    }
461
462    /* static */ std::map<std::string, std::map<std::string, ConsoleCommand*> >& ConsoleCommand::getCommandMapLC()
463    {
464        static std::map<std::string, std::map<std::string, ConsoleCommand*> > commandMapLC;
465        return commandMapLC;
466    }
467
468    /* static */ void ConsoleCommand::registerCommand(const std::string& group, const std::string& name, ConsoleCommand* command)
469    {
470        if (name == "")
471            return;
472
473        if (ConsoleCommand::getCommand(group, name) != 0)
474        {
475            if (group == "")
476                COUT(2) << "Warning: A console command with shortcut \"" << name << "\" already exists." << std::endl;
477            else
478                COUT(2) << "Warning: A console command with name \"" << name << "\" already exists in group \"" << group << "\"." << std::endl;
479        }
480        else
481        {
482            ConsoleCommand::getCommandMap()[group][name] = command;
483            ConsoleCommand::getCommandMapLC()[getLowercase(group)][getLowercase(name)] = command;
484        }
485    }
486
487    /* static */ void ConsoleCommand::unregisterCommand(ConsoleCommand* command)
488    {
489        for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::iterator it_group = ConsoleCommand::getCommandMap().begin(); it_group != ConsoleCommand::getCommandMap().end(); )
490        {
491            for (std::map<std::string, ConsoleCommand*>::iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); )
492            {
493                if (it_name->second == command)
494                    it_group->second.erase(it_name++);
495                else
496                    ++it_name;
497            }
498
499            if (it_group->second.empty())
500                ConsoleCommand::getCommandMap().erase(it_group++);
501            else
502                ++it_group;
503        }
504
505        for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::iterator it_group = ConsoleCommand::getCommandMapLC().begin(); it_group != ConsoleCommand::getCommandMapLC().end(); )
506        {
507            for (std::map<std::string, ConsoleCommand*>::iterator it_name = it_group->second.begin(); it_name != it_group->second.end(); )
508            {
509                if (it_name->second == command)
510                    it_group->second.erase(it_name++);
511                else
512                    ++it_name;
513            }
514
515            if (it_group->second.empty())
516                ConsoleCommand::getCommandMapLC().erase(it_group++);
517            else
518                ++it_group;
519        }
520    }
521
522    /* static */ void ConsoleCommand::destroyAll()
523    {
524        while (!ConsoleCommand::getCommandMap().empty() && !ConsoleCommand::getCommandMap().begin()->second.empty())
525            delete ConsoleCommand::getCommandMap().begin()->second.begin()->second;
526    }
527}
Note: See TracBrowser for help on using the repository browser.