AS3 Does Loader ProgressEvent.PROGRESS event guarantee that server received the request? - actionscript-3

I am new to Action Script and I've faced the following code:
var lc: LoaderContext = new LoaderContext();
lc.checkPolicyFile = false;
lc.allowCodeImport = false;
var ldr: Loader = new Loader();
ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loadHandler);
ldr.load(new URLRequest(url), lc);
Does ProgressEvent.PROGRESS event guarantee that server received the request? Can I asume in loadHandler that request has been received or should I use
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler);
instead?

As it's indicated in its definition :
A ProgressEvent object is dispatched when a load operation has begun or a socket has received data ...
So yes, when the ProgressEvent.PROGRESS event is fired, you are sure that your server has received the request.
And about Event.COMPLETE event, it's fired when the load operation has been completed so you can use your loaded content.
Hope that can help.

Related

AS3 Air Desktop - Dispatch Custom Event from SWF in ApplicationStorageDirectory

I have a series of Air Desktop games that I created. Before the game can be played, the user must first log in. In order to streamline things, I created the login system in a separate project and saved it as a swf file called, "dashboard.swf". When the game is opened, it loads dashboard.swf and displays the login screen. In addition to the login functionality, dashboard.swf also handles a bunch of other stuff like common settings amongst the games.
I didn't want to recompile each game every time I made a change to the dashboard.swf. So, I have it download from a server. I was originally downloading, saving, and loading dashboard.swf in the ApplicationDirectory and it worked fine on Macs. After testing on Window 10 and doing some research, I found that ApplicationDirectory for non-OSX machines is read-only.
So, I changed the location of the dashboard.swf to the ApplicationStorageDirectory. When I run it on my Mac, the swf loads just fine, but the first custom event that gets dispatched throws and error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.thisapp.event::CustomEvent#12786a9fed31 to com.thisapp.event.CustomEvent
Both CustomEvent.as files are identical. It fires just fine when dashboard.swf is saved to and loaded from the ApplicationDirectory on the Mac. Once I move it to ApplicationStorageDirectory, I get this error. So I know it's not an issue with the actual custom dispatcher. Bubbling is true and so in Cancellable.
What would be causing the Type Coercion failure in this situation?
Here's my custom dispatcher:
public class CustomEvent extends Event {
public static const GOT_RESULT: String = "gotResult";
public var result: Object;
public function CustomEvent(type: String, result: Object = null, bubbles: Boolean = false, cancelable: Boolean = false) {
// constructor code
super(type, bubbles, cancelable);
this.result = result;
}
public override function clone(): Event {
return new CustomEvent(type, result, bubbles, cancelable);
}
}
From my dashboard.swf:
dispatchEvent(new CustomEvent(CustomEvent.GOT_RESULT, null,true,true));
In my Main class for the desktop app:
var dashboardURL:String = File.applicationStorageDirectory.url +"dashboard.swf";
var myContext:LoaderContext = new LoaderContext();
myContext.applicationDomain = ApplicationDomain.currentDomain;
var urlReq:URLRequest = new URLRequest(dashboardURL);
var ldr:Loader = new Loader();
ldr.load(urlReq, myContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}
ANSWER
See #BadFeelingAboutThis's answer below to understand why the 1034 error is happening. Here's how I fixed it:
First - Download the swf from the server (I'm using the GreenSock's LoaderMax):
private function dowloadDashboard(){
var url:String = "https://path/to/your/swf/on/the/server.swf";
var queue:LoaderMax = new LoaderMax({name:"mainQueue",onComplete:completeHandler});
//Note: the format is set to "binary"
queue.append( new DataLoader(url, {name:"mySwf",format:"binary", estimatedBytes:3000}) );
queue.load();
function completeHandler(event:LoaderEvent):void {
//Note: "mySwf" is the name I gave to the DataLoader above.
var b:ByteArray = LoaderMax.getContent("mySwf");
//loadDashboard() is the next function and I'm passing the ByteArray to it.
loadDashboard(b);
}
}
Next - Load the swf with the proper context using the ByteArray:
private function loadDashboard(b:ByteArray) {
var myContext:LoaderContext = new LoaderContext();
myContext.allowLoadBytesCodeExecution = true;
myContext.allowCodeImport = true;
myContext.applicationDomain = ApplicationDomain.currentDomain;
var ldr:Loader = new Loader();
ldr.loadBytes(b,myContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadDone);
}
Last - Add your swf to the stage:
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
}
I hope that helps somebody! Remember, in my situation, I have a Desktop Air app that is downloading and loading a swf file that lives on a server.
This error typically means that you have the same Class coming into your root application from different sources.
In your case CustomEvent class must exist in both the host SWF file as well as your loaded in SWF file.
Because your loaded SWF is not in the same application domain as the host SWF, flash/AIR will not see overlapping classes as the same class. So you loaded in SWF CustomEvent is now seen as com.thisapp.event::CustomEvent#12786a9fed31 which (though exactly the same) is seen as a totally different class than com.thisapp.event:CustomEvent. Since your code references the latter, anytime a CustomEvent from the host tries to get stuffed in an object reference typed :CustomEvent it will throw a coercion error because they aren't actually same class.
Usually, the remedy for this problem is to specify the context for the loaded SWF so it integrates the loaded Classes into it's own domain. This should overwrite the host CustomEvent with the loaded SWF's CustomEvent
var ldr:Loader = new Loader();
//The second parameter for load takes a LoaderContext
ldr.load(new URLRequest(File.applicationStorageDirectory.url +"dashboard.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);
function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}
Read more about the loader context here and here

Image path issue on as3

I'm trying to create a screensaver for one our of our display we have at work. Images will be uploaded to an external server, from that server I will have pull the images and xml file. so my flash app and my content will be in two different places. I'm getting an error "SecurityError: Error #2000: No active security context". how do I override error and get the images to my stage.
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML;
var imageList:XMLList;
var imageLoader:Loader = new Loader();
var timer:Timer =new Timer(5000);
var imageIndex:uint = 0;
var child:DisplayObject;
var path:String="http://bgxserv03.mgmmirage.org/interactivemedia/mmhub01/test/mb/edit_bay/hr/infoscreen/servamb/";
xmlLoader.load(new URLRequest(path +"output.xml"));
xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded);
timer.addEventListener(TimerEvent.TIMER, tick);
function xmlLoaded(e:Event) {
xmlData = new XML ( e.target.data);
imageList = xmlData.image.name;
timer.start();
loadImage(imageList[0]);
}
function imageLoaded(e:Event){
if (child){
myImageHolder.removeChild(child);
}
child = myImageHolder.addChild(imageLoader);
Tweener.addTween(child, {alpha:0, time:1, delay:4});
Tweener.addTween(child, {alpha:1, time:1, delay:5});
}
function loadImage(path:String){
imageLoader.load(new URLRequest( path +"photos/"));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoaded);
}
Any help would be deeply appreciate. Thank you.
You need to put the "Crossdomain.XML" on the server's root directory. This will allow your flash file to access the data (image in your case) from that server. You can get a sample xml from the following URL, customize it for your server:
Sample CrossDomain.XML
What you are missing is probably a crossdomain.xml policy file at the domain of your image/xml files.
Use this link to create a crossdomain.xml file and add it to the root of your image/xml domain like so : "http://bgxserv03.mgmmirage.org/crossdomain.xml"
The URLLoader load() function automatically checks for the crossdomain.xml. Loader class requires you specify that you are interested in checking for a policy file in a LoaderContext object sent to the load() function.
In your code, it looks like the error should be coming from the URLLoader xml file request, since it doesn't look like you are trying to access the bitmap data of your images in any way, which is normally what would throw a security error for image files. If it is a problem with the image loading part, then complete the following instructions and you should be set to go:
In your loadImage function, add a LoaderContext parameter to your load method call:
function loadImage(path:String){
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.checkPolicyFile = true;
imageLoader.load(new URLRequest( path +"photos/"), loaderContext);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoaded);
}
Check out the spec for more info on how to use the Loader class.
If you run into any trouble, this thread may be helpful.

AS3 Using variable from one function in another - not working

Can't seem to get the value of myXML outside the function, despite being declared outside. What am I missing here? The data loads and traces correctly inside the function.
var myLoader:URLLoader = new URLLoader();
myLoader.load(new URLRequest("flightPlannerBoard.xml"));
var myXML:XML;
// Check XML data fully loaded
myLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
myXML = new XML(e.target.data);
//trace(myXML);
}
trace(myXML);
Because ActionScript is asyncronous as others have said, you cannot control the flow of execution by code placement. What you must do is control execution through the events, and so whatever actions you want to perform with the loaded XML should be in the processXML function or in another function that is called from processXML:
var myXML:XML;
function processXML(e:Event):void {
myXML = new XML(e.target.data);
trace(myXML); //this trace will work
doNextAction();
}
function doNextAction():void {
trace(myXML); //this trace will also work
}
You should declare your XML variable outside your function in order to be able to use it in another function
private var myXML:XML;
Actionscript is an asynchronous language, meaning the trace "outside" the callback will be called before the file has loaded. The execution order in your case is:
create instance of URLLoader
start loading file
add event listener to listen to the complete event
trace out myXML
(or at some point later) finish loading xml file

How i know if a Sound object is playing?

In AS3 i've created a code that load a sound and execute it in streaming.
var mySound:Sound = new Sound();
var myChannel:SoundChannel = new SoundChannel();
mySound.load(new URLRequest("surrender.mp3"));
myChannel = mySound.play();
Considering that the mp3 file is placed on the server, i need to trace if it's already begun or still receiving initial data from the server. Once it's effectively started i've to call a function that initialize some things.
the problem is, how i can trace if a sound or channel object "is playing" ?
You can check this by listening for the different Events the Sound object dispatches as well as its properties like Sound.isBuffering
Refer to the Sound manpage
you could wait for the mp3 to be loaded completely
var myChannel:SoundChannel;
var soundFactory:Sound = new Sound();
soundFactory.addEventListener(Event.COMPLETE, completeHandler);
soundFactory.load(request);
// ...
private function completeHandler(event:Event):void {
trace("completeHandler: " + event);
myChannel = soundFactory.play();
}
or you can use a Timer and check the myChannel.position periodically - if it doesn't change the sound stopped playing...

AS3 URLLoader throwing URL not found, but is connecting successfully

Okay getting some weirdness. I have a simple URLLoader in AS3 that loads an external XML document. It's loading just fine, I get a correct 302 Not Modified response in Charles, however flash tells me:
"URL Not Found"
Here is the relevant code:
//=============================================================================================
public function openXML(name:String):void { //decides what XML data feed and opens it
//=============================================================================================
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML = new XML();
//add event listener to URLLoader to call closeXML upon completion
xmlLoader.addEventListener(Event.COMPLETE, closeXML);
xmlLoader.load(new URLRequest("http://www.gessnerengineering.com/projects"));
//=========================================================
function closeXML(e:Event):void {
//=========================================================
xmlData = new XML(xmlLoader.data);
xmlLoader.removeEventListener(Event.COMPLETE, closeXML);
drawPage(name, xmlData);
}
}
The problem line according to the debugger is at:
xmlLoader.load(new URLRequest("http://www.gessnerengineering.com/projects"));
I've verified that I can browse to the URL via my browser and cURL, and Charles says that my SWF can and IS successfully accessing it too. However I still get this URL Not Found error. According to the Flash Actionscript 3 documentation, this is the absolute correct way to use URLLoader to load external data including XML.
Updated code with pastie.
I'm finding your code's structure a little odd - why do you have functions inside of a function?
I rewrote your code like this and it works perfectly fine (i just ran it on the timeline in flash cause i'm too lazy to set up a new project):
var xmlLoader:URLLoader = new URLLoader();
var xmlData:XML = new XML();
var request:URLRequest = new URLRequest("http://www.gessnerengineering.com/projects");
request.method = URLRequestMethod.GET;
//=============================================================================================
function openXML(name:String):void { //decides what XML data feed and opens it
//=============================================================================================
//add event listener to URLLoader to call closeXML upon completion
xmlLoader.addEventListener(Event.COMPLETE, closeXML);
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
xmlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
xmlLoader.load(new URLRequest("http://www.gessnerengineering.com/projects"));
}
function onIOError(e:IOErrorEvent):void {
trace("Error loading URL.");
}
function securityError(e:SecurityErrorEvent):void {
trace("security error");
}
function closeXML(e:Event):void {
trace('xmlLoader.data ' + xmlLoader.data);
xmlData = new XML(xmlLoader.data);
xmlLoader.removeEventListener(Event.COMPLETE, closeXML);
}
openXML('ljkl');
Without knowing all of the details, and assuming you implemented the RESTful services properly, your URLRequest might be calling the service with the wrong method (POST, rather than GET).
Check out this tutorial about calling RESTful services from Actionscript 3:
Consuming REST web Services in ActionScript 3
It has some good info on setting the request type and dealing with some of the other issues that can pop up (like setting the return data type, etc.).