• Advertisement
  • entries
    707
  • comments
    1173
  • views
    434383

Debug Console Version 1.0

Sign in to follow this  

75 views

Ok, I'm done with it. First off I'm going to do some talking about it so that the people who try it don't have problems (hopefully.)


Overview


Ok, first off there are two reasons why I'm releasing the source to this: because I've been asked how I do my console in the past and that way those that are using other operating systems or APIs can still use it (although you'll have to convert some of the code.)

Next I need to warn you that some people dislike my naming convention for the fact that I don't have a problem typing out a variable name like DebugConsoleReturnVariable several times in a row. Another note on naming convention is that I do my best to name variables so that you can understand what the variable is for.

And finally, some people might have a problem with me having most (if not all) of the variables in public access. Yes, this can be a major problem if someone goes off and tries to assign values to the data, change the data's type, or convert the data without checking the data's type. So, just don't do that. I designed this library for ME to use, so if somebody takes it and misuses it then that's their problem; I'm not going to take out one of my favorite features because someone might misuse it.


Basic Examples


Ok, now for a couple basic examples. I'll cover variables, functions, and then registered variables handling. Before going through these I should note some of the restrictions.

  • Console.Print() is already registered in the system, but you can override it with your own. (Just supply a new variable or function with the name Console.Print.)

  • argb() and rgb() are also already registered in the system. Overriding is done the same way.

  • true and false are considered boolean, but will be automatically converted to int or string (not float though.)

  • + or - will tell the parser that the rest of the argument is a number (but it will be converted to any data type, even string.)

  • 0-9 will also tell the parser that the rest of the argument is a number (but it will be converted to any data type, even string.)

  • 0x denotes hexadecimal values. Hexadecimal values can only be assigned to integers or strings.

  • Unless quotes are used, spaces are skipped. So, while you could do Console.Print(Debug Consoles Rock!!!) it'd come out as DebugConsolesRock!!!!

  • The semicolon at the end of statements is optional.

  • Commas and parentheses are not optional.

  • You cannot register methods. I have a way to do it that works, but it's way too much of a hack and I don't want to deal with it. Trust me, neither would you.

  • The bottom of the console is not determined by the supplied rectangle, it is determined by DebugConsole::LinesViewable. This however needs to be changed, as having a bunch of blank lines and then the user input line looks kind of odd. Maybe I'll switch it around.

  • 'true' and 'false' cannot be registered over (I check for them in Register().)

  • 'Console.FontColor', 'argb()', 'rgb()', 'Console.Print()' are the only pre-registered variables at the moment. I'm thinking of adding some math functions, but I'm not sure.

  • Variables names can be anything except for 'true', 'false' or anything starting with a number or a -/+ and a number. Although, the latter can be registered, you wouldn't be able to use it since the parsing code would see it as a number.
  • Variable names are case-sensitive.

  • I supplied a C++ function that converts DCT_ types to std::string values.

  • Most types will convert automatically to other types. Int will convert to any (except a function), float will convert to int or string, and bool will convert to int or string. I'm having a little bit of trouble with from-string conversion, but I'll have them fixed soon.


That's all I can think of at the moment.

Note that these aren't working examples as I'm not going to clutter things up with Direct3D and system loop stuff.

Variables

#include "DebugConsole.h"

dft::DebugConsole Console;
int ScreenWidth = 640, ScreenHeight = 480;
RECT ConsoleRect = {5, 5, ScreenWidth - 5, ScreenHeight - 5;

int Integer = 0;
float Float = 0.0f;
bool Boolean = false;
std::string String = "";

int main()
{
Console.LinesViewable = 20;
Console.FontColor = 0xffff0000;
Console.Register("Health", &Integer); // Register the variable Integer to the name "Health".
Console.Register("Money", &Float); // Register the variable Float to the name "Money".
Console.Register("IsDead", &Boolean); // Register the variable Boolean to the name "IsDead".
Console.Register("String", &String); // Register the variable String to the name "String".
}

void Frame()
{
Console.Render(0, 0, ID3DXFontPtr, ConsoleRect); // Checks to see if it is open by itself, so you just tell it to render.)
}





Now all of those global variables can be accessed through the console via "Health", "Money", "IsDead", and "String". You can pass them to functions, assign other variables to them, assign values to them, or assign function-return values to them (A note on assignment support: Integer and float variable types support all assignments (=, +=, -=, *=, and /=), booleans support only assignment, and strings support assigment and add-assign combo (+=).) Some examples are:

Health = 100;
Money = 10.00;
IsDead = true;
String = "Donny is dead = ";
String += IsDead;
Console.FontColor = 0xff004488;
Console.Print(String);

The last line will print "Donny is dead = true".

Functions

#include "DebugConsole.h"

dft::DebugConsole Console;
int ScreenWidth = 640, ScreenHeight = 480;
RECT ConsoleRect = {5, 5, ScreenWidth - 5, ScreenHeight - 5;

int Results = 0;

// you might want to typedef the DebugConsole classes
// for example: typedef dft::DebugConsoleReturnVariable DCReturnVar;
// and maybe the Arguments variable below to: typedef const std::vector& ArgumentsList; or something (maybe not include the const and & since that shouldn't be hidden.)
dft::DebugConsoleReturnVariable Add(dft::DebugConsole* Console, const std::vector& Arguments)
{
if(Arguments.size() < 1)
return DebugConsoleReturnVariable(0, "No values supplied to Add().");

int Results = 0;
for(int ArgumentIndex = 0; ArgumentIndex < Arguments.size(); ++ArgumentIndex)
Results += atoi(Arguments[ArgumentIndex].c_str());
return Results;
}

dft::DebugConsoleReturnVariable Average(dft::DebugConsole* Console, const std::vector& Arguments)
{
if(Arguments.size() < 1)
return DebugConsoleReturnVariable(0, "No values supplied to Average().");

int Results = 0;
for(int ArgumentIndex = 0; ArgumentIndex < Arguments.size(); ++ArgumentIndex)
Results += atoi(Arguments[ArgumentIndex].c_str());
return Results / Arguments.size();
}

int main()
{
Console.LinesViewable = 20;
Console.FontColor = 0xffff0000;
Console.Register("Math.Add", Add);
Console.Register("Math.Average", Average);
Console.Register("Results", &Results);
}

void Frame()
{
Console.Render(0, 0, ID3DXFontPtr, ConsoleRect); // Checks to see if it is open by itself, so you just tell it to render.)
}






Now, you could add or average any number of integers. Some examples:

Results = Add(10, 21, 16, 1, 19, 32);
Print(Results);
Results = Average(10, 21, 16, 1, 19, 32);
Print(Results);


Quote:
Results:
99
16


Registered variable handling
Ok, there is pretty much only one way to correctly handle registered variables inside a registered function and that is via a type-switch check. Here's an example:

dft::DebugConsoleReturnVariable Function(dft::DebugConsole* Console, const std::vector& Arguments)
{
DebugConsoleVariable* Variable = Console->GetVariable("VariableName"); // RegisteredVariable is of type DebugConsoleVariable.
void* VariableData = Variable->Variable;
switch(Variable->Type)
{
case DCT_NULL:
break;

case DCT_INT:
{
(*(int*)(VariableData) = atoi(Value.c_str());
break;
}

case DCT_FLOAT:
{
(*(float*)(VariableData) = (float)atof(Value.c_str());
break;
}

case DCT_BOOL:
{
if(Value == "false")
(*(bool*)(VariableData) = false;
else if(Value == "true")
(*(bool*)(VariableData) = true;
break;
}

case DCT_FUNCTION:
{
std::vector Arguments;
// add arguments here
return (*VariableData)(Console, Arguments);
}
}
return 0;
}






Obviously if you're looking for just one specific type you could check for just that. For example you could do:

if(Variable->Type == DCT_INT)
{
// do integer stuff here
}
else
return DebugConsoleReturnVariable(0, "Was expecting an integer, but a %s was supplied.", DebugConsoleTypeToString(Variable->Type).c_str());




Here's the link: DebugConsole.zip. I'd appreciate it if some of you DirectX users could download it and try it out (even if you don't plan to use it.) I need to know that it works for people other than me. Also, if any of you OpenGL users find it useful and make an OpenGL version of the render function, could you send me a copy so that I could upload it? (I'll add you to the readme.txt when I get around to adding that.) Thanks!

Sorry if this is incomplete, but I'm way tired and need to go to bed now.


Update


Added some new features:
Debug-specific variable registration. If you tell the Register() function that the variable is "Debug only" (via a new bool variable I added0 it'll wrap the register in #ifndef _DEBUG/#endif.

Added 2 new functions: Console.ListCommands() and Console.ListVariables(). I was going to add a full-on help system, but that would require me adding a help string to the variable class and then people would have to fill it in, so I opted out of that.

I also added a couple features to the todo list:
Variable allocation and memory management. This will allow people to do something like:
Color = argb(0, 64, 128);

Now 'Color' would be accessible anywhere in the game (until the player exits.) this however is the very last thing I'll implement since I really don't see any use for it (so it might actually be removed. We'll see.)

The other thing I added to the list is macro support. An example would be:

Console.DefineMacro("KillerCombo", "CastSpell(^FireBall^);", "CastSpell(^Ice Storm^);", "CastSpell(^Chain Lightning^);");
Macro.KillerCombo




The first line would define Macro.KillerCombo and the second would use it.

I'm also thinking about supporting macros via a text file, but I'm not sure. Seems like a little overkill, but I can see where it would be really useful.

Finally, I got it hooked into my sidescroller (which is a totally separate project) without breaking it or having to modify any of the DebugConsole.h/DebugConsole.cpp code.
Sign in to follow this  


1 Comment


Recommended Comments

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement