AS3-embedded SWF comes up as null - actionscript-3

So I have a SWF embedded in my AS3 project, but when I try to do anything with it, it says it's null.
The code looks like this:
[Embed(source = "../lib/Introduction.swf", mimeType = "application/octet-stream")]
public var introClass:Class;
(after a bunch of irrelevant stuff...)
var intro:MovieClip = new introClass() as MovieClip;
intro.play();
(The error message it gives me is a standard #1009 error.)
I've tried a bunch of stuff including using Loaders, not using MovieClip, etc, but at best, only the audio (not the video) of the SWF loads up, and at worst, the entire application crashes when the SWF tries to load. How do I get the SWF to be recognized?
(I'm using FlashDevelop if that helps.)

You can do this:
[Embed(source="asset.swf", symbol="symbol")]
private var symbolClass:Class;
var symbol:MovieClip = new symbolClass();
If you want to embed a symbol from an art SWF.
Instead if you want to import animations this is the solution:
[Embed(source="/loading.swf", mimeType="application/octet-stream")]
public var LoadingAnimation : Class;
// allows us to import SWFs to use as animations
var context : LoaderContext = new LoaderContext (false,
ApplicationDomain.currentDomain);
context.allowCodeImport = true;
var loader : Loader = new Loader ();
loader.loadBytes (new LoadingAnimation (), context);

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

Actionscript 3.0 import external linkage from swf works only once

When I load externall SWF and load class from it the externall classes are loaded only once
I use the following code to load externall class that I found on the website.
The problem is that applicationDomain works only once, which means after the swf file loaded once its not loading again. In other words i load externall class (linkage) which contains movieclip only for once and later it doesnt work. I think the problem is because i use applicationDomain. any way to solve the problem?
var sym:MovieClip;
var loader:Loader = new Loader();
var req=URLRequest = new URLRequest("foo.swf");
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fooLoadComplete);
loader.load(req):
function fooLoadComplete (event:Event):void
{
var classDefinition:Class=event.target.applicationDomain.getDefinition("Symbol1") as Class;
sym=new ClassDefinition();
addChildren();
}
function addChildren():void{
addChild(sym);
}

How to load image to swf which is loaded into other swf? (AIR, AS3)

I have an application in AIR, which is loading swf files and makes previews of them. When those swfs loads other content (eg. jpg) then i have an error, that url not found - i am convinced that is about jpg file. This problem shows only when i load swf by filereference using loadBytes(). When i load swf by Loader using load() - problem doesn`t exist. How can i fix this issue? Sorry for my english. I attach code fragment with loading swfs.
private static function loadFile(loadType:String, swfNum:Number = 0):void {
lc = new LoaderContext();
lc.allowCodeImport = true;
lc.allowLoadBytesCodeExecution = true;
currentSwfNum = swfNum;
var fRef:FileReference = DataBase.swfsList[currentSwfNum];
fRef.addEventListener(Event.COMPLETE, onFileReferenceLoad);
fRef.load();
}
private static function onFileReferenceLoad(e:Event):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, ifComplete);
loader.loadBytes(e.target.data, lc);
}
private static function ifComplete(e:Event):void {
var mc:MovieClip = LoaderInfo(e.target).content as MovieClip;
mc.addEventListener("SHOOT", SwfSingleCapture.captureSingleShoot);
}
DataBase.swfList - it is an array of FileReference objects, which are selected by FileReferenceList and browse().

URLRequest multiple SWF links not working properly

I'm trying to load 3 different tickers in 3 different containers.
When I delete this line:
loader2.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
loader3.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
and load them separately they works fine:
but when i load them together, just as the written in this document in adobe, all three tickers showing the same number:
package {
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.display.Loader;
public class importExternalSWF extends MovieClip {
private var loader:Loader = new Loader();
private var loader2:Loader = new Loader();
private var loader3:Loader = new Loader();
public function importExternalSWF() {
loader.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=mrj-4&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
loader2.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
loader3.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=grel&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
ticker1.addChild(loader);
ticker1.width=50;
ticker1.height=20;
ticker2.addChild(loader2);
ticker2.width=50;
ticker2.height=20;
ticker3.addChild(loader3);
ticker3.width=50;
ticker3.height=20;
}
}
}
I cant find solution anywhere
Thanks
edit
I rewrite my code to this, and its still the same result
public class importExternalSWF extends MovieClip {
public function importExternalSWF() {
var url = "http://tickers.playtech.com/jackpots/new_jackpot.swf";
var urlParams:Array = ["grel", "bl", "game=mrj-4"];
var tickers:Array = [ticker1, ticker2, ticker3];
var tickerHeight:Number = 50;
var tickerWidth:Number = 50;
loadUrls();
function loadUrls():void {
for(var i:uint = 0; i<urlParams.length; i++)
{
var urlLoader = new Loader();
var flashvars:URLVariables = new URLVariables();
flashvars["casino"] = "cityclub";
flashvars["info"] = "1";
flashvars["game"] = urlParams[i];
flashvars["currency"] = "eur";
flashvars["font_face"] = "arial";
flashvars["bold"] = "true";
flashvars["font_size"] = "10";
flashvars["bg_color"] = "0x000000";
flashvars["font_color"] = "ffffff";
var request:URLRequest = new URLRequest(url);
request.data = flashvars;
urlLoader.load(request);
tickers[i].width=tickerWidth;
tickers[i].height=tickerHeight;
tickers[i].addChild(urlLoader);
}
}
}
I suspect that the external SWF file sets some variables on the root level. Therefore each load will override the previous values and you'll end up with the same score in all "tickers".
Most likely this interference can be resolved by loading each SWF into its own ApplicationDomain. By default, SWFs are being loaded into the same ApplicationDomain and share their code.
So instead of doing this:
urlLoader.load(request);
You should do soemthing like this:
// create a new LoaderContext with a spearate ApplicationDomain
var context:LoaderContext = new LoaderContext(false, new ApplicationDomain());
// load the request and use the context with the separate ApplicationDomain
urlLoader.load(request, context);
I have bad news, i tried everything, but I can't load correctly the swf files. So, I have started to investigate this, and i found that, first, your SWF has AVM1Movie format (new_jackpot.swf), so, I conclude that this SWF was created with version 1 or 2 of ActionScript. If you see the reference of AVM1Movie Class (here the link), says the following:
There are several restrictions on an AVM1 SWF file loaded by an AVM2 SWF file:
The AVM1 SWF file that is loaded by an AVM2 SWF file cannot load another SWF file into this. That is, it cannot load another SWF file over itself. However, child Sprite objects, MovieClip objects, or other AVM1 SWF files loaded by this SWF file can load into this.
Then, i tried too, with a library that implements Threads in Flex, and found this (here this link async-threading):
The Actionscript Virtual Machine (AVM) in the Flash Player is severely limited by only having one thread...
I have created several projects using Loaders, SWFLoaders, ByteArrays, etc, all this in actionscript 3 in Flex SDK 3.2.
Maybe if you create this project in a previous version could work, or try to use same library that implements threads.
Anyway if I find something more, will edit this answer with another solution that's right.
Try adding a 1 after «laoder» at these places:
private var loader:Loader = new Loader();
loader.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=mrj-4&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24&currency=eur"));
There was no solution to this issue due to lack of compatibility from third part company that provides the tickers.

Embed bitmap in ActionScript3

How can I embed a bitmap in Actionscript 3 and get the BitmapData?
public class MyGame extends Sprite {
[EMBED(source="Assets/helicopter1.png")] private static var BMClass:Class;
public function MyGame() {
var BM:Bitmap = new BMClass();
var BMData:BitmapData = new BitmapData(BM.width, BM.height);
BMData.draw(BM)
}
}
I've tried everything. If I ever try to instantiate the embedded class (new BMClass();) I get this error:
TypeError: Error #1007: Instantiation attempted on a non-constructor..
If I use
[EMBED(source="Assets/helicopter1.png")] private static var BMClass:BitmapData;
or something similar the BitmapData is null.
Edit:
So I figured out that the embedded data is null, but I can't figure out why. What did I do wrong in the embedding?
Looks like you are embedding correctly if you don't get an error transcoding. You should be able to get the bitmapData directly from the bitmap:
[Embed(source="picture.jpg")]
private var Picture:Class;
// create a bitmap of the embedded
var pic:Bitmap = new Picture();
// add to display list
addChild(pic);
// if you need to get the bitmapData for something else
var bitmapData:BitmapData = pic.bitmapData;
You don't need to instantiate as BitmapData and draw - you can simply:
[Embed(source="Assets/helicopter1.png")]
private var AssetClass:Class;
var bitmap:Bitmap = new AssetClass();
In some editors (at least my version of Intellij) the Embed tag is case sensitive. I got the exact same error you have when using [EMBED] but it worked great when I switched to [Embed]