Flash Remoting with AS3

Posted by Luke | Actionscript 3.0, Flash, Remoting | Saturday 26 July 2008 6:23 pm

While staying on the topic of Flash Remoting. Using it with ActionScript 3 isn’t all that different. The basic building blocks are quite similar with those used in ActionScript 2. The main difference is that in ActionScript 3 there is a dedicated flash.net.Responder object that needs to be instantiated to receive the result from a AMF call. Knowing that, a bare bone ActionScript 3 Flash Remoting call would than look something like this:

import flash.events.NetStatusEvent;
import flash.net.NetConnection;
import flash.net.Responder;

function onConnectionStatus( event : NetStatusEvent ) : void
	{
		trace("onConnectionStatus " + event.info.level + ", " + event.info.code );
	}

function onResponderResult( result : String ) : void
	{
		trace("onResponderResult " + result);
	}

function onResponderStatus( event : NetStatusEvent ) : void
	{
		trace("onResponderStatus " + event.info.level + ", " + event.info.code );
	}

var responder : Responder;
responder = new Responder( onResponderResult, onResponderStatus );

var nc : NetConnection;
nc = new NetConnection();
nc.addEventListener( NetStatusEvent.NET_STATUS, onConnectionStatus);
nc.connect(http://localhost/remoting/gateway.php");
nc.call("HelloWorld.say", responder, "hello");

Flash Remoting

Posted by Luke | Actionscript, Actionscript 2.0, Flash, PHP, Programming, Remoting | Monday 21 July 2008 9:57 pm

I never really had the chance to use Flash Remoting on a commercial project and it has been years since I played around with it. It must have been 2003/2004 or so that I first tried using it. At the time I tried it with ColdFusion, which worked pretty OK, and with Java (JRun to be precise). I was pretty impressed with the level of abstraction that Flash Remoting provided. Not just from the ActionScript point of view but also from the server point of view. No more manual parsing of data structures. Great! Thinking about it, I can’t really understand why it isn’t more widely used. It seems that it is only used on the more corporate websites, or very specialized stuff to say the least, and you don’t see it much used with the ‘typical’ Flash stuff or hear much about it in the general Flash community. Maybe that’s because Flash Remoting is quite a techy thing to get your head around and that it’s out of the league of your typical Flashers. Maybe BlazeDS is going to make a change to this, but somehow I doubt that.

Anyways, I was playing with AMFPHP over the weekend. It was a fair bit of work to get it all up and running. The documentation on the site isn’t what you would call ‘good’ but after a bit of puzzling I was able to figure it out and was able to make a request through Remoting and get a result value back. Awesome. The next thing I wanted to do was to use a bare bone NetConnection instance to connect to AMFPHP. After all, in Flash it’s the only intrinsic object available to connect to an AMF server and somehow the Remoting classes provided by Adobe seem to be so incredibly complicated and not intuitive to use at all. Luckily they changed this for ActionScript 3, but I wanted to figure this out for ActionScript 2.

The first mistake I made was to focus on the connect method of the NetConnection object. I figured out that the NetConnection has an undocumented onStatus event handler. I figured also out that when I made a connection the onStatus wasn’t triggered when I used http, only when I used rtmp. Hmmm, that was kinda odd. I played around with it for a while and decided to move on to the next thing, which was calling a remote method. I created a simple HelloWorld method on the AMFPHP server and called it using the Remoting classes provided by Adobe. That worked fine. So I set up the following code using a bare bone NetConnection:

var responder : Object;
responder = new Object();
responder.onResult = function( result : String ) : Void
   {
      trace("responder:onResult " + result);
   };
responder.onStatus = function( info : Object ) : Void
   {
      trace("responder:onStatus " + info.code + ", " + info.level);
   };

var nc : NetConnection;
nc = new NetConnection();
nc.onStatus = function( info : Object ) : Void
   {
      trace("nc:onStatus " + info.code + ", " + info.level);
   };
nc.connect("http://localhost/remoting/gateway.php");
nc.call("HelloWorld.say", responder);

Now, this is where I went on my next wild goose chase. I spent the next couple of hours trying to figure out why this didn’t work. Going back and forth between the test case I did with the Adobe classes and this example. I just couldn’t figure out why the NetConnection example wasn’t working. I made dozens of small changes, trying to isolate the problem. But alas. Nothing. Until, at one point, I decided to change this line:

nc.call("HelloWorld.say", responder);

To this:

nc.call("HelloWorld.say", responder, "hello");

Bang! It worked. Apparently, just because the signature didn’t match previously with any remote function on the server, the function simply wasn’t called… Maybe it’s my naivety, but I was expecting the parameter to be just passed as an empty string, or null, if not specified. I’m currently not sure where the problem lies with that, but I guess it’s with AMFPHP. I think AMFPHP is to strict on signature testing and should be a bit more relaxed when it comes to that. I played around with it a bit more and decided to call it a day.

Today, while doing the dishes, or better, cleaning out the dishwasher the http/rtmp problem just solved itself. Of course the behavior was different! When connecting to an AMF server through http, the connection is stateless and can’t be maintained. In fact, calling the connect method on the NetConnection object doesn’t actually do that much and behaves completely different than with rtmp. It does call the server, but it seems to only check if the location, or gateway you want to call, exists. Only over an rtmp connection the Flash Player can maintain an open connection with the server. Duh!

I will definitely be using more Flash Remoting in the future and will most likely try to push it for more commercial projects from now on. It’s a great technology, saves heaps of bandwidth and no more XML/JSON parsing!

Papervision3D rocks!

Posted by Luke | Actionscript 3.0, Flash, Papervision3D, Programming | Friday 16 November 2007 4:10 pm

Some months ago I was working on a conversion of an OpenGL Quake 1 model viewer I did years ago, it must have been 2000 or 2001 or something, to Papervision3D. The overall conversion went pretty smooth because all of the difficult stuff I already did when I was building the OpenGL version and the code was documented pretty well.

When doing the conversion there was one problem I had at the time and that was the texturing. I just couldn’t get the texturing to work correctly with Papervision3D. I read the Papervision3D documentation and searched the web from top to bottom and inside out to find an example of the correct way to apply a texture to a Face3D object. At one point I just gave up and the code started to collect dust on my hard drive.

Until today. For a commercial project I’m currently working on I’m going to use Papervision3D and since I could spend paid hours on figuring out what the problem was with this code it seemed the right opportunity to dust off the Quake 1 model viewer code and fix this issue once and for all. And behold, after a day of debugging and bending my brain over and backwards, I seemed to have fixed the problem.

Basically, and I will not bore you with the details, I figured out that the Papervision3D documentation wasn’t that clear since the Face3D class constructor didn’t expected an array of {x,y} objects for the UV coordinates but an array of NumberUV objects. Second, the UV coordinates had to be given in percentage, something I lucky remembered from my OpenGL programming days.

So, there you go. You can checkout the Quake 1 model viewer here (might take a couple of seconds to load) and please let me know what you think…

ActionScript trace

Posted by Luke | Actionscript, Flash, Programming | Friday 12 October 2007 3:16 pm

On my workstation, where I do Flash development, I always run a debugger version of the Flash Player. This is because I do not use the Flash IDE nor Flex Builder for development and I still want to see trace output.

A side effect of having the debugger version of the Flash Player installed is that I also see trace output from any other website with Flash content that I visit when I have the trace console open. Sometimes this is quite funny because some programmers think its really cool to have swear words in their trace output. Most of the time however, I can’t seem to understand or make sense of their output or why its still there in the first place. Maybe I’m just anal, but I always seem to remove any trace statement I put in my code because that trace statement is there for debugging purposes only, not for general logging. Other then that, over the years I’ve adopted a specific syntax when it comes to trace output.

The main problem with trace statements is to be able to find them back in the code where they occurred. If you have a whole bunch of trace statements and your application is quite biggish, then five minutes after putting in the trace you’re probably still be able to remember where you placed it in your code. The next day however, you see a trace statement pop up but you have no clue where in your code the trace statement occurred. “Ah, then you just use the find function on your text editor”, you’d say. Valid point and sometimes this works. But what if your output is composed in the style of:

trace("varname=" + varname + ", somecounter=" + i );

Happy finding!

When I put trace statements in my code I usually include the class and method name in the trace statement. This way I can always quickly locate where in my code the trace statement occurred. My trace statements therefore look something like this:

trace("classname:methodname varname=" + varname + ", somecounter=" + i );

Now, whenever I see a trace statement popping up I know exactly where in my code this occurred and I can locate it in an instance.