Game Development Community

dev|Pro Game Development Curriculum

Torque 2D MIT (Part 2)

by Melv May · 01/25/2013 (2:57 am) · 19 comments

This is part 2 of my technical blog, welcome back!

Part 1 of this blog can be found here.

Modules

Another aspect of Torque 2D that I found very frustrating when I first started using Torque was the sheer number of scripts I had to understand before I even started. There was no “hello world” scripts available but far, far worse was that the infrastructure scripts that dealt with things was confusing, coupled all over the place, had no version control, could not be loaded discreetly, blah blah blah. It was a confusing mess.

One of the driving forces of 3-Step Studio was the ability to update the product from the web. Add to this that this also had to happen for assets as well (I’ll come to those later).

I went to my trusty pen and paper and came up with a list of things that I felt needed to be addressed to allow for code modularity of TorqueScript without modifying TorqueScript itself (originally I was considering doing that). I knew that “packages” were a construct from the early days of Torque but they just didn’t cut-it for what was needed here.

Here’s part of the shopping list of features I came up with:

  • Physical code isolation in separate folders i.e. a “module”.
  • Module identification and versioning (Module-Id, Version-Id, Build-Id, Description)
  • Module dependency controls
  • Module discovery, loading, unloading and enumeration
  • Module meta-data (description, type, deprecation
  • Module logical grouping
  • Module live-updating
I implemented all the features above and lots more. There’s a huge wiki reference document on the GGs servers that goes into a lot of detail about this system for both end-users and developers and I won’t even attempt write-up that level of detail here but I will go over the cool stuff and hopefully demonstrate how modules are not scary and are in actual fact really easy to use.

A module is just a folder. More specifically, it’s a folder with a module definition file. A module definition file is just a torque type of “ModuleDefinition” persisted using, yes you guessed it, Taml.

In XML it looks like this:
<ModuleDefinition
   ModuleId="TruckToy"
   VersionId="1"
   Description="A monster truck toy."
   Group=”Cool”
   Dependencies=”CoreModule=1,GraphicsModule=2”
   Type="toy"
   ScriptFile="main.cs"
   ScopeSet="TruckToySet"
   CreateFunction="createTruckToy"
   DestroyFunction="destroyTruckToy"
   />
The only mandatory fields are the “ModuleId” and “VersionId” (actually this defaults to “1” so I lied). The module-Id is a unique identification for the module. The version is obviously the version but you can have multiple co-resident modules of different versions. A new version of the same module indicates a newer module but also that it has breaking changes from the old one. You can load a module explicitly by its module-Id and/or its version-Id if you wish. The same goes for unloading it. When you load a module then any specified “createFunction” in executed and likewise the “DestroyFunction” is called when it is unloaded. The “ScopeSet” is just a SimSet that is automatically generated when a module is loaded and is given the name you specify here. You can use this as a mechanism to delete objects automatically when the module is unloaded because the SimSet is deleted when the module is unloaded along with any objects added to it.

Rather than load modules explicitly which requires your code being coupled to lots of module-Ids similar to the nasty “exec(“./blah.cs”)” lines you’d see littering the scripts where if you want to load something then you’d add a line like that, you can instead assign any module to any group. The group is just a logical name but it allows you to load or unload whole module groups. This is nice because your code does not need to know what’s in the group, just that you want to load or unload it. This addressed the nasty coupling that I was seeing in the scripts. Being able to have your application load or unload a logical set of modules is very nice indeed. Also, internally, modules are reference counted so if a module needs loading but it’s already loaded then it gets a reference count bumped-up. Likewise for unloading where a module will only be unloaded if it has no references.

Another extremely useful feature is dependencies. You can define which modules this module depends on, even specify a specific version. This informs the module system that to load this module requires that the specified modules need to be loaded first. This happens recursively and can automatically detect and warn about cyclic dependencies. It can also warn about incompatible versions. The only rule with the module manager is that a only a single version of any module id can be loaded at once. This is because a new version is a breaking-change of the previous version but also has potentially conflicting function and object names or behavior. Each module does have a serial-Id and the asset system has methods that allow you to update modules for publishing. The scripts that presented that to the end-user is in 3-Step studio but the infrastructure for it is in the module manager.

This dependency and version might seem like overkill for some and you are free to just leave all your modules at version “1” and be done with it and that’s fine. However, there’s a whole project synchronization infrastructure designed around modules that allows very cool things like having a game project that can have modules updated after the fact. Even allowing new modules to come along and not replace existing modules being used in a game project. All this without requiring that a game project have copies of all the module code placed into the project folder. Essentially the code just asks for modules and the engine takes care of the rest.

One final feature is that the “^” expando character used when expanding and collapsing paths is now used a lot in T2D. This is because when a module is loaded, an expando is automatically generated with the module-Id. This means that for any module, code within it can get its own location by using something like:
TamlWrite( “^MyModule/scene.taml”, %scene );
This will write the file “scene.taml” in the root folder of the “MyModule” location.

Asset System

Gone are the days of a single script file containing, typically, a SimSet that contained a bunch of datablocks containing state that defined some kind of asset. Most of the time this was something like the t2dImageMapDatablock and always each used the Torque object-name feature where an object was assigned a global name that could conflict with other objects. Goodbye, I won’t miss you.

Like the module system, the asset system is a complex system to describe and there’s a huge internal wiki document that does just that however the day to day use of it is crazy simple. Most of the asset system functionality is for an editor as it provides lots of administration functionality for generating, destroying and querying assets and asset meta-data.

So previously you had a file containing TorqueScript code that described an object. Each of these objects contained all the fields for that object. Now, that file has been replaced with an asset definition. An asset definition describes an asset but in reality, it’s just an object persisted using Taml.

The legacy T2D didn’t have any real definition of an asset, it was just a term used to mean “something that objects consumed”. In the new T2D, there are real assets and they are all derived from a type named “AssetBase”.

The initial set of assets available are:

  • ImageAsset (Replaces the old t2dImageMapDatablock)
  • AnimationAsset (Replaces the old t2dAnimationDatablock)
  • AudioAsset (Replaces the old AudioProfile)
  • ParticleAsset (Replaces the old t2dParticleEffect & t2dParticleEmitter)
The asset system provides a lot of functionality but essentially it allows you to scan a folder for assets. When these are discovered it maintains an internal database of them all. They can then be used as soon as they are discovered.

Here’s an example of a basic ImageAsset type:
<ImageAsset
    AssetName="background"
    ImageFile="@assetFile=#background.png" />
This is an asset named “background” that uses the “background.png”. The “#” you see is a shortcut meaning a file relative to the location of the asset definition file. You can use anything you like here, even relative locations but it’s common for the asset definition to be located alongside the asset data.

Now it may scare you that at start-up the system is going to scan and load all assets but that absolutely isn’t the case. What does happen is that the asset system knows about the asset definitions and their names but does not load the assets, that’s done elsewhere when required.

An important aspect of assets is that they have a partially-qualified and fully quality identity. In the example above, the asset is named “background” and this is the partially-qualified name. The thing is, you will NEVER refer to this asset as background and the reason is that it’s quite likely that you’ll conflict with another asset named “background”. If you keep tight control over your asset names then that might not happen though. Indeed, historically folks used horrible name encodings to try to make each unique.

The asset system gets around this however forcing assets to be contained within a module. Modules not just for code, they can contain assets. Indeed, modules can be thought of as isolated “asset packs” which you can obviously load/unload, even have versions for them! This means that if you were to get an “asset pack” module from a buddy or from someone selling one and want to integrate it within your game, there’s a good chance that it’ll contain assets with names that conflict with ones you already have.

To get around this, assets are always referred to by their fully qualified names. This is in the form of:
ModuleId : AssetName
So for instance, in a module Id of “EnemyAssets” with an asset named “Monster” you’d assign it to a sprite like this:
%sprite.Image = “EnemyAssets:Monster”;
This fully-qualified form is known as the asset-Id and it’s what you’ll be using all over the place. This means that you can have two assets named “background” and it won’t matter because they must be in different modules. If you attempt to use assets of the same name within the same module then the asset system will warn you about it, giving you a lot of detail about what went wrong.

This configuration is very nice because as an author of these assets, you have the freedom to both configure and name your assets however you like. You can use whatever naming conventions you so choose as well knowing that the asset-Id is generated by prefixing the module-id of your asset pack and that it won’t conflict in any way with other modules. The trick of course is ensuring that your module-id is unique but it’s a nice high-level scope that everyone will use.

Also, given the example above, the assets in the module “EnemyAssets” won’t become available until that module is loaded. If you perform queries on the asset manager, you won’t see these assets if the module is not loaded. This confirms that the system doesn’t scan and load all assets at start-up.

Another huge change with this system is how and when assets are loaded. When you reference an asset, it is acquired and assigned automatically. If you assign the same asset to another object that uses it then it gets it immediately without the asset being loaded (it’s already loaded). In other words, assets are reference counted, The same goes for when assets are no longer referenced, they are unloaded although you can control the unloading allowing all assets or specific ones to stay in memory until the module is unloaded or your perform an asset purge.

Unloading of assets might have veteran users of legacy T2D worried. The old t2dImageMapDatablock was powerful in that it could take any sized image and ensure that it was packed into a texture (or textures) that were compatible with the target hardware. That’s great for novices however it’s a content-pipeline process that is being executed at runtime and was the number one problem on mobile platforms causing considerable performance problems.

The new ImageAsset does none of that. Gone are the crazy modes and a few dozen options. The image that is loaded is the texture that gets uploaded to the GPU. You can section the texture as before into frames but it’s a simple load the thing up and get it as a texture rather than the legacy load up the image, copy parts of the image and pack them into a memory bitmap (or bitmaps) then upload them to the GPU. it also means that things like resolution switching on desktop platforms is super-quick as it does not require a whole bunch of stuff being calculated.

This simplified configuration and the use of Taml in Xml format means that you can consume XML based data configuring things like image-assets. This is why when I downloaded the demo of TexturePacker and looked at how it can be customized to output a custom file it took 20 minutes to get it to work. It actually took longer to grab this video showing me doing it:



For C++ developers, there’s an internal smart-pointer system that allows you to reference assets without any concern over how they are loaded or even persistence. Even Taml knows about assets (not directly but indirectly via the smart asset pointer) meaning you can have fields that expose the asset assignment and they persist using Taml.

Without going into more detail of each feature I’ll highlight some other awesome features of the asset system as well. For one thing, T2D “knows” about the assets you use in a game project. As I said, I won’t go into the detail here but the great thing is that the system is aware of what assets your project is using and therefore perform publishing options like only publishing the assets you use. It therefore knows about assets being used that don’t exist and can inform you of that too. It not only knows what assets you use but it also knows where you use them. This means that if you were to ask the asset system to rename an asset then it knows to rename the asset references you have. Also, it can delete assets for you and it knows not only where they are used but also what “loose files” are being used. A loose file is something like an “audio file” for an Audio Asset or an “image file” for an Image Asset etc. This is known as asset referencing and loose-file referencing.

T2D not only supports asset referencing from the obvious things like scene-objects but it also knows about references of assets from other assets i.e. assets using other assets. This may sounds strange but it’s actually quite common. Take, for instance, an AnimationAsset. That might be defined like this:
<AnimationAsset
    AssetName="BananaWiggle"
    Image="FruitAssets:Banana"
    AnimationFrames="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
    AnimationTime="5" />
This is an animation asset and as you can see, it has a field of “Image” which is an asset reference, in this case an “ImageAsset” reference. When this “BananaWiggle” asset is discovered by T2D it not only knows about this asset but it also takes note that it requires i.e. depends on another asset of “FruitAssets:Banana” of the type “ImageAsset”.

This means that the animation asset requires an image asset. It also means that if you assign the animation to a sprite like this:
%sprite.Animation = “FruitAssets:BananaWiggle”;
… then the asset system will first load the “FruitAssets:Banana” image-asset (assuming it’s not already loaded) followed by the animation. Of course if any of these things are already loaded then nothing is loaded, just reference counted. The same goes, of course, if they are not reference any more such as destroying a sprite that used the animation. In this case both the animation and the image assets have their references reduced which may result in them being unloaded.

Although primarily for an editor, the asset system provides a dedicated query system that allows you to perform asset queries on all the asset meta-data. You can even pass previous queries to refine results. So for instance you can query all assets of a particular asset type i.e. "ImageAsset" then refine the search for assets that have the word "Zombie" in them and continue like that. The system uses a dedicated AssetQuery object to completely remove the need to pass long and slow strings back and forth. When you've finished performing your query or queries you can retrieve your results in very much the same way you would retrieve objects from a SimSet. Asset queries return asset-Ids which allow you to perform work on your results.

A final thing I’ll mentioned about the asset system is its notification system. If an asset changes, in any way whatsoever, then anything that uses it gets notified if it wants to. Assets don’t change often and nearly always in an editor so there’s very little to worry about in a game runtime nevertheless, it’s still super-fast as the notification is a simple callback. The net result is that any object using an asset knows that it’s been updated and respond accordingly. This also applies to other assets that may be using another asset i.e. an animation uses an an Image asset. If an image asset was updated then any animation assets using it would also be updated and their frames validated. Anything using those animations like a scene sprite or a GUI control would see the change instantly.

Whilst this is used typically in an editor, you are free to use it for cool things in your game should you so choose.

There’s a huge set of features here but far too much to go into now. It’s safe to say that the asset system is powerful but it’s also really easy to use. You just assign the asset-id and all is done for you.

These two systems are by far the biggest change to T2D and at first they are a lot to take in but then you realize that actually using them is really simple. In an attempt to show you not only what the new Sandbox set-up looks like but also working with modules and assets, here's a video of me using a simple toy to create a sprite using a static asset rotating on the screen:



Part 1 of this blog can be found here.
Part 3 of this blog can be found here.

#1
01/25/2013 (8:22 am)
Hi Melv;

This Module system is a boon for not only making our individual repositories usable but affords the opportunity for teams to really work well together.

Packing assets within a module can allow many individuals to work on particular assets of the product without concern for what other developers/artists are doing with their respective parts.

Thank you,

Brian
#2
01/25/2013 (8:23 am)
You hit the nail on the head there Brian. Thinking of them as not just code repositories but also asset repositories is the way to go.
#3
01/25/2013 (8:48 am)
This YAML and module stuff is fantastic. Seriously, everything I've read in these three blogs has been just spot-on in terms of making Torque not only a viable option for an engine, but one of the best.
#4
01/25/2013 (3:23 pm)
Is that editor going to be released with Torque 2d MIT ? It was my understanding that the MIT version of Torque will not be released with any kind of editor.
#5
01/25/2013 (4:47 pm)
@Jimmy - What editor are you referring to?
#6
01/25/2013 (8:13 pm)
@ Michael I was referring to the tools being used in the videos.

Nevermind, just finished reading part three of the blog.
#7
01/26/2013 (4:11 am)
For anyone else who didn't see, the tool is called TexturePacker. We will include our exporter and a readme file on how to install it. It is a very useful tool at a super low cost. I highly recommend everyone pick it up.
#8
01/26/2013 (5:38 am)
@Michael, thanks for pointing me to that util, very useful :-)
#9
02/03/2013 (7:36 pm)
It sounds great, but I'm having trouble wrapping my head around a serious use case. Can you provide one @Melv/@Mich?

I guess I have PTSD from using module dependency systems, which tend to add a layer of complexity as different people on the project link to different versions of the same module and require all kinds of hand-edited one-off fixes.

It seems I'd normally have "MyGameModule" and work in there. *Maybe* I'd have the a module per stage for the art. That's cool.

But, if a basic "clean slate" project has too many "core" modules, it's going to get ugly, I think!
#10
02/03/2013 (7:39 pm)
While I'm in constructive concern mode, programmers have started to back away from "line noise" languages like Perl and towards verbose languages like Ruby/Python/etc. My point?

This line above:

ImageFile="@assetFile=#background.png"

Is there any way that can be

ImageFile="background.png"

And have the engine read or fail at load time if the image is not an "assetFile" type?

I'm assuming a real game will have LOTS of assetFile's.
#11
02/03/2013 (7:43 pm)
I'm not a big fan of exec("../blah.cs") either, but if you remove it currently, you can't order the dependencies between scripts, at least not in a module together.

Here would be an opportunity for dependency tracking!

How about loading all the scripts in a module by default. However, a script can have an asset file as well. And that asset file could describe if the script is dependent on something else loading first, like so?

Quote:
<ScriptAsset
Script="later.cs"
Dependencies="previous.cs","multicast.cs"
>
#12
02/03/2013 (7:47 pm)
One *final* constructive idea. :)

For the "line noise" expando character, how about assuming that the game directory is the root, then

TamlWrite( "^MyModule/scene.taml", %scene );

could become

TamlWrite( "/MyModule/scene.taml", %scene );

I don't think there is a good reason to allow a game outside of the "sandbox" of its own game directory.
#13
02/04/2013 (12:50 am)
Not got much time this morning but I'll try to cover your points briefly.

I'll start by saying, thanks for the constructive feedback!

So in terms of modules, I too have many (oh so many) years of modular systems, especially in the large-scale. For this however, it's a pretty simple set-up but like those large-scale systems it has some vital ingredients: versioning and dependency control.

The thing is, your point about too many modules is valid and I think you'll be pleased to know that we're NOT shipping with lots of infrastructure modules. I didn't want them and the ones we had were for 3SS. We actually only had two for any game "runtime" which were named "GameBoot" and "GameCore".

T2D has been stripped down to its bare-ass. We're not shipping with modules that contain complicated level loading code or crazy feature persistence stuff etc.

A "hello world" in T2D is now possible in a single script with a window, a scene and a few lines of code. That was important to me to achieve. I think the Sandbox we're shipping with will show you how this isolation and simplicity works for T2D.

For the "line noise" you mention; you do not need to use those prefixes. I got into a habbit of typing them out in full but you are free to just use the filename. Told you I was verbose!

Without going into too much detail, each Torque Console Type can have its own prefix now. These assets have theirs. They are primarily used by an editor for other features but are totally optional for you.

Also, with a single change you can ask the asset system to go into "verbose" mode (like its father). When this is on, almost everything the asset system does is output to the console such as asset discovery, meta-data info, dependencies registered (asset to asset). Also asset loading, unloading etc.

With it off, the asset system only outputs when there's a problem. For instance, if you try to load an asset like an animation that requires another asset but that asset could not be found then the asset is not loaded and the asset system gives you a clear dump of what asset was being acquired, what assets is requires and which asset dependencies were not loaded.

Exactly the same thing is available for the module system btw. It'll provide you with module discovery, loading, unloading info etc.

In terms of executing scripts using "exec()". That has not gone away, it's still a vital ingredient of Torque. The module system is not about doing away with the loading of individual scripts but creating logical functionality of your choosing and providing some isolation and at least making it easier to see code coupling where you perhaps don't want it. The module system will load/unload the module as required and as specified in the dependencies. What you do (or don't do) in the module load/unload is up to you.

This "compartmentalization" of things helps in deeper ways. For instance previously you have a "rootgroup" simset for the whole game which you knew would deal with destroying stuff when the game ended. Modules each have their own and its named the same as the module-Id so for a module named "Charlie" you'd get a simset named the same. You can add objects to this, push dynamic-fields to it etc. When the module is unloaded, all its child objects are destroyed then the set itself is removed. This is very handy indeed. You can obviously also use it to isolate functions for the module by using the module-id name as a namespace. Sure you can do this yourself but it's one of the many extra goodies you get for free.

You can think of a legacy TorqueScript application as a single module with a bunch of "execs". This system allows you to decompose that into whatever compartments you so desire only loading what you need, when you need it. Granted a lot of this is more helpful for an editor but its use creeps into game projects in more ways than at first it might seem useful. Asset "packs" are the obvious one but also, having a game project that is made up of modules means that your game project can be updated with the latest version of a module etc. In TGB, after the system generated your project, you were on your own. If a "core" script was updated, you would have to merge those changes with existing game projects. Not so with this or at least this being used in 3SS.

For the expando "noise". You are free to use:

TamlWrite( "^MyModule/scene.taml", %scene ); <- Root module folder.
TamlWrite( "scene.taml", %scene ); <- Root of game folder.
TamlWrite( "/scene.taml", %scene ); <- Root of file-system (not recommended).

Hope this helps.
#14
02/04/2013 (8:40 am)
Thanks @Melv.

One of my favorite aspects of T2D has been how easy it is to get started, even though the depth is often there. I see you are a driving force behind that. When I check out a new toolkit, be it MFC or Qt or Box or openGL or renderMan, the first thing on my mind is how easy I (and others) can get started before learning the depths of the tool. Torque is a rarity in it's thought-out design.

(I was always a little surprised that I had to add my objects to the scene graph instead of that happening by default :P)

As for the expando example, it's not a huge thing but I remember it being a hard-to-find-documents-for intial issue with using Torque. Instead, like the mighty fine Apache web server, it would be nice to NOT have absolute paths to your system root anyway. Then you can avoid one more concept to learn:

"/scene.taml" for game folder
"/modules/MyModule/scene.taml" for a module
"~save1.taml" for the user's game-specific app storage
"./scene.taml" or "scene.taml" for storage in "this" module (or whatever)

#15
02/04/2013 (9:01 am)
While I'm being a stickler about "line noise", perhaps you can load an asset as "module.asset" instead of "module:asset". All the modern scripting languages (since Java I guess) are moving towards a period for separation.
#16
02/04/2013 (9:05 am)
This separator is defined in a single place. You could change it, recompile and go.

#define ASSET_SCOPE_SEPARATOR           ":"
#17
02/04/2013 (9:42 pm)
Heh. The intention of my picky comments is that lots of things will probably get locked into place upon first release. One of the more antiquated aspects of Torque, in my opinion, is the %$!#: styling.

I believe the reason several languages and tools have moved away from it (with some exceptions, of course) is because it's harder on the beginner. Also, if you can express as much without them, great. (Hence Java using . instead of ::).

For instance, I notice old examples on here had modules like {myModule} and the curly braces are gone now.
#18
02/05/2013 (12:14 am)
Steering Committee? :)

If things get "locked into place" then the whole point of this being open-sourced has been lost really. It's not for GG to tell folks how it should be but to allow everyone to join in to drive how it can be. If enough folks say let's change that character by default then it'll happen. What you like, others won't so consensus wins else you have it how you like in yours. Choice is key.

I think this is where talking about something prior to it actually being released is a bad idea. The old examples were just that, examples. You can use any character for your module names (apart from the scope character) after all they are *just* strings and not language namespaces (which have pretty hefty restrictions) and where the analogy falls down in my opinion. Surrounding them in curly braces was what the 3SS team did but for the T2D modules we didn't use them. It doesn't involve engine changes however.

I'd be happy with almost any character including the period but at this late hour, it's hardly feasible to change this unfortunately. As I indicated previously, I made it trivial to change which is an important step.

I appreciate your feedback and maybe you'll consider the link? :)
#19
02/05/2013 (9:55 am)
Thanks @Melv.

I'll save my counter-points for another day. I'm considering asking for a slot on the committee, but I'm not sure if I have the 8 hrs/week anymore. Ugh.