TorqueX/ExtendingTXConsole
From TDN
NOTE: Implementing this requires TorqueX Pro, as modifications have to be made to the TX console's code (non-pro users are not able to bring up the console let alone modify the code for it). If someone creates a console that doesn't require TX Pro, the steps in this page could be used to extend it.
Contents |
Introduction
After finding out TorqueX had a debugging console I immediately got excited for the potential to make debugging game development much easier. For those who don't know, the console can be brought up by pressing the Tilde (~) key or by pressing in the left analog stick on the 360 controller. By default, TX's console can only be used to get properties from TorqueObjects and by calling properties of singletons. While this in itself can be useful, it has it's limitations. Allowing custom methods to be called through the console allows for developers to do nifty things such as calling a method in real time to load a specific level, restart a mission, give the player a certain amount of health, and anything else their heart desires.
This article describes developing a simple pool of delegates to quickly and easily add and remove method calls from the console.
Creating the delegate pooling class
The first step is to create a new class skeleton called CustomConsoleMethodPool inside of the Torque project (I created it the GarageGames.Torque.Util folder).
Now we need to create the delegate type which will define how our console methods will look like. Add the following code outside of the CustomConsoleMethodPool class:
public delegate bool CustomConsoleMethodDelegate( out string error, string[] parameters);
Next we need to implement the meat of the CustomConsoleMethodPool class. The purpose of this class is to maintain a dictionary of registered methods which can be looked up by passing in the name of the method as well as running a specific method. The code for this class is as follows:
public class CustomConsoleMethodPool
{
public CustomConsoleMethodPool()
{
customMethods = new Dictionary<string, CustomConsoleMethodDelegate>();
}
public bool RunMethod(string methodName, out string error, string[] parameters)
{
error = null;
if (methodName == "")
return false;
// Check if this method exists
if (!customMethods.ContainsKey(methodName))
{
error = "Methodpool does not contain the method " + methodName;
return false;
}
// Run the method
return customMethods[methodName](out error, parameters);
}
public void RegisterMethod(CustomConsoleMethodDelegate cDelegate)
{
// Make sure the passed in delegate isn't null
if (cDelegate == null)
return;
// Make sure this delegate isn't already registered
if (customMethods.ContainsKey(cDelegate.Method.Name))
return;
// Add the delegate to dictionary
customMethods.Add(cDelegate.Method.Name, cDelegate);
}
public void UnRegisterMethod(CustomConsoleMethodDelegate cDelegate)
{
// Make sure the passed in delegate isn't null
if (cDelegate == null)
return;
// Make sure this delegate is in the dictionary
if (!customMethods.ContainsKey(cDelegate.Method.Name))
return;
// Add the delegate to dictionary
customMethods.Remove(cDelegate.Method.Name);
}
public void UnRegisterMethod(string delegateName)
{
// Make sure we passed in a string
if (delegateName == "")
return;
// Make sure this delegate is in the dictionary
if (!customMethods.ContainsKey(delegateName))
return;
customMethods.Remove(delegateName);
}
protected Dictionary<string,CustomConsoleMethodDelegate> customMethods;
}
Modifications to the ConsoleGUI class
Now we need to setup the ConsoleGUI class to use a CustomConsoleMethodPool. Add the following code to the ConsoleGUI class:
/// <summary>
/// Specifies the custom console method pool to use
/// </summary>
public CustomConsoleMethodPool MethodPool
{
get { return _methodPool; }
set
{
#if !XBOX
_methodPool = value;
#endif
}
}
protected CustomConsoleMethodPool _methodPool;
This code gives the ConsoleGUI class a pool variable as well as a property to access and set the pool. The reason for adding a property and allowing external methods to get and set the console's methodpool is to allow greater flexibility on when and where console methods can be used. This allows you to have a set of methods which the console can call on while you are inside of a mission, allow a completely different set of methods to be called while in the main menu, and make it so at certain stages (like loading screens) no methods can be called.
Getting/Setting the property from outside of the engine's assembly
Because ConsoleGUI's class is declared as internal your game code will not be able to access and set the console's method pool. In order to give us access to it the following code needs to be added to the TorqueConsole class:
static public CustomConsoleMethodPool MethodPool
{
get { return ConsoleGui.Instance.MethodPool; }
set
{
#if !XBOX
ConsoleGui.Instance.MethodPool = value;
#endif
}
}
This allows access to the console's method pool via TorqueConsole.MethodPool. Pretty simple
Extending the console parser
Finally, we need to modify the console parser so it understands method calls and differentiates them from the original calls the console supports. For the formatting of method calls through the console I took the following format:
methodName(param1,param2,param3,....,paramX)
To implement this we need to modify the ConsoleParser.ParseText() method. In this method, right below the code to remove spaces from the entered text add the following code:
// first check if the user is trying to call a custom console method
// Syntax for calling a defined method is just methodName(param1,param2).
// An unlimited num of params can be used
if (text.Contains("("))
{
// Make sure an end parathesis was given
if (!text.Contains(")") || text.IndexOf("(") > text.IndexOf(")") || text[0] == '(')
{
error = "Invalid syntax for calling custom console methods. Correct syntax is 'methodName(paramX,paramY)'";
return false;
}
// Make sure a method pool is exists
if (ConsoleGui.Instance.MethodPool == null)
{
error = "No methodpool is currently set!";
return false;
}
// break up the parameter list into an array
int length = text.IndexOf(")") - (text.IndexOf("(") + 1);
string[] paramlist = new string[0];
if (length > 0)
paramlist = text.Substring(text.IndexOf("(") + 1, length).Split(',');
// Call the requested method
string methodName = text.Substring(0, text.IndexOf("("));
return ConsoleGui.Instance.MethodPool.RunMethod(methodName, out error, paramlist);
}
That's all you need to call custom methods from the console at runtime.
An Example
Here's a simple example to show how to use custom methods in your code. First I created a function called testMethod(). Here's the code:
public bool testMethod(out string error, string[] parameters)
{
error = null;
#if !TORQUE_CONSOLE
Assert.Warn(false, "Warning: TORQUE_CONSOLE not defined, output won't be displayed!");
#endif
// Print out all the parameters
if (parameters.Length == 0)
TorqueConsole.Echo("No parameters passed into testMethod()");
else
{
for (int x = 0; x < parameters.Length; x++)
{
TorqueConsole.Echo("Parameter #" + x + " = " + parameters[x]);
}
}
return true;
}
The #if !TORQUE_CONSOLE code is used because by default that define is not set. That does not mean you can't use the console, but instead it means that the compiler will compile out the TorqueConsole.Echo/Warn/Error methods preventing the method from writing text to the console. Many custom methods will not need to send output to the console but it's a good idea to put the warning there so if the user is expecting output and doesn't get any he knows why.
Note: An optional step you can take is to add code to the Assert.Warn() method to write warnings to the console. I'm actually not quite sure why it doesn't do this to begin with, as running the game from a command prompt in order to get warnings is annoying and limiting.
In this example method all I am doing is printing out the passed in parameters to the console, one line at a time. It's pretty simple. Now we need to add the code to create a new CustomConsoleMethodPool, register the method in the pool, and set the ConsoleGUI's method pool to point to the one we created. The code is as follows:
CustomConsoleMethodPool cust = new CustomConsoleMethodPool();
cust.RegisterMethod(testMethod);
TorqueConsole.MethodPool = cust;
And that's it. Run the game, open the console and type "testMethod()" and press enter. You can also enter as many parameters as you want. It's also good to realize that the text entered in the console is case sensitive.



