AS3 Wrapper Accessing AS1 Variables - actionscript-3

Okay, so I have a Flash CS3 (+ AS3) program which is loading another flash program (called "pacman_main.swf" in this example). I've determined this is a rather old SWF, as it is made in Flash 5 and AS1 (yippee!).
I want the parent SWF (a.k.a. the wrapper) to be able to access the variables, specifically the score, of the child SWFG (a.k.a. "pacman_main.swf"). This is so I can submit the score to a 3rd party PHP/mySQL db blah blah.
function checkScore() {
// Get the score and submit it
}
submitScore.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(event:MouseEvent):void {
checkScore();
}
var loader:Loader = new Loader();
loader.load(new URLRequest("pacman_main.swf"));
addChildAt(loader, 0);
I know the variable name of the score, using the Debug > List Variables after building the wrapper. The score is a variable listed as "Variable _level0.instance5.instance6.score = 180" after getting 18 pac-dots in the game. How would I access that in my "checkScore" function?
Thanks!

The latest flash players have two virtual machines packaged in them, the AVM2 for as3, and AVM1 for as2/as1. Because of this, when you load an as1/as2 swf into flash it is of the type AVM1Movie, which will be run by the AVM1. Unfortunately, the AVM2 has little access to the objects running on AVM1, in fact, "no interoperability (such as calling methods or using parameters) between the AVM1Movie object and AVM2 objects is allowed".
Do you have access to the as1 source code? If you do I suggest firing off events every time the score changes, you can listen for these events in your wrapper class and not have to worry about accessing the score variable directly.
You can read more about AVM1Movie here

Related

AS3: How to instantiate the generic 'Document Class' (MainTimeline?) of a loaded SWF?

I have "Question.swf", which was created from "Question.fla". Note that Question.fla has no Document Class associated with it. (Note that this is legacy content, and there are over 14,000 variants of "Question.swf"; changing all these is not a viable option.)
Now I have my main Flash application, which loads in Question.swf at runtime. I know that Question.swf has a "Document Class" automatically created which represents the entire "stage" of the SWF (and that it's named "MainTimeline"). I want this application to be able to instantiate multiple instances of that Question.swf Document class... how can I?
I've been working with Flash/AS3 since 2006 (I'm very familiar with loading/using external content, the ApplicationDomain, etc.), but I find that I have no idea how to do this!
Things I've tried which haven't worked include querying the relevant ApplicationDomain with hasDefinition( "Question_fla.MainTimeline" ) - this returns false - as well as running getQualifiedClassName() on my loader.content object - this just returns MovieClip.
I'm not sure how to duplicate the main content of the Loader. However, a reasonable workaround might be to load the SWF bytes once and create multiple Loaders from those bytes:
Load your SWF bytes with a URLLoader:
var urlloader : URLLoader = new URLLoader();
urlloader.load(new URLRequest("your url here"));
Once it is loaded, use the bytes to instantiate new display objects:
var loader : Loader = new Loader();
loader.loadBytes(urlloader.bytes);
Use your loaded loader's loader.content display object on the display list (or the loader itself).

Modifying the domain memory of a loaded SWF to control behavior

I have several flash games that cannot be paused from within the games. I would like to write a wrapper swf that allows me to pause them. It is not feasible to recompile the games, so no functionality can be added to them.
What I would probably need to do is control when the loaded swf gets ENTER_FRAME events and redirect calls to flash.utils.getTimer to a function defined in the wrapper. Can this be done by modifying the domainMemory ByteArray of the loaded ApplicationDomain object?
domainMemory is definitely doesn't help you, it's just the API to access to the fast memory.
What you can try to do is to decompile the game swf and find the dispatcher of main EnterFrame event (and after loading game swf you have to find this dispatcher through the display list for example if it doesn't turned out to be the stage or root), that is used as the game tick dispatcher, than you will be able to intercept the default EnterFrame event for this dispatcher. For interception just add your own listener with the higher priority:
//pause the game
dispatcher.addEventListener(Event.ENTER_FRAME, onGameEnterFrame, false, 1);
//resume the game
dispatcher.removeEventListener(Event.ENTER_FRAME, onGameEnterFrame);
protected function onGameEnterFrame(event:Event):void
{
event.stopImmediatePropagation();
}

AS3: Handle BulkLoader.COMPLETE event on AS3 Preloader

I am trying to use BulkLoader (https://github.com/arthur-debert/BulkLoader) to preload all assets of my AS3/Flex application. Right now it is working and I am able to access the contents everywhere on my Main module (where my BulkLoader instance lives).
My problem: I need to handle the BulkLoader.COMPLETE event from my preloader (pre.as living next to Main.mxml on src/), to allow the user to exit the preloader and enter the application ONLY after BulkLoader.COMPLETE was fired.
Thanks!
Why not pass the reference to the BulkLoader instance?
Somethinglike this:
preloader.setLoader(_bulkLoaderInstance or name)
or
var preloader:Preloader = new Preloder(_bulkLoaderInstance or name)
BTW, the LoaderMax from Greensock is better (fewer bugs, more reliable events, nicer API).

referencing existing sound objects on the timeline via actionscript 3

In Actionscript 3 / Flash 10, is it possible to programmatically reference a sound object that exists on the timeline? I've found lots of examples for referencing DisplayObjects via the following sytax:
var m:MovieClip = stage.getChildByName("SomeMovieClipClass");
var n:MovieClip = stage.getChildByIndex(1);
But this doesn't seem to include sound objects. Similarly, it seems straightforward to instantiate and play a sound that exists in the Library via Actionscript:
var s:SoundClip1 = new SoundClip1(); // exported in first frame via properties
s.play();
For my purposes, though, I'd like to reference sound clips (ideally in a specific layer, although that seems to be a design-time element) that designers have adjusted and arranged on the timeline, so that I can inspect their waveforms via code, at runtime. Something like this:
// Imaginary Code
sc = timeline.getSoundClipByName("SoundClip1");
sc.extract(waveform,sc.length/1000 * bitrate);
Is this possible? Thanks!
As of this date, no it is not possible to access the soundChannel generated by a timeline sound. It's a feature I would love to see implemented.
I was going to try to test the feasibility of using computeSpectrum to get the waveform of a timeline sound but I'm having problems importing mp3s right now. In absence of firsthand proof of concept, I searched around and found this thread:
http://www.kirupa.com/forum/showthread.php?t=329632
Which links to this solution
http://www.mail-archive.com/flashcoders#chattyfig.figleaf.com/msg43157.html
But of course this doesn't allow you to disambiguate between different timeline sounds. I'm pretty sure you won't be able to do that at all.
I have not ever used Sound.extract(), but if the sounds exist in the fla library this indicates to me that you can simply give them a Class name and at runtime use extract() to gather the waveform for your own purposes, yes? Then whenever the appropriate timeline sound plays, you can tap into the waveform from the Sound object. Perhaps a timeline callback or event would suffice for this?

Loader.load and Loader.loadBytes differences

I'm loading as2 swf into AIR application. It works properly when loaded from file. But when loaded from bytes, it is broken in some way (it reacts to mouse, but some elements are inactive)
var bytes:ByteArray = ... //loaded from resources
var loader:Loader = new Loader();
var context:LoaderContext = new LoaderContext(false);
context.allowCodeImport = true; //this is neccessary
// Method 1 - blocks some scripts in loaded SWF
//context.applicationDomain = new ApplicationDomain();
// (application domain has no effect with as2 swf)
//context.securityDomain = SecurityDomain.currentDomain; //gives error 2114: securityDomain must be null
loader.loadBytes(bytes, context);
// Method 2 - loads properly
//loader.load(new URLRequest(file.url));
So why not just load it from file? My resources are protected with encryption and I can't dump them to disk - they must still be protected.
What tricks may exist to load from bytes properly?
There is similar question, but in my case as2 causes more problems.
AS2 and AS3 use different runtimes (bytecode is different) so you won't be able to properly execute any AS2 bytecode in the AS3 runtime. you are basically injecting AS2 code into your AS3 application, so it ain't gonna work :/
According the the documentation for LoaderContext you should only use the applicationDomain property only when loading ActionScript 3.0 SWFs. Try dropping that parameter (or setting it to null) and see what happens.
It seems that old SWF movies (AS1 and AS2, which require AVM1) loaded into an AIR app with load get put in their own domains, but those loaded with loadBytes share a domain. So if you have multiple AVM1 SWFs loaded with loadBytes their _global properties will clobber each other. This affects the Flash MX UI components (ca. 2002).
I can't be the only one trying to package ancient Flash files in AIR apps, so I figure this info may be useful to someone.