Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
114 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Creating a Scalable Console System with STL – Part 1


Planning the Console

Designing the class

When we write the base console class we are looking forward for it to be extensible because it isn't planned to be used alone but to be used as a base class to a more complex console class. I will explain this later when we get to the usage section (virtual functions info here).

class console
{
public:
  console();
virtual ~console();

public:
void addItem(const std::string & strName,
    void *pointer, console_item_type_t type);

  void removeItem(const std::string & strName);

  void setDefaultCommand(console_function func);

  ...

  void print(const std::string & strText);

  ...

  void passKey(char key);

void passBackspace();

void passIntro();

...

public:
  virtual void render() = 0;

private:
  bool parseCommandLine();

private:
  std::vector<std::string> m_commandBuffer;

  std::list<console_item_t> m_itemList;

  console_function defaultCommand;

  ...

protected:
  std::list<std::string> m_textBuffer;

std::string  m_commandLine;

...
};

This sample class contains the most important parts of the console class, always check the attached source code to see the complete and working code. I will now start to explain the different parts of the class:

console();
virtual ~console();

These two functions are the constructor and destructor of the class. In the constructor we initialize all the variables and the destructor is used to free all the lists and items. The destructor *HAS TO BE* virtual because we are going to use this as a base class and in order to properly call the derived class' destructor we make the base class' destructor virtual.

void addItem(const std::string & strName,
             void *pointer, console_item_type_t type);

This function is used to add an item to the console, an item can either be a command or a variable. For example if you write "/quit" and hit enter the console may quit but if you write "color red" then the console will assign "red" to the string variable "color". You may also want the console to report the content of "color" if you write the name of the variable and hit enter. To be able to do this we have to create a "console_item_t" struct, and a "console_item_type_t" enumeration, one will store the item and the other will identify the item type:

enum console_item_type_t
{
  CTYPE_UCHAR,      // variable: unsigned char
  CTYPE_CHAR,       // variable: char
  CTYPE_UINT,       // variable: unsigned int
  CTYPE_INT,        // variable: int
  CTYPE_FLOAT,      // variable: float
  CTYPE_STRING,     // variable: std::string
  CTYPE_FUNCTION    // function
};

The "console_item_type_t" enumeration will identify the item, as you can see the item can be of different variable types or it can be a function. You can easily add more variable types by adding some names to the enumeration and just a few lines of code in other function, you'll see.

typedef struct
{
  std::string name;

  console_item_type_t type;

  union
  {
    void *variable_pointer;
    console_function function;
  };
} console_item_t;

The first two variables are straightforward, but I should do some explaining about the union. A union is used when you want more than one variable to share the same space of memory. The first item inside the union is a pointer, THE pointer to the variable when the item type is some variable type. The second variable is a function pointer, I will now explain it.

typedef void (*console_function)(const std::vector<std::string> &);

Here we define the "console_function" type, this line of code means: "All the function command handles should be of type void and have a parameter where it will be passed the list of arguments for that command".

Inside the union both the function pointer and the variable pointer are of type "void *" and only one will be used at the same time, that's why we can use a union to save some space in memory (we save one void pointer for each item in the list).

We will now go back to the main console class, I hope I haven't lost you.

void setDefaultCommand(console_function func);

When the console system can't find a suitable command that matches the user's commandline it executes the default command. This function MUST BE called before running the system. If you don't want or need a special default function you can make one that prints out an error message:

void default(const std::vector<std::string> & args)
{
  console->print(args[0]);
  console->print(" is not a recognized command.\n");
}

void initialize()
{
...
console->setDefaultCommand(default);
...
}

That example function would print "<command name> is not a recognized command.".

void print(const std::string & strText);

The "print" function just adds text to the output history buffer.

void removeItem(const std::string & strName);

This function is used to remove an item from the list by providing its name, pretty straightforward.

void passKey(char key);

void passBackSpace();

void passIntro();

These three functions are used to control keyboard input: The first one is used to send the characters to the console ,i.e. passkey(‘c'); would write a "c" in the console. The second function is used to delete the last character from the console (when backspace is pressed). And the last one is used to execute the command line.

virtual void render() = 0;

This is our virtual rendering interface, it will be used in the derived class to present the content of the console to the screen. By making it pure virtual we ensure that this class is not instantiable so it can not be used alone.

void parseCommandLine();

The parseCommandLine function will be explained later, it has a whole section for its own.

private:

std::list<std::string> m_commandBuffer; std::list<console_item_t> m_itemList;

These two lists are the responsible for holding the command line buffer, that is composed of several strings the item list that has already been discussed before. I made these variables private because the derived class will have no need to access them directly.

std::list<std::string> m_textBuffer;

Here we have another list with the history of all the console output, when initializing the console we choose how many lines to store. If the buffer passed the maximum number of lines then the oldest line is erased and the new one is added. Exactly the same happens with the command line buffer.



Console Core


Contents
  Introduction
  Planning the Console
  Console Core
  Usage & Conclusion

  Source code
  Printable version
  Discuss this article