Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

I've hit a very complicated brick wall

New Here ,
Oct 29, 2013 Oct 29, 2013

I'm sorry that I can't be more descriptive in my title, but I think I stuck my neck too deep and now I can't tell what is not working. I'm going to atempt to be as clear and concise as possible in my explanation, but sorry if I do something completely wrong or don't understand it fully.

Basically, what I am trying to do is load a bunch of .swf files that each extend the class "Plugin" from a folder called "plugins", and then execute specific code from them at specific times.To do this properly, I'm making a test plugin that is using a .swc library from the main program to extend "Plugin". Whenever I want to instantiate something that extends "Plugin", I have to give it a reference to my main program. However, here is where the problem occurs: when I try to load and then instantiate the plugin, I get an error saying that my main class is not my main class:

TypeError: Error #1034: Type Coercion failed: cannot convert me.bleachisback.cocmod::CoCMain@51b31f1 to me.bleachisback.cocmod.CoCMain.

I've been trying to fix this problem for the past week, and I just can't figure it out. I have a feeling it might have something to do with how I use the .swc file, but I can't tell if that is true/how to fix it because there is barely any documentation out there on it, especially in normal Flash and not Flash Builder.

Below is my source and how I attempted to get it to work:

https://mega.co.nz/#!Pdtn2SiB!ISszSDdGkaZyw6HB1ntRaVD2kckmnAxDeGsMTqS9SVw (A rar file containing my source)

There are 10 main files in the rar:

System/CoCMod.fla - The fla file for the main program

System/CoCMod.swc - The swc file for the main programe, and the library my plugin is using

System/CoCMod.swf - The swf for the main program

System/me/bleachisback/cocmod/CoCMain.as - The main class for the main program

System/me/bleachisback/cocmod/Plugin.as - The "abstract" class that every plugin should extend

System/plugins/TestMod.swf - The swf for the plugin, same as below. Does not do anything unless loaded by the main program.

Test Mod/TestMod.fla - The fla file for the plugin. Has actionscript on frame 1.

Test Mod/TestMod.swf - The swf for the plugin, same as above.

Test Mod/main.xml - Embedded into TestMod.swf, contains information about the mod.

Test Mod/plugin/bleachisback/testPlugin/TestMain - The main class for the plugin - extends Plugin.

This is how I export the .swc file (in CoCMod.fla):

help1.png

And this is how I reference it in TestMod.fla:

help2.png

What should happen is just a simple "blah" appears in the console, but for as few lines of code as I have, it doesn't want to work. Can someone tell me what I'm doing wrong?

TOPICS
ActionScript
2.6K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Oct 30, 2013 Oct 30, 2013

Enable debugging in your publishing option and post the Line of Code that causes the error

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 30, 2013 Oct 30, 2013

It happens in line 38 of CoCMain.as:

        private function pluginLoadingComplete(e:Event):void {

            var plugin:Object = new e.target.content.mainClass();

            var desc:XML = new XML(new e.target.content.description);

            trace(e.target.applicationDomain == ApplicationDomain.currentDomain); //outputs false

            plugin.initialise(this, desc.name[0], desc.description[0], desc.version[0], desc.author[0]); //error here

           

            plugin.onEnable();

        }

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Oct 30, 2013 Oct 30, 2013

I´m guessing you attach the event.complete listener to a Loader Object.

Make sure you instantiate the loaded swf properly:

from

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/LoaderInfo.html

For a Loader object that has not called the load() or loadBytes() method, or that has not sufficiently loaded, attempting to access many of the properties of the contentLoaderInfo property throws an error.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Oct 30, 2013 Oct 30, 2013

It's an applicationDomain or securityDomain issue. Essentially, you have multiple swfs loading in the same Class, but they're seen as different Classes because they're not in the same applicationDomain or securityDomain. That should give you enough background to go find the solution with a web search--I always have to look it up myself.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 30, 2013 Oct 30, 2013

I thought it was an applicationDomain issue, so I tried loading it into my current application domain:

var loader:Loader = new Loader();

var url:URLRequest = new URLRequest(file.nativePath);

loader.load(url, new LoaderContext(false, ApplicationDomain.currentDomain));

loader.contentLoaderInfo.addEventListener(Event.COMPLETE, pluginLoadingComplete);

 

                    private function pluginLoadingComplete(e:Event):void {

                              trace(e.target.applicationDomain == ApplicationDomain.currentDomain); //outputs false

                              plugin.initialise(this, desc.name[0], desc.description[0], desc.version[0], desc.author[0]); //error here

 

                              plugin.onEnable();

                    }

But when I do this, the trace outputs false, even though I esentially copied and pasted it from the adobe documentation.

Also, I am publishing the swc before I publish my plugin swf.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2013 Oct 30, 2013

there is no plugin swf. it's TestMod.swf that uses the swc.

anyway, that's a convoluted setup and it's causing you problems.

what are you trying to do?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 30, 2013 Oct 30, 2013

I'm basically just trying to load plugins for a game that I am working in. Every plugin is a .swf that is made by someone else and can modify the game using an API. Each plugin has a class that extends "Plugin" and implements certain methods from that class. Each plugin has a reference to my main class so that they can access certain methods from that class. If I were doing this in Java, it would be extremely easy, I just export my main program's project as a .jar and then add it as an external archive in my plugin's project.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2013 Oct 30, 2013

that's a problematic setup.  no plugin should have a dependency on the same class that loads the plugin

it's ok for your plugin's to reference some other class.  but that class should not then load the plugins.

ie, create one class that loads the plugins and another class that the plugins reference.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 30, 2013 Oct 30, 2013

I've now made two separate classes: one that loads the plugins and then one that the plugins reference, but it's still giving me the same error.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 31, 2013 Oct 31, 2013

what's your simplified setup?

hint:  if it's difficult to explain, it's not simple enough.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 31, 2013 Oct 31, 2013

I assume you mean the setup of my classes?

I now have a CoCMod class which is the main document class of my program: it makes an instance of CoCMain and then loads all of the plugins initialising them with the instance of CoCMain that I created:

    package me.bleachisback.cocmod {

        import flash.display.Loader;

        import flash.display.MovieClip;

        import flash.filesystem.File;

        import flash.events.Event;

        import flash.net.URLRequest;

        import flash.system.ApplicationDomain;

        import flash.system.LoaderContext;

        public class CoCMod extends MovieClip {           

            public function CoCMod() {

                loadPlugins(new CoCMain());

            }

            private var pluginFolder:File = new File(new File("app:/plugins/").nativePath);

            private function loadPlugins(main:CoCMain):void {

                //For first run, make sure plugins folder exists

                //Then load every swf inside it

                if(!pluginFolder.exists)pluginFolder.createDirectory();

                for each(var file:File in pluginFolder.getDirectoryListing()) {

                    if(file.extension == "swf") {

                        var loader:Loader = new Loader();

                        var url:URLRequest = new URLRequest(file.nativePath);

                        loader.load(url, new LoaderContext(false, ApplicationDomain.currentDomain));

                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, pluginLoadingComplete(main));

                    }

                }

            }

            private function pluginLoadingComplete(main:CoCMain):Function {

                return function (e:Event):void {

                    var plugin:Object = new e.target.content.mainClass();

                    var desc:XML = new XML(new e.target.content.description);

                    trace(e.target.applicationDomain == ApplicationDomain.currentDomain); //outputs false

                    plugin.initialise(main, desc.name[0], desc.description[0], desc.version[0], desc.author[0]);

                    plugin.onEnable();

                    plugin.onDisable();

                }           

            }

        }

    }

The CoCMain class is relatively unchanged, except for the parts I moved over to this class.

I'm mostly confused as to why, when I specifically tell it to load into ApplicationDomain.currentDomain, the later trace outputs as false.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Oct 31, 2013 Oct 31, 2013

I'd look for blog posts about ApplicationDomain and SecurityDomain issues. My experience with the Help is "this is what we think it's going to do when we're finished," and blog posts are "this is what I had to do to get it to really work."

Just a piece of advice: Anything that both your main swf and the plugin swfs need to reference should really be an Interface, not a Class. Swfs don't really "own" the definition of an Interface in the same way they do a Class, so I think that even if the base implementation of the Class really is the same Class under the hood, you may be able to get away with a bit more as far as whether it casts to be the same Class. Honestly, though, I'd allow the plugins freedom to implement the Interface however they want (or if they're getting an instance that implements an Interface, inject that by Interface, not implementation).

You may want to also consider that instead of using:

e.target.content.foo and e.target.content.bar, use

var plugin:IPluginDefinition = e.target.content as IPluginDefinition;

Then you can test to see if the cast worked and not get Null Pointer Exceptions if for some reason the properties you think you can access aren't there.

Once you create the Class based on what you're getting from the definition, test to see that it actually also implements the properties and methods you need (again by casting and checking for null).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Oct 31, 2013 Oct 31, 2013

I made Plugin implement the interface IPlugin, and TestMain extends Plugin.

This is my IPlugin interface:

package me.bleachisback.cocmod {

          public interface IPlugin {

                    function get author():String;

                    function get description():String;

                    function get enabled():Boolean;

                    function get name():String;

                    function onDisable():void;

                    function onEnable():void;

                    function onLoad():void;

                    function get version():String;

          }

}

I then tried this, and it gave me null:

var plugin:IPlugin = e.target.content.mainClass as IPlugin;

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Nov 01, 2013 Nov 01, 2013

Right, because mainClass is of type Class. The new instance you make from it may or may not implement IPlugin, which is why you check.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Nov 01, 2013 Nov 01, 2013

I just realised that directly implementing an interface won't work in this case. I don't want to force plugin makers to override every function in Plugin, only two of them. Normally you would accomplish this in Java by extending an Abstract class which implements the Interface, but AS3 doesn't have Abstract classes, so I made a makeshift one out of Plugin that throws an error on two of my functions. Extending this Plugin, which implements IPlugin, doesn't make Flash think that it implements IPlugin, sadly.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Nov 01, 2013 Nov 01, 2013
LATEST

That's ridiculous. I extend Classes that implement Interfaces all the time, and I guarantee you Flash does recognize that the implement the interfaces.

You may want to also consider handing IPlugins an instance of some other thing that implements those other methods you don't need to override that the IPlugins can manupulate in whatever way they need to and then they can have their "free and clear" implementations of the two methods.  This also gives them the option of not implementing those other methods by using the object you pass in if they don't want to.

A lot of times it seems like a really cool idea to provide a common Base Class until you find that one circumstance when you need something that implements the Interface that has a completely different Base Class and you're totally stuck because too many other things know about the Base Class.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 30, 2013 Oct 30, 2013

you have to publish your swc first.  then publish the swf that uses that swc.  then test.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines