Not sure if this is possible but I would like to reflect a swf or swc file selected by the user at runtime to find any classes that implement a certain interface. Can this be done or do you actually need a reference to the class you want to reflect using describeType();
Note - this would be done in actionscript.
Thanks,
You can inspect a swf for the classnames (Source) and then use describeType on them to find the ones which implement the interface(s). But this is probably slow. You can try to extend the getDefinitionNames code to get around the describeType and extract the needed info from the bytes...
Related
Firstly, my environment. My question is if it's possible to do so using Flash Professional and not Flex, FlashBuilder or the like (I don't have those environments at the moment).
Here is the thing: we have several .fla files with a Document Class set. The .as file with the class is shared with all those .fla files, so all them have this same class set as their Document Class. The point is that because of that the Class is compiled into each generated .swf files, and as result any changes made to the Class would require all the .fla files to be recompiled.
After some research I found out about RSLs. But I'd like to know if it's possible to have the class as RSL while also having it as Document Class for each file? It would ease stuff because in case a change needs to be done in the class we wouldn't need to recompile each file, or regenerate each .swf files.
Aditionally, if it's possible, how could I implement a RSL through Flash Professional? All the documentation I have found shows that through Flex and others.
Please let me know if I wasn't clear enough.
As already pointed out, you cannot use a RSL with a document class. However, you can put classes in an RSL and load those at runtime likely achieving what you desire.
Here is a very simple example:
1. Create the RSL assets:
Let's say you have a class that changes from time to time and you want to load it's functionality at runtime:
//TestyMcTestFace.as
package {
public class TestyMcTestFace {
public static function go():String{
return "I'm Testy McTestFace";
}
}
}
So, what you can do, is make a new AS3 project in FlashPro/AdobeAnimate CC. Link up your class file so your project finds it (in this case I just put my TestyMcTestFace.as in the same directory as the new .fla I created).
Put a reference in the timeline code to the class(es) you want included. Without this reference the class will not get exported in the resulting swc/swf.
So for this case, I have a new AS3 project with just one line on the first frame of the timeline:
TestyMcTestFace;
Now, go to your publish settings, and make it so only Flash (swf) and SWC are checked.
Publish this new project (you now have a swf/swc you can use as a RSL for other applications).
2. Setup your other applications to use the swf/swc as a RSL.
In your existing flash project, go to the 'Advanced Actionscript Settings' (click the wrench icon next "Actionscript 3.0" in the publish settings).
Click the library path tab, click the plus button, then click the "Browse To SWC File" button (currently it's an icon with the flash 'f' in it). Find your swc file from the previous step.
Now, with your new entry highlighted, click the info icon (linkage options). Change it from "Merged into code" to "RSL". Then add a path to the swf file (where it will be when this application runs).
Now, in your application, you can reference classes from the RSL. So if we do this:
trace(TestyMcTestFace.go());
You should get the output "I'm Testy McTestFace".
FlashPro will automatically load the RSL for you. Be aware though, that if you aren't letting flash preload your app automatically, it won't be available right away.
If you changed and re-exported the swc/swf from step one, those changes should be reflected when you run your existing swf again (no recompiling necessary).
Caveats:
Be careful with code in RSL's. It's easy to get clashing classes. As a best practice, only put code that is completely standalone/de-coupled into RSL's. Code that has lots of imports should be avoided. It's also best if you don't reference classes with same names in your compiled swf's that you are loading the RSL's.
Also keep in mind that RSL's can have sanbox/security restrictions if not coming from the same domain.
not possible, RSL is only meant for runtime sharing not for compile time sharing which you need to access the class.
First thing is, one class is not that much in term of size so there's not really a need to make it unique a sharable between swfs.
Now you affirm that all swfs would have to be recompiled if you make any change but that's not actually accurate since only one class definition can exist in one given runtime. The first swf running is by default the one loading the class definition, all the loaded swfs following would have their class definition discarded by default so no you don't have to recompile them in theory.
So to resume yes you have to recompile all swfs if you make major changes to the class but not for minor changes. But that situation is symptomatic to your app design which might not be the most efficient and logical.
I'm learning Flash Builder so I can add some extra functionality to my Flash Pro project.
Let's say I create a new Flash Pro file called foo.fla. I can then open Flash Builder and create a new project (and in the setup wizard I specify my foo.fla file as the target of the project). The wizard then creates a new project containing one file called foo.as which extends Sprite.
Now I would expect this initial file to be a root of some kind, and a great central place where I could create variables that all my MovieClips need to share. However, I can't figure out what exactly this file is being used for when my project is run. It doesn't seem to correspond to the stage or to the parent of any of my movie clips. It's constructor doesn't even seem to be called. What is this file used for? Is there a way I can use it to store 'global' stuff?
In order to "link" it to your FLA, you'll want to set it as the document class:
Once you do that, the constructor should be called at startup.
This class is exactly what you think it is: root*.
The class that you provide is the class that is associated with your .fla file.
It is called the document class or main class.
You are probably familiar with the concept of associating a library symbol with a class.
Say you create a MovieClip, add it to your library and define a class for it.
This is pretty much the same thing now, except you add the class to the document.
When the flash player executes your .swf file, it will instantiate your class and add it to the display list. This has a couple of implications:
The class must be some DisplayObject, because it is added to a DisplayObjectContainer.
This is why you it extends Sprite. (Sprite is a lightweight class that you should prefer over MovieClip if you do not need a timeline)
This is the strange part, remember * up there?
Yes, as your swf is created, the document class is instantiated and the resulting object is added to the display list, this means that root isn't actually the root of the display hierarchy. There's a parent container and that is stage.
Think of root as the root of your application, not necessarily the top most root of all roots.
And here's the (imo) strangest thing:
You can access the stage property within the constructor of the document class.
This is not true for any other class that extends DisplayObject (unless you force it by passing stage as a parameter to the constructor, which you shouldn't be doing)) and who's objects will end up on the display list, because you have to addChild them after they are created.
You might be tempted to use the stage property in such a constructor that is a constructor of a document class (because you can), but this leads to problems, because you can never tell if your document class is actually used as a document class.
If you want to instantiate your current document class in some other project, it will not have the special status of being the document class. It will be some regular class as all the others of that project.
In this case, stage will be null in the constructor. So don't access stage in the constructor, even if you can.
If you need stage, wait for it to be available. That is when the ADDED_TO_STAGE Event fires.
I am making a code completion system for a code editor, and i would like to show a tooltip for every parameter containing its reference data. I would like to emulate the code completion from Eclipse, so i was wondering if the API reference is available in code, or if i have to manually import it using the file system or something like that.
You could reflect the current class in question with flash.utils.describeType
This will return a xml with informations about methods, properties and so on.
This can be very heavy. If you use it all the time, try to use a caching system. The Flex framework has a class for it mx.utils.DescribeTypeCache
I'm making a game and I an in-game editor that is able to create entities on the fly (rather than hard coding them). I'm using a component-aggregation model, so my entities are nothing but a list of components.
What would be the best way to obtain or generate a list of components? I really don't want to have to manually add entries for all possible components in some giant registerAllComponents() method or something.
I was thinking maybe somehow with reflection via either the knowledge that all components inherit from the base Component class, or possibly via custom metatags but I haven't been able to find ways to get a list of all classes that derive from a class or all classes that have custom metatags.
What sort of options am I left with?
Thanks.
For a project I did once, we used a ruby script to generate an AS file containing references to all classes in a certain package (ensuring that they were included in the compilation). It's really easy considering that flash only allows classes with the same name as the file it's in, so no parsing of actual code needed.
It would be trivial to also make that add an entry to a dictionary (or something similar), for a factory class to use later.
I believe it's possible to have a program execute before compilation (at least in flashdevelop), so it would not add any manual work.
Edit: I added a basic FlashDevelop project to demonstrate. It requires that you have ruby installed.
http://dl.dropbox.com/u/340238/share/AutoGen.zip
Unfortunately, there is no proper way of getting all loaded classes or anything like that in the Flash API right now. So finding all sub-classes of Component is out, inspecting all classes for a specific meta tag is out as well.
A while ago I did run into a class/function that inspected the SWF's own bytecode upon loading to retrieve all contained classes. That's the only option for this kind of thing. See this link and the bottom of my post.
So, you're left with having to specify a list of component classes to pick from.
One overly complicated/unfeasible option that comes to mind is creating an external tool that searches your source folders, parses AS3 code and determines all sub-classes of Component, finally producing a list in some XML file. But that's not a task for the faint-hearted...
You can probably think of a bunch of manual solutions yourself, but one approach is to keep an accessible Array or Vector.<Class> somewhere, for example:
public static const COMPONENT_LIST:Vector.<Class> = Vector.<Class>( [
CollisionComponent,
VisualComponent,
StatsComponent,
...
...
] );
One advantage over keeping a list of String names, for example, would be that the component classes are guaranteed to be compiled into your SWF.
If the classes aren't explicitly referenced anywhere else in your code, they are not compiled. This might occur for a simple component which you only update() once per frame or so, and is only specified by a string in some XML file.
To clarify: You could use the code in the link above to get a list of the names of all loaded classes, then use getDefinitionByName(className) for each of them, followed by a call to describeType(classObj) to obtain an XML description of each type. Then, parsing that for the type's super-types, you could determine if it extends Component. I personally would just hardcode a list instead; it feels too messy to me to inspect all loaded classes on startup, but it's up to you.
How can I convert a string to a class without getDefinitionByName because that class is not linked to a library item and getDefinitionByName only works with classes that are linked to library or allready initialized! Is there a way? Or I have to initialize every class I want to use?! That would be soooo stupid of Adobe!
getDefinitionByName() will work with any class name, linked to library or not. Your problem is likely that since you're not mentioning the class name in the code, it's not in your swf at all. You will have to make sure the class is used at atleast one place in your code, if not it will not be compiled in.
This can be as simple as just putting them on a line in your Main-class:
public class Main {
public function Main(){
ClassYouWant;
AnotherClass;
codeThatDoesStuff();
}
}
The short answer:
If you want to avoid including class references (as suggested by #grapefrukt) you'll have to compile those classes in a library and reference that from your main application as an RSL (Runtime Shared Library)
The long answer:
There is no other way to create a Class by its name than to use getDefinitionByName().
However there are several ways to compile your code. By default, if you have a single application that doesn't include libraries, it will not compile classes that are not referenced in your code. You call this stupid, but there's a pretty good reason for that: it reduces the size of your swf and so the download time of your application.
If you use libraries there are three ways they can be referenced from your main application:
merged into code
runtime shared library (RSL)
external
The first option will take all (and only) the classes from the library that were referenced in the main application. This results in a smaller swf size.
The second option will compile the entire library into a separate swf, which is loaded by the main application. This results in a bigger file size, but the same swf can be used by several applications. And what's most important to you: all classes are in that swf, so they can be referenced by getDefinitionByName() without having to include the class in your main app.