AS3 package issue - actionscript-3

Really want to refactor and re-architect my project, it's become basically an 11k line monobloc that desperately needs to be split into multiple classes (and class files) inside a single package.
Yes I know I should have figured all this out when I started, but this is play not work and I was brand new to AS3 when I started. And I've kept building and building and it all works, it's just become very hard to manage.
My immediate goal is to define a package and then start breaking out function groups from the current main class into subclasses that extend the base. But I'm having a problem with the first step - defining the package.
I'm getting:
C:\Users\Vossie\Documents\Fex Line of Battle Project\trunk\line_of_battle\LOB_Core.as, Line 1, Column 1 5001: The name of package 'line_of_battle' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file. C:\Users\Vossie\Documents\Fex Line of Battle Project\trunk\line_of_battle\LOB_Core.as
So I've checked:
package line_of_battle {
public class LOB_Core extends flash.display.MovieClip {
Filename is LOB_Core.as.
Path:
I explicitly added it to the class search path:
So:
Name of package agrees with name of folder (I actually pasted it from folder to .as file)
Package file is within that folder.
Class search path includes that folder
Shouldn't matter for this but filename and public class name match
I've searched stack overflow and one similar case involved a text case mismatch that I don't see here. One other related question the guy's question turned into just how to make classes and name the files correctly.
According to the documentation I read, this should work fine. Can someone tell me what I am missing?
Edit - This is the code that's triggering the error, LOB_Core.as:1102 -
var test:LOB_Scenario_Data = new LOB_Scenario_Data();
And the class that is calling:
package line_of_battle {
import line_of_battle.LOB_Core.*;
public class LOB_Scenario_Data extends LOB_Core {
public function LOB_Scenario_Data() {
// constructor code
trace("BIG MONKEYS");
}
}
}

Related

Checkstyle check for duplicate classes

The project I am on is having horrible problems with class collisions in the classpath and developers reusing class names. For example, we have 16, yes 16 interfaces called Constants in this bloody thing and its causing all kinds of problems.
I want to implement a checkstyle check that will search for various forms of class duplication. here's the class
import java.io.File;
import java.util.List;
import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
import com.wps.codetools.common.classpath.ClassScanner;
import com.wps.codetools.common.classpath.criteria.ClassNameCriteria;
import com.wps.codetools.common.classpath.locator.ClasspathClassLocator;
/**
* This codestyle check is designed to scan the project for duplicate class names
* This is being done because it is common that if a class name matches a class
* name that is in a library, the two can be confused. Its in my best practice that
* the class names should be unique to the project.
*
*
*/
public class DuplicateClassNames extends AbstractFileSetCheck {
private int fileCount;
#Override
public void beginProcessing(String aCharset) {
super.beginProcessing(aCharset);
// reset the file count
this.fileCount = 0;
}
#Override
public void processFiltered(File file, List<String> aLines) {
this.fileCount++;
System.out.println(file.getPath());
ClassScanner scanner = new ClassScanner();
scanner.addClassCriteria(new ClassNameCriteria(file.getPath()));
scanner.addClassLocater(new ClasspathClassLocator());
List<Class<?>> classes = scanner.findClasses();
if (classes.size() > 0) {
// log the message
log(0, "wps.duplicate.class.name", classes.size(), classes);
// you can call log() multiple times to flag multiple
// errors in the same file
}
}
}
Ok, so the ClassScanner opens up the classpath of the current JVM and searches it with various criteria. This particular one is a class name. It can go into the source folders, and most importantly it can go into the libraries contained in the classpath and search the *.class files within the jar using ASM. If it finds copies based on the criteria objects that are presented, it returns an array of the files. This still needs some massaging before mainstream but im on a time budget here so quick and dirty it goes.
My problem is understanding the input parameters for the check itself. I copied from the example, but it looks like CheckStyles is giving me a basic IO file object for the source file itself, and the contents of the source file in a string array.
Do I have to run this array thru another processor before I can get the fully qualified class name?
This is more difficult to do right than one might think, mostly because Java supports all kinds of nesting, like static classes defined within an interface, anonymous inner classes, and so on. Also, you are extending AbstractFileSetCheck, which is not a TreeWalker module, so you don't get an AST. If you want an AST, extend Check instead.
Since "quick and dirty" is an option for you, you could simply deduce the class name from the file name: Determine the canonical path, remove common directories from the beginning of the String, replace slashes with dots, cut off the file extension, and you are more or less there. (Without supporting inner classes etc. of course.)
A better solution might be to extend Check and register for PACKAGE_DEF, CLASS_DEF, ANNOTATION_DEF, ENUM_DEF, and INTERFACE_DEF. In your check, you maintain a stack of IDENTs found at these locations, which gives you all fully qualified class names in the .java file. (If you want anonymous classes, too, also register for LITERAL_NEW. I believe in your case you don't want those.)
The latter solution would not work well in an IDE like Eclipse, because the Check lifecycle is too short, and you would keep losing the list of fully qualified class names. It will work in a continuous integration system or other form of external run, though. It is important that the static reference to the class list that you're maintaining is retained between check runs. If you need Eclipse support, you would have to add something to your Eclipse plugin that can keep the list (and also the list from previous full builds, persisted somewhere).

Importing a Package in Adobe Flash CS3 - Pointless Messages from "Access of Undefined Property" to none at all

I inherited a Flash CS3 legacy app and I am trying to refactor it a little. Eventually everything is supposed to be moved over to JS, but for now I would like to start working with what I have rather than attempting a complete rewrite. First I would like to install a little regression test.
I am trying to setup the test in it's own package in order to reducing the seams it has with the original app. The app uses a lot of global variables and I wish not to interfere with those.
I can't get my regression test to work, since I can't figure out how to import the package properly. I am pretty certain that I am overseeing something obvious.
My folderstructure looks as follows:
+- ascripts
| +-- dependencies.as
|
+- root.fla
+- initialize.as
+- regressiontest.as
root.fla is my one and only fla file. It just contains:
stop();
include "initialize.as" // Let's go outside!
initialize.as contains all the magic. I am using this external file so I don't have to use the Flash IDE (since it is the worst IDE for coding). In there I have this:
// ...
import fl.controls.ComboBox;
include "ascripts/dependencies.as"
var t = new regressiontest.TestRunner(); // 1.
// ...
At 1. I am trying to instantiate my regression test class. It can be found in the file regressiontest.as and looks like this:
package regressiontest {
public class TestRunner {
public function TestRunner() {
trace('Hello');
// Actual Test Code Here ...
}
}
}
So now when I go to flash and debug the movie using Strg+Shift+Enter, I get the following error messages. I tried every way I could think of, so here is an overview of what I achieved so far:
var t = new TestRunner();
Message: 1180: Call to a possibly undefined method TestRunner.
var t = new regressiontest.TestRunner();
Messages:
root.as: 1120: Access of undefined property regressiontest.
regressiontest.as: 5001: The name of package 'regressiontest' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file. folder\regressiontest.as
regressiontest.as: 5008: The name of definition 'TestRunner' does not reflect the location of this file. Please change the definition's name inside this file, or rename the file. folder\regressiontest.as
import regressiontest.TestRunner;
var t = new TestRunner();
root.as, Line 19: 1172: Definition regressiontest:TestRunner could not be found.
root.as, Line 20: 1180: Call to a possibly undefined method TestRunner.
What is most confusing to me is that Flash appears to be picking up the class definition in regressiontest.as somehow. When I put an obvious error, such as
public function TestRunner() {
shoelace('Hello');
}
and use this to instantiate an object of the class:
var t:TestRunner = new regressiontest.TestRunner();
then I get the Message:
regressiontest.as: 1180: Call to a possibly undefined method shoelace.
One might think now that the instantiation causes the problem. But when I set the code from shoelace to trace and leave the instantiation I get the following messages:
Messages
Scene 1, Layer 'AS', Frame 1: 1046: Type was not found or was not a compile-time constant: TestRunner.
root.as: 1120: Access of undefined property regressiontest.
regressiontest.as: 5001: The name of package 'regressiontest' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file. folder\regressiontest.as
regressiontest.as: 5008: The name of definition 'TestRunner' does not reflect the location of this file. Please change the definition's name inside this file, or rename the file. folder\regressiontest.as
I tried renaming the file within the package, I tried renaming the package, I tried importing with import regressiontest.*; and so on. What am I missing?
What do I need to set my filename to? Does it need to match the PACKAGE NAME or the CLASS NAME?
Am I missing some crazy camel case rule?
Is there a maximum length to package names or something crazy like that?
Did I forget to configure flash or the FLA file correctly?
Am I missing some magic keyword?
Might there be sideeffects from the includes or imports at the beginning of my script?
I can reproduce these steps and I can provide the package via github.
Thank you in advance, with clueless greetings from Heidelberg, Germany
Johannes
As I see it, TestRunner is the class and regressiontest is the package, so you need import the class.
import regressiontest.TestRunner;
var t:TestRunner = TestRunner();
Also, you must do this changes.
The filename must be exactly the same of the class, replace regressiontest.as by TestRunner.as
Create a folder for the package and call it regressiontest, put inside TestRunner.as.

passing custom events between modules through parent application

I have created a custom event that I want to use to pass a string between two modules. The event looks like this:
package com.mypackage.events
{
import flash.events.Event;
public class ThumbDeleteEvent extends Event
{
public static const THUMBS_DELETED:String = "thumbsDeleted";
public var files:String;
public function ThumbDeleteEvent(type:String, files:String)
{
super(type);
this.files = files;
}
// Override the inherited clone() method.
override public function clone():Event {
return new ThumbDeleteEvent(type, files);
}
}
}
In one module I dispatch the event like so:
parentApplication.dispatchEvent(new ThumbDeleteEvent("parentApplication.thumbsDeleted", files));
and in another module I listen for the event like so:
public function init():void {
parentApplication.addEventListener("parentApplication.thumbsDeleted", onThumbsDelete);
}
if I use ThumbsDeleteEvent as the type passed in to the listener function like this:
public function onThumbsDelete(evt:ThumbDeleteEvent):void{
trace("thumb delete event for thumbs: "+evt.files);
}
I get the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.mypackage.events::ThumbDeleteEvent#26748a31 to com.mypackage.events.ThumbDeleteEvent.
if I just use Event as the type passed in to the listener function like this:
public function onThumbsDelete(evt:ThumbDeleteEvent):void{
if(evt is ThumbDeleteEvent){
trace("thumb delete event for thumbs: "+(evt as ThumbDeleteEvent).files);
}else{
var type:XML = describeType(evt);
trace(type.toXMLString());
}
}
It works but does not think it is a ThumbDeleteEvent type class (it hits the else statement) the xml output of describe type says its type is:
type name="com.mypackage.events::ThumbDeleteEvent"
What is going on here? If I put a breakpoint in the debugger it says the event is a ThumbDeleteEvent and I can see the files parameter and its right???
The issue here is that one swf has their definition of that class, and then the other swf has its own version of that exact same class. When trying to cast between them flash does a bytecode-check to see if the definitions are the same, and if you ever changed something in that as file without updating both with the exact same info you will run into this issue. That is, compile both swf-files, then change a space in the as-file, and compile only one swf file.
Urgh it's coming back to me, all those issues with shared code between different modules. I always just slug my way through these errors until I get it to work and can never really remember what it is since it can be so many issues.
Make sure both compiled swf-files have up-to-date-versions of the file.
Make sure both swf-files have same linkage-nesting to the code-file.
If that doesn't work [can't really remember since this issue is kind of like solve-once and copy to every other project].
See in which order things are added to ApplicationDomain and make sure nothing else has their own out-of-date-version of it through something imported in flash library
Move shared code into seperate code library linked in with "dynamic binding"
Try with sharing the Interface instead
Change how assets are loaded into the ApplicationDomain
Hopefully someone has more knowledge of this issue and can tell exactly what steps to use, but this is at least a starting point... I might have more time to research this and write a post about it sometime in the future later today.
Edit:
from another SO-thread Custom AS3 Class not Updating
This is the age old problem of what ultimately boils down to is the Verify Error. It happens when you embed "Class A" in one or more applications, modules, swfs, etc. Ultimately every output swf that uses "Class A" must be recompiled when "Class A" is changed. Otherwise you end up with a situation where 1 module has the newer implementation but others don't. This problem is compounded by the fact that the application domain is defined as a "first in wins" when it encounters a Class of the same name / package - meaning if the old one is referenced first, the newer one loaded later gets ignored.
The more permanent solution is to use class promotion to an RSL that ultimately allows the RSL to control the actual "Class A" reference in which it also implements an "IClassAImpl" interface that all modules use. This allows the compiler to cross link the reference with a signature it knows about without actually embedding the actual class itself.

Custom AS3 Class not Updating

I've had a similar issue to this, but the means that I solved the last one are not working here.
I have a custom class that consists of 12 separate .as modules. They're declared in the document class as follows:
import trailcrest.v1.s3.averta;
import trailcrest.v1.s3.chronos;
import trailcrest.v1.s3.eripio;
import trailcrest.v1.s3.fabrilla;
import trailcrest.v1.s3.gradua;
import trailcrest.v1.s3.lingua;
import trailcrest.v1.s3.navigare;
import trailcrest.v1.s3.pedem;
import trailcrest.v1.s3.praeferre;
import trailcrest.v1.s3.scriba;
import trailcrest.v1.s3.securos;
import trailcrest.v1.s3.sonus;
public static var Averta:averta = new averta();
public static var Chronos:chronos = new chronos();
public static var Eripio:eripio = new eripio();
public static var Fabrilla:fabrilla = new fabrilla();
public static var Gradua:gradua = new gradua();
public static var Lingua:lingua = new lingua();
public static var Navigare:navigare = new navigare();
public static var Pedem:pedem = new pedem();
public static var Praeferre:praeferre = new praeferre();
public static var Scriba:scriba = new scriba();
public static var Securos:securos = new securos();
public static var Sonus:sonus = new sonus();
This is a new version of the code. I am able to successfully refer to all of these classes and the public variables and functions inside in the "osr.as" document class. I can also SEE one module from another (i.e. Sonus can see Scriba using "osr.Scriba."
Where I'm having trouble is that, while the various modules used to be able to access all of each other's public functions and variables perfectly, after I added some new modules and variables and removed some old ones, Flash Professional is still literally USING the old version. Inside of any module, the code hints are showing all of the old public functions and variables, and none of the new ones.
I am guessing that this has something to do with some sort of temporary file that I can't get to. I absolutely need this working this week!
My .fla is "Tester.fla," and the document class is "osr.as." They're both in the same directory. Also in the same directory is the folder structure "/trailcrest/v1/s3/" which contains all of the Trailcrest modules.
Help??
EDIT: Whenever I try to reference one Trailcrest class from another Trailcrest class (i.e. osr.Sonus.foo), I get...
TypeError: Error #1009: Cannot access a property or method of a null
object reference.
I have confirmed beyond a shadow of a doubt all references.
This is the age old problem of what ultimately boils down to is the Verify Error. It happens when you embed "Class A" in one or more applications, modules, swfs, etc. Ultimately every output swf that uses "Class A" must be recompiled when "Class A" is changed. Otherwise you end up with a situation where 1 module has the newer implementation but others don't. This problem is compounded by the fact that the application domain is defined as a "first in wins" when it encounters a Class of the same name / package - meaning if the old one is referenced first, the newer one loaded later gets ignored.
The more permanent solution is to use class promotion to an RSL that ultimately allows the RSL to control the actual "Class A" reference in which it also implements an "IClassAImpl" interface that all modules use. This allows the compiler to cross link the reference with a signature it knows about without actually embedding the actual class itself.
Well, I finally figured it out. Here's the skinny on what was happening:
#1: Flash was apparently pulling an old version of the Trailcrest modules. To remedy this, I backed up everything and then removed all old instances of Trailcrest from my entire computer. Then, I put only the new modules back. That fixed the problem with Code Hints showing the old modules and variables.
#2: I had been experiencing Error #1009 whenever one Trailcrest class tried to access any component of another Trailcrest class, even though the references were all correct.
The cause was that I was calling functions on the various modules directly from the document class osr.as, outside of a function. This, of course, executes on the program start.
However, all the code within one Trailcrest class that called another Trailcrest class (i.e. osr.Sonus.foo) would not be able to access "foo" because osr.as for some reason or another hadn't finished initializing the classes before it ran the code that called them. This occurred, even though the problem code was well below the code that initialized the classes (see my question).
To fix this, I simply had to wrap the problem code into a public static function in the document class, and then call it from the Timeline. That ensured that all the classes were initialized before they tried referencing each other.
Needless to say, everything is running like a well-oiled machine now. How weird.
I'd welcome any explanation as to WHY this fixed the problem.

Accessing Variables in another class?

First off I don't understand classes, how to "call" or "initiate" them. I'm class ignorant.
I have two .fla files. One of my .fla files consist of 15+ .as files; we'll call this one XML editor. The other .fla file consists of 10+ .as files; we'll call it the interface.
The xmleditor.swf loads the interface.swf.
Within the xmleditor.swf, a login screen appears and the enduser logs in as either a "user" or an "admin". The "user" or "admin" is stored in a public variable called "userType". The userType variable is created in one of the many xmleditor.fla .as files called Login.as.
Once logged in, xmleditor loads the interface.swf. interface.fla uses 10+ .as files. one is called nodeNames.as I need an if statement in nodeNames.as that is something like this:
if (Login.userType == "user"){
trace("do something");
}
I have the following FlashVars.as file but I have no idea what the steps are to make it work.
package extras.utils {
import flash.display.Sprite;
import flash.display.LoaderInfo;
/* In AS3, we need to have a display object on the stage to access FlashVars
* this class can be used once, and then referenced from anywhere as
* FlashVars.data.variableName
*/
public class FlashVars extends Sprite {
public static var data:Object;
public function FlashVars() { }
public function load():void { //Only needs to be called once
data = this.root.loaderInfo.parameters;
}
}
}
Should I use this FlashVars? and if so, how?
Or is there an easier way to access the variable?
well, from what i understand, you Login.as is a class. Then you have two ways of accessing the Login.userType variable : if you want to be able to call it with
Login.userType, you'll need it to be static in your class
public static var userType:String
it is then accessible using Login.userType from anywhere in your application, as long as you import Login.
But it is often considered bad practice to have too many static vars in your app, especially from different classes. so you may want to have an instance of your login class stored in a variable somewhere in your app, along with anything you need
var myLogin = new Login();
myLogin.userType = 'value';
But be aware that this way, every new Login() will carry it's own different userType, so you will want to pass along myLogin to any object needing it.
Object programming can be confusing, but is very powerful, i suggest you read about it (in books or on the web) since the whole thing can't be explained here.
Have fun!