ActionScript 3 Reflection: list fields on an object with ClassFieldCache

Say you’re working on some sort of reflection/deserialization system in Flex, Flash, or another ActionScript 3 technology. It would be nice to know the type of all the fields on an object or class, including accessors, so that you can automagically infer the right way to parse your serialization data. You can use describeType to do this but it has some overhead – dumping a full XML description of a complex type can’t be something you’d want to do frequently, and then you have to parse it again.

I present the ClassFieldCache. It contains one static method, getFieldsOfClass, which will return a dictionary of types indexed by field name. It returns every kind of property you can set – both fields and accessors. (And it ignores constants and readonly accessors.)

Usage is like this:

	var dict:Dictionary = ClassFieldCache.getFieldsOfClass(myObject);
	trace("Field boo is of type " + dict["boo"]);

Which outputs “Field boo is of type flash.geom::Point” – or whatever that field happens to be.

And the class itself is as follows:

	import flash.utils.*;

	/**
	 * Utility class to get list of fields on an object or class.
	 */
	public class ClassFieldCache
	{
		/// Indexed by Class, this contains dictionaries mapping name to type (string).
		private static var smFieldInfoCache:Dictionary = new Dictionary(true);

		/**
		 * Return a dictionary describing every settable field on this object or class.
		 *
		 * Fields are indexed by name, and the type is contained as a string.
		 */
		public static function getFieldsOfClass(c:*):Dictionary
		{
			if(!(c is Class))
			{
				// Convert to its class.
				c = getDefinitionByName(getQualifiedClassName(c));
			}

			// Is it cached? If so, return that.
			if(smFieldInfoCache.hasOwnProperty(c))
				return smFieldInfoCache[c];

			// Otherwise describe the type...
			var typeXml:XML = describeType(c);

			// Set up the dictionary
			var typeDict:Dictionary = new Dictionary();

			// Walk all the variables...
			for each (var variable:XML in typeXml.factory.variable)
				typeDict[variable.@name.toString()] = variable.@type.toString();

			// And all the accessors...
			for each (var accessor:XML in typeXml.factory.accessor)
			{
				// Ignore ones we can't write to.
				if(accessor.@access == "readonly")
					continue;

				typeDict[accessor.@name.toString()] = accessor.@type.toString();
			}

			// Don't forget to stuff it in the cache. :)
			smFieldInfoCache[c] = typeDict;
			return typeDict;
		}
	}

Hope this is useful for you. You’re free to use it however you like. Attribution would be appreciated.

Published (Twice)

Game Programming Gems 7, which has a chapter by me on clipmaps, is out. Very nice!

There’s errata – they forgot the sample app on the CD. You can download the missing app at this URL. Please drop me an e-mail if you run into any problems compiling or have any questions at all – I switched hard drives recently so it might not be the very latest code.

GameDev.Net also is running an article that I and Eric Hartman wrote titled Learning From The 3000 “Classics”: What can MAME teach us about game design?. Pretty cool! So far all the comments have been positive. Cut us down to size and tell us what we did wrong here.

Forest Pack – Finally out the door

Trees With Shadows

It took a few years, but I finally released the fixed function GL forest renderer I was working on for Torque. You can find out all about it at my .plan on GarageGames. Various businessy things got in the way of releasing it (and perhaps a bit of apathy on my own part :) … but it’s nice to have it out! Done with? We’ll see. There’s always a lot of question/answer and trouble-shooting to go with these things.

On a personal level, I like to think this heralds a new chapter of my life, where things Just Get Done a lot more often. We’ll see how that pans out.

SpaceNavigator Support for Sauerbraten

SpaceNavigator I recently got a 3dconnexion SpaceNavigator after trying a friend’s. Really neat device. 6 degrees of freedom in a slick little package, and only $50. And it’s actually fun to use – not frustrating and cheap-feeling like many other “weird” input devices I’ve tried. Its big brother is the same knob with some extra buttons – for only $400. Yikes. Yet I’m beginning to see why you might want to upgrade…

Anyway, I did a lame integration with Sauerbraten, an open-source 3d engine, under Win32 against the 3dconnexion SDK. The integration is pretty simple – even crude. This is another code post, skip if you’re not a techy! :)


First, grab this file (spaceNav.cpp) and add it to the Sauerbraten project. Then add a COM reference to the TDxInput that ships with the 3d connexion SDK (which you can download here). Finally, go to engine/main.cpp and add:

extern void spaceNav_start();
extern void spaceNav_poll();

void updateCameraFromSpaceNav(float tX, float tY, float tZ, float rX, float rY, float rZ, float rAngle)
{
   // Construct a matrix from our cur yaw/pitch/roll
   matrix m(vec(1,0,0), vec(0,1,0), vec(0,0,1));

   m.rotate(-camera1->yaw * RAD,   vec(0,0,1));

   m.X.mul(tX / 10.f);
   m.Y.mul(-tY / 10.f);
   m.Z.mul(tZ / 10.f);

   camera1->vel.add(m.X);
   camera1->vel.add(m.Y);
   camera1->vel.add(m.Z);
}

Right before the main function (around line 434).

Right after the line that reads:

    SDL_ShowCursor(0);

Add:

    spaceNav_start();

And around line 630, inside the for(;;), add:

               spaceNav_poll();

You can bind to the SpaceNavigator buttons by setting up keymaps like…

keymap -131 SPACENAV_LEFT

…and similar to a cfg file that gets executed when Sauerbraten starts up – I used keymap.cfg. Then you can bind to SPACENAV_LEFT and execute whatever commands you like. The binding uses button ids -100 through -132. 31 and 32 are the two buttons on the SpaceNavigator. On other 3dconnexion products there are more buttons and thus you can make use of the other binds.

And that’s it. spaceNav_start() loads up the SpaceNavigator COM object, Connect()s to the driver, and sets some global. spaceNav_poll() queries state and calls updateCameraFromSpaceNav() with the current state. It also dispatches to keypress() when a button is hit so the console can deal with binds.

Known issues:

  • Not networked properly. I’m just stuffing into the camera1 entity’s velocity field. It’s good enough to edit with, which is what I want.
  • Not based on frame time, so will give different behavior based on framerate.
  • No rotation. Since you have to aim with the mouse anyway this didn’t seem like a big need, but if someone made clicking independent of heading it could be a really useful feature… It does take the yaw into account when translating so you can fly around pretty well.
  • Not configurable. You can tweak the code in updateCameraFromSpaceNav to change how/how fast you move but it would be better to have that all be console-controllable.

Conclusion

I hope this is useful to someone! Feel free to do what you like with this code. Sauerbraten is under zlib, and 3d connexion SDK probably has some restrictions, too.

Using the Domain class in Tamarin for dynamic code loading

Using the Domain ActionScript class (as opposed to the C++ class of the same name) in Tamarin is actually really easy. This class isn’t available under Flash 9 for security reasons. It lets you load new ActionScript code at runtime, as our example will demonstrate. Dynamic code loading is pretty cool functionality – it could be used to implement a plugin system in an application, as the basis for a web server that executed files on demand, or as part of a programmer’s workbench written in AS.

Continue reading “Using the Domain class in Tamarin for dynamic code loading”