Game Development Community

dev|Pro Game Development Curriculum

A handful of handy Torque tips

by Tom Bampton · 07/26/2006 (11:19 pm) · 22 comments

Torque 1.4 has got an incredible amount of useful code, and a lot of it is not obvious. This blog is a handful of handy tips on some of the less well known aspects of Torque, and some of the more well known things for good measure.

Replacing the TGE Master Server with minimum effort

Did you know that stock Torque supports a favorite server list ? The list is populated through a couple of client prefs, and is queried whenever the master server or LAN is queried. The C++ code also has a function to query the favorites list directly, but it's not exposed to script.

Add a simple 2 line console function for queryFavoriteServers() and you can query the favorites server list independently of the master server or LAN. The code for queryFavoriteServers() can be mostly copy/pasted from the querySingleServer() console function. Once you've done that, to replace the master server is simply a matter of populating the favorite server list and calling queryFavoriteServers() instead of queryMasterServer(). The changes you need to make to joinServerGui.gui are mostly minor and obvious - and you get pings, player count, etc for essentially free.

To actually populate the server list, there are two variables you need to use. Set $Pref::Client::ServerFavoriteCount to the number of servers in the list and populate the $Pref::Client::ServerFavorite array with the actual server information. For example:

function addServerToList(%name, %address)
{
  $Pref::Client::ServerFavorite[$Pref::Client::ServerFavorite] = %name TAB %address;
  $Pref::Client::ServerFavoriteCount++;
}

This, of course, assumes $Pref::Client::ServerFavoriteCount is initialized to zero before you start to populate the list. In the project I came up with this for, I also changed the names of the variables so that they weren't part of the prefs to ensure that the list wasnt saved in the client prefs.

Since there is no heartbeat to send to the master server (unless you add it), this tip works best when you have a controlled server list. For example, in a database downloaded via a PHP script. The actual implementation of the backend is left as an exercise for the reader.

Of course, alternatively you could use the favorite servers list for actually implementing favorite servers, but that's not nearly as interesting ;-)

Frustum Culling

Frustum Culling is the process of culling (e.g. not rendering) geometry that's out of the viewing frustum. Torque already culls object if their entire bounding box is outside of the view frustum, but what about large objects? With a huge object (for example, a .dif building) most of the time you will only be viewing a small part of it so rendering all of it would be pointless. It's worth pointing out here that interiors already do their own frustrum culling and so are a bad example where performance is concerned.

So, lets look at a rather extreme example. As a performance test a while ago, I threw together a huge test level for Alive and Ticking, you can see it below:

www.burntwasp.com/bm/huge-fps2.jpg
This monster SceneObject is 109 x 43 blocks. Each block is 2.7 Torque units (a little over 1 standard Orc width), which equates to 294.3 x 116.1 Torque units. With the camera positioned to view the whole level, we're getting a whopping 43 FPS. Considering there's only 2 objects visible (the level and the player), I think you'll agree that's pretty crap.

Fortunately, when playing the game we're never going to be viewing the whole level. It will look more like this:

www.burntwasp.com/bm/huge-fps1.jpg
And now we're getting a much more respectable frame rate! The fundamental point here though, is the only reason for the better frame rate is frustum culling. If the level object didn't do frustum culling, the frame rate in the second screenshot would be exactly the same as the first screenshot.

What's the point in all this? Well, adding frustum culling to the level rendering code took 2 lines of code. Torque 1.4 provides an incredibly easy to use frustum culler in util/frustrumCuller.h.

There is no TDN article on the frustrum culler, but if you're in a position that you need it you should have no problem figuring it out from the header file.

Frame Allocator

Memory allocation is a slow business. When you only need memory temporarily (e.g. for the life of a function), wouldn't it be great if you could just get that memory from a pool and save the hassle of going through the OS to get it ? Well, you can, go and read this TDN Article on the Frame Allocator and have your eyes opened.

ITickable

What if you have a SceneObject and you want the tick processing that GameBase gives you, but you really don't need nor want a datablock ? What if you're writing a GUI control and you want to smoothly animate something without writing lame timing code in your render method ? Then you use ITickable.

BitStream and Chunked File Formats

If you've done any networking with Torque, you've probably come across BitStream. BitStream is derived from the normal Torque Stream class so you can use it like any other stream in Torque, but it also adds methods for bit packing data. Since Torque 1.4, there's also a ResizeBitStream and InfiniteBitStream which allow you to easily create a memory based bit packed stream. InfiniteBitStream also adds a couple of useful methods to write the BitStream out to another stream and obtain a CRC32 of the data.

This makes it incredibly easy to create an efficient chunked file format. In fact, Torque 1.4 already has one, which is the reason that Ben wrote ResizeBitStream and InfiniteBitStream in the first place. There used to be some test code for the chunked file format in common/main.cs ... I don't know if it is still there, though. If not, have a look at core/chunkFile.cc/h.

As an aside, one of the more insane uses I've put BitSream to is storage for undo/redo data. I may talk about that one day, but it's a big topic and the code isn't finished yet.

DSOs

It's probably more or less common knowledge that you can set $Pref::ignoreDSOs to 1 to stop Torque creating DSOs. But, did you ever stop to think that .mis files are Torque scripts, get exec'd, and yet they never produce a .dso ?

If you do a find in files in the C++ code for ignoreDSO you'll find the line of code that controls DSO creation. Want your own file extension to avoid DSOs ? No problem, just add it to that line in the same way as .mis. I've used that to good effect before to create .prefs files, which were the normal prefs.cs and config.cs combined into a single file. A script managed list of extensions to never produce DSOs is something that's been on my to do list for a while.

SAFE_DELETE

You can find SAFE_DELETE macros in util/safeDelete.h. You may be familiar with them from non-Torque development, but since 1.4 Torque has had them too. In case you're not familiar with them, SAFE_DELETE ensures that the pointer is not NULL before deleting it, and sets the variable to NULL after deleting it. There's also a companion SAFE_DELETE_ARRAY macro for memory allocated with the new [] operator.

I also have a SAFE_DELETE_OBJECT macro that uses deleteObject() to delete a SimObject instead of the delete operator. Ben said it was OK to post it here, so here it is. Just add it to util/safeDelete.h and enjoy.

#undef  SAFE_DELETE_OBJECT
#define SAFE_DELETE_OBJECT(a) if( (a) != NULL ) (a)->deleteObject(); (a) = NULL;
Page«First 1 2 Next»
#21
07/28/2006 (4:52 pm)
@Orion: LOL! It's a common mistake for some reason... (Everyone together now, say it 10 times: "Frustum Frustum Frustum..... " =)

@Tom: Thanks for the info... definitely some good stuff to know about even if it's not all needed for day to day coding.
#22
02/28/2008 (2:09 pm)
I found this in the middle of trying to write the Favourites functionality from scratch... Shoo ;)

Above script has minor error, should be:
$Pref::Client::ServerFavorite[$Pref::Client::ServerFavoriteCount] = %name TAB %address;
Page«First 1 2 Next»