in-engine debugging console and functions

Started by
8 comments, last by RobTheBloke 18 years ago
I've written an in-engine debugging console, and it's looking pretty good. I had to stop in the middle of it and learn how to use the boost libraries, and then stop again and write a couple of classes to properly encapsulate bitmap fonts and incorporate them into my engine. But, now I'm here. It's possible to add variables to the console and access and change their value at runtime. The console also has it's own bunch of variables for it's settings that can be changed at runtime. Now, I'm wondering about functions. I had always planned to be able to call functions from the console during runtime. My only problem is, well, where to start. I'm looking for a way to be able to keep track of the function parameters types and return types. If I can figure out a way to do that, and of course, figure out a data structure that will store function pointers for many many different functions with different parameters lists that doens't include putting in another variable type in a boost::variant variable. I know that someone suggested a scripting language for this, but I'm not really sure how that would work. If you've got any ideas, anything at all, even a random thought, let me know. :D
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Have you got Steam and the Source SDK? It doesn't give you the engine/console source but you can get an idea of how they add functions/variables to their console and use them. Just a random thought :P
You could use lua for scripting - you have to bind c function so
they are exposed to lua - makes it really easy to call c-functions

Then have a console using sth simple like sscanf to figure out
a base command and additional commands, sth like
sys framerate
sys ai showgrid
...
exec <someluatext>
execfile <luafilename.lua>

visit my website at www.kalmiya.com
You could use the well-known function signature you see in "int main(int argc, char* argv[])"

This way you just have a single flexible signature and can store your functions in a simple mapping table from name to address. Also since every function has to check its parameters exhaustively you will have some garantueed error checking in place.

Also writing some kind of command processor is really easy, say

"func -x -y -z"

would parse out the "func" function name and then call it with the parameter list (provided as argc and argv).

If you want functions to return a lot of different data it could be a bit tricky. In my system I just have an int return type (just like main()) that indicates success/failure. But you can still chain commands together. An example:

image_load "ls gfx/"

The "ls" part is in quotes and would be evaluated first (by another instance of the command processor), its output is a list of filenames that will be stored temporarily, which in turn will be sent to the "image_load" command as argc/argv. In image_load you just loop through the argv array and load images. Then when the image_load command returns, the temporary data can be cleaned up and a error code printed to the console.


This is very C-ish (I wrote such a command processor in C) but it's kind of flexible like a unix command line. I think it could be translated to C++ easily.

Just some food for thought, let me know what you think about this.
I have written a simple console system similar to the quake console. It is not the best implementation I am sure, and I personally will be re-writing it in the near future, but I'll explain how I do it now in case it might help :)

At the end user level, they need to call a very simple function

console->RegisterCommandCallBack("SetFactionMoney", FConsoleFuncSetMoney);


The first param is the command typed into console to execute the command, the second param is the callback executed when the console command is run. For ease of use, it is required that the console command cannot have any spaces in it.

Thats all the code the end user needs.

The console code is of course a bit more complicated. I won't explain how I get the command typed into the console and how the console knows a command has been typed in, I think thats probably pretty simple for you.

But this is what I then do once a command has been entered.

I check the CRC of the command entered against the CRC sig. of all the commands currently registered. If the command is not found, exit. If it is, it passes the parameters to the stored callback.
e.g.>  SetFactionMoney Sekhura 100

The above command would call FConsoleFuncSetMoney("Sekhura 100"). This is then interpreted by the function as it sees fit.

This avoids the need to have multiple function callbacks of many different types. Its true that the function has to split the args up (this could easily be improved using the methods in the above post), but it allows it to deal with it as is.

Regarding the return type, that is another matter. I always return 1 or 0 depending on the function.

One method you could use is to pass a void* to the callback, which is cast to the correct type and filled in. Instead of using the offical return route, you could get data from the function that way.

Hopefully that gives you some ideas on how you could go about it. As I said (and I'm sure you have probably seen), you could easily improve it, but the overall functionality is there.

Spree

For setting ingame values, I would agree on spreetree's method.
I think an implementation of this can be found in ogre (www.ogre3d.net),
not 100% sure though

But like I said, for more complex things like calling c-functions with
several parameters, handling return values and reacting on that,
instead of (wasting time) writing your own parser, go for an existing
script-language which you can bind to c/c++ - I would suggest lua,
but I'm sure there are lots of alternatives to it.

If you do these parser things yourself, they tend to get out of hand
with featurecreap.

Just my 2ct :)
visit my website at www.kalmiya.com
Quote:
I'm looking for a way to be able to keep track of the function parameters types and return types.


If you use boost::function, the function object will hold a list of types for the return and argument types. Those can then be used as keys for a templatized serialization [to take user entered strings and convert them to the expected arguments].

No need to re-implement string parsing in every single function you'd ever think about using with the console.
I'm guessing that this might have been the scripting engine that had been suggested to you, but here it is anyways: AngelScript
Projects:> Thacmus - CMS (PHP 5, MySQL)Paused:> dgi> MegaMan X Crossfire
Okay, here's what I'm having a little trouble understanding. Why are people telling me to use a scripting language? As I understand it, using a scripting language that can call C/C++ functions will allow you to call C/C++ functions from a function written in this scripting language.

I'm attempting to find out how to store and call an arbitrary C/C++ function from an in-engine console (not console window as in DOS, but similar in function to doom/quake console). Obviously I have to store things to make sure that each command-line parameter that is parsed is the correct type (and the types will only be primitive types are std::strings, no user defined types).

Or are people suggesting scripting languages because in some way as yet unknown to me they can help me do what I'm trying to?


Smit: I do intend to take a look at that, thanks for reminding me. I'm not really sure when I'll get a chance to, I still have to download it, and I do have some other things I want to be downloading at the moment *cough* Bleach *cough*, but I will get to it.

Telastyn: That seems like the best idea so far.

basement: Your idea is a fairly good one and probably the one I would be going with if I was writing the console for a specific game or purpose, but at the moment, it's just being a general graphics engine.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
well, you can either walk down the boost::function method, or go for a very Win32 specific fubi approach (done this before and it works quite well).

The main reason that everyone is suggesting scripting languages is, that all languages have some method for binding C/C++ functions into a scripting language. It'll save you an awful lot of messing about with various bits of code if you were just to pick a suitable scripting language and use it.

Squirrel is my current favourite, it's basically a heavily modified version of lua, to the point that it's no longer lua... It's a tad bit easier to integrate with C++ than lua is.

lua & squirrel are both small libs, neither will impact run time performance enough to care about it (well, lua can have issues with the garbage collector, one good reason to use squirell). In addition to function binding, you'll also handily get variables, for loops, if statements etc. Something that'll ultimately make your console far more useful.

This topic is closed to new replies.

Advertisement