Copy link to clipboard
Copied
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):
And this is how I reference it in TestMod.fla:
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?
Copy link to clipboard
Copied
Enable debugging in your publishing option and post the Line of Code that causes the error
Copy link to clipboard
Copied
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();
}
Copy link to clipboard
Copied
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()
orloadBytes()
method, or that has not sufficiently loaded, attempting to access many of the properties of thecontentLoaderInfo
property throws an error.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
what's your simplified setup?
hint: if it's difficult to explain, it's not simple enough.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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).
Copy link to clipboard
Copied
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;
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
you have to publish your swc first. then publish the swf that uses that swc. then test.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now