Adding your own console methods and functions
by Alex Scarborough · 02/01/2005 (10:14 am) · 6 comments
Adding Script Functions and Methods via C++ Source
The first thing that must be clarified is the difference between a function and a method. A function is universal and is not called by an object. A method on the other hand is called by an object and is aware of that object. More often than not, you will be using methods.
Console methods are actually surprisingly easy to implement. As a simple example, let's examine item.cc. Starting on line 931, there are five defined console methods: isStatic, isRotating, setCollisionTimeout, getLastStickPos, and getLastStickyNormal. Take a look at how isStatic is defined:
The first argument is the class name. Only objects of this class can call this method. This argument is not part of ConsoleFunction.
Next is the method name, which is what you'd be calling in script. (%itemObj.isStatic())
Then we have what type of data it returns (bool, int, float, etc.)
Next is the minimum number of arguments, then the maximum number.
But waitisStatic doesn't have any arguments!
As far as calling it from script goes, it has no arguments. However, ConsoleMethod considers the name of the method and the object calling it to be arguments, therefore all ConsoleMethods must have a minimum of two arguments. ConsoleFunctions only have a minimum of one because they are not called by any one object.
Finally, we have the doco field, which is used for documentation.
Never underestimate the power of console methods. Because they are located in the source code, they have full access to all source code level functions, which allows them to do a variety of complex tasks not possible in script alone.
Now how does this all work together?
Did you know that many objects in Torque can render shadows(StaticShape takes a little more tweaking than what is shown here, for TSStatics, buy the lighting pack. Thanks for pointing that out Brett)? The reason they don't is because by default, up in ShapeBaseData, mGenerateShadow is set to false. Let's write a console method that will allow us to turn shadows on and off for individual objects.
Open up shapeBase.cc and scroll down to the beginning of the ConsoleMethod declarations (line 3519). At the very beginning of these, we'll add ours. Let's call it "switchShadowState". It will only need two arguments, the name and the ID of the object that called it. So, first the declaration
Notice how we didn't set the variable directly in the console method.
Now, for this to work, somewhere after IMPLEMENT_CONETOBJECT in your code you need to add
And you're done! Go ahead and try it out in starter.fps. Get the handle of a health pack and in the console call switchShadowState on it. You should see a shadow being cast from it now. Cool, no?
Notes: The object calling the method is always the first argument, the name of the method is always the last argument. All other arguments you may include are in the middle.
All arguments are passed to ConsoleMethod as strings. To extract useful data from these strings, you need to use dAtoi for ints, dAtof for floats, or dAtob for bools. For a complete list of various functions you can use with strings, refer to this (Don't you just love DOxygen docs?)
ConsoleFunction works in a similar manner, only it is not aware of the object calling it, greatly reducing it's usefulness in many situations.
C++ functions can not call console methods or functions. However, you can call functions defined in script via C++ using Con::executef(). The setup for this is
More Console Stuff DIY. You always learn more that way.
Here is another resource on adding console methods and functions.
The first thing that must be clarified is the difference between a function and a method. A function is universal and is not called by an object. A method on the other hand is called by an object and is aware of that object. More often than not, you will be using methods.
Console methods are actually surprisingly easy to implement. As a simple example, let's examine item.cc. Starting on line 931, there are five defined console methods: isStatic, isRotating, setCollisionTimeout, getLastStickPos, and getLastStickyNormal. Take a look at how isStatic is defined:
ConsoleMethod(Item, isStatic, bool, 2, 2, "()"
"Is the object static (ie, non-movable)?")What's going on here?The first argument is the class name. Only objects of this class can call this method. This argument is not part of ConsoleFunction.
Next is the method name, which is what you'd be calling in script. (%itemObj.isStatic())
Then we have what type of data it returns (bool, int, float, etc.)
Next is the minimum number of arguments, then the maximum number.
But waitisStatic doesn't have any arguments!
As far as calling it from script goes, it has no arguments. However, ConsoleMethod considers the name of the method and the object calling it to be arguments, therefore all ConsoleMethods must have a minimum of two arguments. ConsoleFunctions only have a minimum of one because they are not called by any one object.
Finally, we have the doco field, which is used for documentation.
Never underestimate the power of console methods. Because they are located in the source code, they have full access to all source code level functions, which allows them to do a variety of complex tasks not possible in script alone.
Now how does this all work together?
Did you know that many objects in Torque can render shadows(StaticShape takes a little more tweaking than what is shown here, for TSStatics, buy the lighting pack. Thanks for pointing that out Brett)? The reason they don't is because by default, up in ShapeBaseData, mGenerateShadow is set to false. Let's write a console method that will allow us to turn shadows on and off for individual objects.
Open up shapeBase.cc and scroll down to the beginning of the ConsoleMethod declarations (line 3519). At the very beginning of these, we'll add ours. Let's call it "switchShadowState". It will only need two arguments, the name and the ID of the object that called it. So, first the declaration
ConsoleMethod( ShapeBase, switchShadowState, void, 2, 2, "")Here we have a method that any ShapeBase object can call named switchShadowState. It returns nothing, and no arguments are passed from the script call. Continuing
{
object->switchShadowState();
}Notice how we didn't set the variable directly in the console method.
Now, for this to work, somewhere after IMPLEMENT_CONETOBJECT in your code you need to add
ShapeBase::switchShadowState()
{
mGenerateShadow = !mGenerateShadow;
}And you're done! Go ahead and try it out in starter.fps. Get the handle of a health pack and in the console call switchShadowState on it. You should see a shadow being cast from it now. Cool, no?
Notes: The object calling the method is always the first argument, the name of the method is always the last argument. All other arguments you may include are in the middle.
All arguments are passed to ConsoleMethod as strings. To extract useful data from these strings, you need to use dAtoi for ints, dAtof for floats, or dAtob for bools. For a complete list of various functions you can use with strings, refer to this (Don't you just love DOxygen docs?)
ConsoleFunction works in a similar manner, only it is not aware of the object calling it, greatly reducing it's usefulness in many situations.
C++ functions can not call console methods or functions. However, you can call functions defined in script via C++ using Con::executef(). The setup for this is
Con::executef(object, argc, name, arg[1], arg[2]);Where object is the SimObject calling the function(usually mDatablock or this Note: This field is only necessary if the function belongs to a namespace), argc is the number of arguments, name is the name of the script function, and arg[1], etc. are the arguments to be passed. A very useful function that can be used with this is scriptThis() which will return the ID of the SimObject. There is always 1 argument (the name of the function) but the calling object does not count as a second argument.(Thanks Stephen. Hope I got that right)
More Console Stuff DIY. You always learn more that way.
Here is another resource on adding console methods and functions.
About the author
#2
Not all objects can render shadows. Any objects that implement ShapeBaseData can, but not any object. Some objects are tsStatic, while yet others are StaticShape, so they wouldn't render shadows. However, there are some great forum threads covering this. In fact, look for one by Melv May and shadows and statics.
- Brett
02/01/2005 (1:48 pm)
One other inaccuracy...Not all objects can render shadows. Any objects that implement ShapeBaseData can, but not any object. Some objects are tsStatic, while yet others are StaticShape, so they wouldn't render shadows. However, there are some great forum threads covering this. In fact, look for one by Melv May and shadows and statics.
- Brett
#3
@Stephen: Thanks for pointing that out, I'll read the docs for it and update the resource.
02/01/2005 (4:56 pm)
@Brett: I've gotten statics to render shadows... they just render on the skybox for some odd reason. Anyways, I'll change that soon. Didn't realize the resource was going to go up so soon, and submitted it before actually being able to test it. Yea... that was pretty stupid of me.@Stephen: Thanks for pointing that out, I'll read the docs for it and update the resource.
#4
Thanks,
Gary (-;
02/08/2005 (4:48 pm)
Great resource, except you don't explain what the "()" parameter does...Thanks,
Gary (-;
#5
"Is the object static (ie, non-movable)?"? The "()" is an example call to the method. So, it says that the method needs no script specified arguments.
02/08/2005 (5:00 pm)
@Gary: you mean in the doc field where it says "()""Is the object static (ie, non-movable)?"? The "()" is an example call to the method. So, it says that the method needs no script specified arguments.
#6
ConsoleMethod(Item, isStatic, bool, 2, 2, "()"
"Is the object static (ie, non-movable)?")
I've only just realised that there's not a comma at the end of that line... Duh.
Thanks,
Gary (-;
02/08/2005 (6:24 pm)
Actually, I was looking at:ConsoleMethod(Item, isStatic, bool, 2, 2, "()"
"Is the object static (ie, non-movable)?")
I've only just realised that there's not a comma at the end of that line... Duh.
Thanks,
Gary (-;

Torque 3D Owner Stephen Zepp
In fact, they can, and do so in many, many circumstances. I don't have code in front of me at the moment, so I cannot go into complete detail, but the c++ function Con::executef(...) is written specifically (in console.cc IIRC) to allow a C++ method to call a function or method written in TGEScript.
An example here from memory is onCollision()--this is a method that is called from the collision C++ code with the appropriate information, but lets scripters handle how the actual collision is handled. While extremely powerful, passing control back and forth between code and script can make for convoluted control flow, making it a bit harder to debug (look at the way connecting to a server is handled in depth for an example of what I mean--control flow goes back and forth between script and code, both on client and server, with several ack-controlled timing steps), but it is so flexible and gives so much functionality to your game that understanding control flow passing between script and C++ is an integral part of making a quality game!
EDIT: After re-reading the above quoted statement a couple of times, what you say is semi-true: the macro that is used when you define a console method hook creates a differently named c++ function, so in fact you cannot actually call a specific console method itself. You could analyze the macro and form a method/function call that does in fact call your final console method, but it's not worth the trouble most of the time.
This clarification being made, as I described, you can still call scripted functions and methods via the Con::executef() handle.