Dynamic assets creation by full class name from swf library is broken

I am using some external swf libraries at openfl project for html5 target. I have embedded them with preload=“true” and generate=“true” options. All assets were placed at bin directory in unpacked swflite .bin format.

Before last openfl big update I have easily instantiated assets by code like this:

var clip:MovieClip =
    cast Type.createInstance(Type.resolveClass("full.class.Name"), []);

Now I see that libraries turns to (unpacked) zip archives that are downloaded by browser, but assets classes became unavailable by name. My small investigation shows that adding direct call to constructor like this:

var preloadDummy = new full.class.Name();

brings followed creation of assets by classified class name to life. But this ruins my approach of dynamic assets creation.

It looks like some sort of ‘unused assets optimization’. If I don’t use them directly at my code they are also unavailable for creation by full path. Is it a new openfl option that should be configured?

I have removed generate=“true” option because it have no sense for my case. All children are discovered by getChildByName() or getChildAt(). But problem still persists.

Moreover, straight import of asset as class with full name allows to get reference by resolveClass() method, calling of constructor is not needed…

I have solved my problem. AS3 approach with

var asClass:Class = getDefinitionByName("full.class.Path");
var asClip:MovieClip = new asClass() as MovieClip;

that is implemented in Haxe as

var hxClass = Type.resolveClass("full.class.Name");
var hxClip:MovieClip = cast Type.createInstance(hxClass, []);

will work seamlessly on flash target only.

When using OpenFL at html5, all resources loaded by external libraries doesn’t appears as classes by default. You can access only to those of them that have been embedded directly to the application bundle in compile time.

To access dynamic libraries you should use:

var hxClip = Assets.getMovieClip("lib-name:full.class.Name");

or via loaded library assets container:

Assets.loadLibrary("lib-name").onComplete(function(lib:AssetsLibrary) {
    var hxClip = lib.getMovieClip("full.class.Name");
});

This works both at flash and html5 targets and probably at all other.

1 Like

Does it work if you use new full.class.Name() instead?

Assets.loadLibrary("lib-name").onComplete(function(lib:AssetsLibrary) {
    var hxClip = new full.class.Name();
});

It isn’t exactly my case. Classified asset name will work in case of including library to the project – openfl will generate substitution dummy classes and include them in bundle. But my point is to use constant strings with full class path to resolve them as dynamic library assets. In this case I can load and create any external asset that is not even described in project.

As I said before, approach with getMovieClip works fine, I just was misleaded by my common actionscript experience. Sorry for late answer.

Yeah perhaps there would be a way to make an ImportAll.hx file or something to make sure that all the generated class names are included in the final build so they can be referenced dynamically. The @:keep metadata helps prevent dead code elimination but only if the files have been referenced somewhere from the code to begin with. This may relate back to a broader question of how to handle SWF automatic processing back on the openfl process topic

In my opinion it doesn’t make sense – asynchronously loaded library that is demanding generation of substitution classes that must be included to the main bundle. So, every little new resource in external library will force rebuilding and deploying core application.

I think that using of getMovieClip by assets name at dynamic libraries is very straight and robust method.

1 Like

I’d want to confirm the problem which is appeared with openfl 9.0.2 + swf 3.x. My short investigation led me to the fact that generated class names since new openfl version are not included into /html5/haxe/[debug|release|final].hxml

I’d like to clarify – should generated classes to be included at external library bundle? I think that resolveClass-createInstance sequence will work properly on dynamic libraries only if assets wrappers will be generated and packed into library and then processed after loading.

I believe that classes are generated into /html5/haxe/_generated and included in the source path if you use the <library /> tag (and generating is always on by default) where processing outside of a project build it no longer generates class names

As for me, I use <library /> tag.
See the snippet:

<library path="assets/ui_skins/ui_common.swf" id="ui_skins.ui_common.bundle" generate="true" preload="true"/>
<library path="assets/ui_skins/ui_lobby.swf" id="ui_skins.ui_lobby.bundle" generate="true" preload="false"/>
<library path="assets/ui_skins/dialogs_common.swf" id="ui_skins.dialogs_common.bundle" generate="true" preload="false"/>
... and so on

And generated classes are not included into /html5/haxe/[debug|release|final].hxml since 9.0. In older versions of openfl each and very generated class is listed in build params files.

Try to look at bin/html5/haxe/_generated/<classified-paths-to-packages> directory for all generated assets wrapper classes. All of them are included then to .hxml build files as the same single line: -cp ...bin/html5/haxe/_generated. There’s no need to set path to the every class.

-cp is a classes path. It’s says to compilator where to find the classes in case they are directly used in you code. But it’s not enough to include the classes which can be found in this path into your build if they don’t mentioned directly in your code.

I do not presume to talk about why it was excluded in 9.0.x but the fact is that listing classes name by name each and every, as it was in prior versions, solves this problem.

Let me explain step by step:
html5 build consists of few steps. Last of them is a javascript generation from your code and generated classes using all the parameters which are directly passed through command line and your project.xml and indirectly by included libs. This step is automatically executed by haxelib openfl [build|test] html5 but you can run this one by yourself by executing haxe Export/html5/haxe/[debug|release|final].hxml.

So, just perform the build (let’s say a debug one) as you usually do it. And after add one class name you are missing into Export/html5/haxe/debug.hxml and then run haxe Export/html5/haxe/debug.hxml.

After that expressions like var swfObject = Type.createInstance(Type.resolveClass("myswf.asset.Circle"), []); will perform as expected.