Add hyperlinks to SWF buttons - actionscript-3

I have an SWF file which I downloaded off the internet for studying purposes: http://binw.net/externalUIs/campaigns/skylandersSuperchargers/SkylandersSuperchargersMap_26_10_15.swf
There are different "locations" on the SWF file and I believe it is a map - for example, there's a fountain, a racing track, a tree and a castle. What I need to do is make all the different locations redirect to a different hyperlink when they're clicked..
I had a look at How to edit redirect link on an SWF Flash file? and it suggested that I download the trial version of Flash Decompiler which I have done but I am lost at what to do subsequent to this.

You need to decompile the swf then modify some code, then compile it to new one.
I have try on your swf,and when you click the location, it will redirect to the baidu website.
here is the changed swf
You need two software, JPEXS and RABCDAsm
1. Decompile the swf and found the relative code
JPEXS is used to decompiled the swf into code and png, jpg. You can find the code for the action when you click the city, I find it is Map Class, gotoLocation function.When I try to open your swf, it throws some error, and I found the class name and function name directly.
2. Use RABCDAsm to disassemble the swf, get abc code
RABCDAsm is an ActionScript 3 assembler/disassembler, it will turn the swf into many files with asasm and abc type, then you can modify the file in your editor,and the RABCDAsm tool can make the files into a new swf.
So here is a problem, how can you want the target Map file in the generated files?
Try to search Map.class.asasm in the files, the same name of the decompiled class.
3. Write a new Map class contain the gotoLocation function,get the target abc code
You need to use new abc code to replace the abc code in the Map.class.asasm.
Try to make a project, then add a Class named Map, put a gotoLocation function in it like this.
package
{
import flash.net.URLRequest;
import flash.net.navigateToURL;
import flash.events.MouseEvent;
public class Map
{
public function Map()
{
}
public function gotoLocation(param1:int) : void
{
if(param1 != 999)
{
navigateToURL(new URLRequest("http://www.baidu.com"),"_blank");
}
}
private function closeMap(param1:MouseEvent = null) : void
{
}
}
}
Get the release swf of the new project,then repeat the second step, you will get the abc code of the class like this
trait method QName(PackageNamespace(""), "gotoLocation")
method
refid "Map/instance/gotoLocation"
param QName(PackageNamespace(""), "int")
returns QName(PackageNamespace(""), "void")
body
maxstack 3
localcount 2
initscopedepth 4
maxscopedepth 5
code
getlocal0
pushscope
getlocal1
pushshort 999
ifeq L11
findpropstrict QName(PackageNamespace("flash.net"), "navigateToURL")
findpropstrict QName(PackageNamespace("flash.net"), "URLRequest")
pushstring "http://www.baidu.com"
constructprop QName(PackageNamespace("flash.net"), "URLRequest"), 1
pushstring "_blank"
callpropvoid QName(PackageNamespace("flash.net"), "navigateToURL"), 2
L11:
returnvoid
end ; code
end ; body
end ; method
end ; trait
It's easy to find the abc code by search function name.
4. replace the abc code,create new swf with RABCDAsm
use the new abc code to replace the target body part in second step, then use RABCDAsm to generate the new swf.
The old abc code like this
trait method QName(PackageNamespace(""), "gotoLocation")
method
refid "com.binweevils.externalUIs.map:Map/instance/gotoLocation"
param QName(PackageNamespace(""), "int")
returns QName(PackageNamespace(""), "void")
body
maxstack 2
localcount 2
initscopedepth 10
maxscopedepth 11
code
getlocal0
pushscope
getlocal1
pushshort 999
ifeq L21
getlocal0
getproperty QName(PrivateNamespace(null, "com.binweevils.externalUIs.map:Map/instance#0"), "bin")
getproperty Multiname("crntLocID", [PrivateNamespace(null, "com.binweevils.externalUIs.map:Map/instance#0"), PackageNamespace(""), PackageNamespace("com.binweevils.externalUIs.map"), Namespace("http://adobe.com/AS3/2006/builtin"), PrivateNamespace(null, "com.binweevils.externalUIs.map:Map/instance#1"), PackageInternalNs("com.binweevils.externalUIs.map"), ProtectedNamespace("com.binweevils.externalUIs.map:Map"), StaticProtectedNs("com.binweevils.externalUIs.map:Map"), StaticProtectedNs("flash.display:MovieClip"), StaticProtectedNs("flash.display:Sprite"), StaticProtectedNs("flash.display:DisplayObjectContainer"), StaticProtectedNs("flash.display:InteractiveObject"), StaticProtectedNs("flash.display:DisplayObject"), StaticProtectedNs("flash.events:EventDispatcher")])
getlocal1
ifeq L19
NOTICE
you can find the RABCDAsm for windows here,and you can find the RABCDAsm commands in its github page.
At Last, some times you don't need RABCDAsm if the project is simple.Try to put the decompiled code into a project, then fix the compile error.In this case, you need luck.

SWF file is compiled and zipped ActionScript code. You can't change anything inside (in general) without recompiling. So, you need to decompile the swf you have and hopefully, you'll get a set of files. Then you need to find the parts of code where the hyperlink addresses are located and change them. Then you need to compile the code back, and, if you are lucky enough, you'll get the swf with changed hyperlinks. Imho, it's a pretty bad idea.

Related

AS3 trying to import a custom class. Files in wrong order?

I posted my original question here. Which got me to this point. I think I'm doing everything just as #Atriace suggested, but I get this error:
C:\Users\User\Desktop\oldProjects\nealdavis\calculations\GeoMath.as, Line 1, Column 1 5001: The name of package 'nealdavis.calculations' does not reflect the location of this file. Please change the package definition's name inside this file, or move the file. C:\Users\User\Desktop\oldProjects\nealdavis\calculations\GeoMath.as
Since, I think I'm doing everything as I've been suggested to, I thought I'd upload the screenshots. Maybe there is something amiss that I don't even know to tell you about. Thanks.
The problem is that your tutorialAsteriod file can only see a sub-folder called calculations when it tries to compile. Yet your Document.as code tells it to :
import nealdavis.calculations.GeoMath;.
With that line, it is expected that Document.as is in the same location as a sub-folder called nealdavis which in turns contains that calculations sub-folder inside. You only have a sub-folder called calculations hence you get the error.
To Fix :
Either make a new extra sub-folder called nealdavis and then move that calculations folder into it so that the final setup is :
Document.as + folder called nealdavis + inside that will be calculations sub-folder.
Your folder structure should be like this example :
Desktop > oldProjects > nealdavis > (Document.as here... + ) nealdavis > calculations
Or else just do : import calculations.GeoMath;.

Setting breakpoints at methods of inner and anonymous classes in JDB

I'm attempting to operate JDB programmatically. Unlike any sane debugger, JDB refers to the source code using class names instead of source file names. I'm assuming it's related to having the bytecode stored in multiple .class files instead of a single file(you would expect compilation with the -g flag to produce some reference to the source files, but making things easy is not the Java way...)
When JDB refers to classes I can usually do some string manipulations and look at the source file names to figure out which source file declares the relevant class. When I need to supply a class name for a breakpoint, I can read the file to get the package name, use the file name as the class name and generate the full class name that way. These two cases I got them working.
The problem starts with inner classes and anonymous classes. They reside in their own class files, and their names are mangled versions of the class that contains them. To set a breakpoint there I need the mangled name.
For example - this is Main.java(+line numbers):
1: public class Main{
2: public static void main(String[] args){
3: new Object(){
4: #Override public String toString(){
5: System.out.println("hi");
6: return "";
7: }
8: }.toString();
9: }
10:}
I compile it using javac -g Main.java and got Main.class and Main$1.class. I'm running jdb:
Initializing jdb ...
> stop on Main.main
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
run Main
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 new Object(){
(I needed that part to load Main.class - otherwise I would simply get "It will be set after the class is loaded." for all the breakpoint setting attempts.)
If I set a breakpoint for line 8 it works properly:
main[1] stop at Main:8
Set breakpoint Main:8
If I set a breakpoint for line 5 - which is part of the anonymous class - I get an error:
main[1] stop at Main:5
Unable to set breakpoint Main:5 : No code at line 5 in Main
Line 5 clearly contains code - the problem is that the code is not compiled into Main.class - it's compiled into Main$1.class, so I need to write instead:
main[1] stop at Main$1:5
Deferring breakpoint Main$1:5.
It will be set after the class is loaded.
Now, the way Java splits the bytecode into .class files is deterministic, and in this simple example it's easy to figure out what goes where - when you examine it with human eyes - but I need a way to figure the mangled class names programmatically(with VimScript) for real world source files. Trying to syntactically analyze the source file and figure out which is what is too complex a task - there ought to be a simpler way.
Maybe extract that information from the .class files, or question JDB about it, or even make JDB use source file names like any sane debugger for any sane language...
I just had the same problem. As a quickfix I just grepped for the class name (Object in your case) in all the Main$[x].class.
If you find many of them you have to use the index of the order they appear in the source file.

How can I reference a Flash file's own filename from actionscript?

In our pipeline, we ultimately publish HTML5 using Toolkit for CreateJS. However one of the steps to get us to that HTML5 includes publishing an SWF that outputs some Javascript code. I've mostly managed to automate this using JSFL. However, at present there is one line of AS3 that our artists have to find on the timeline and change manually, but it interrupts their workflow, and if they miss it or mess it up it is hard to catch, so I would like to automate it too:
Object(root).log.text += " root.skillAnime189 = factory();\n";
From the above, "skillAnime189.fla" is the name of the .fla file which contains this code. This is the case if the artist is working on Skill Animation #189, but if he is doing #304 or #6 or #1022 (no padding) the number changes accordingly, and he has to update that line accordingly.
So, I would like to change that line to something like:
var flaName:String = getThisFlashFileName().split(".")[0];
Object(root).log.text += " root." + flaName + " = factory();\n";
but I am at a loss as to how to access the name of the .fla file containing the code.
The common way to get the swf name is to parse stage.loaderInfo.url parameter:
var url:String = stage.loaderInfo.url;
url = url.split("?")[0]; //remove query string after "?"
var swfname:String = url.substring(url.lastIndexOf("/")+1);
trace(swfname);
output:
astest.swf
But this code gives swf but, rather than fla, so you need to maintain the same names for flas and published swfs (any case usually they are the same, so it shouldn't be the problem)

getDefinitionByName not finding a variable that exists

I am using flash.utils.getDefinitionByName in an attempt to grab an art asset. I use this function quite a bit and haven't had trouble until now. Check it:
assetName = Assets.MegaBerry; // works
assetName = getDefinitionByName("Assets.MegaBerry") as Class; // doesn't work
What the heck?? Error response for the second line is "Variable not found."
If it matters: Assets is a file in my root source directory (it has no package; Assets is the fully qualified name) and I've tried putting:
import Assets;
at the top with no luck.
For reference, in Assets.as I have:
[Embed(source = "../art/Inventory/MegaBerry.png")]
public static var MegaBerry:Class;
Your problem is that embedding the resource into the Assets class will create a static variable of type Class that belongs to that class - which is what you are referencing when you use Assets.MegaBerry: A variable(!) of type Class.
It does not, however, register the MegaBerry class to a fully qualified class name. To do this, you have to use - who would have guessed it - registerClassAlias at some point in your application:
registerClassAlias("Assets.MegaBerry", Assets.MegaBerry);
After that, it will be available everywhere else when calling getDefinitionByName.
** EDIT **
Well that's some unexpected behavior... It turns out, the class that was embedded is in fact automatically registered, but under {className}_{variableName}, instead of the notation you would expect. So using:
getDefinitionByName("Assets_MegaBerry") as Class;
should to the trick.
registerClassAlias also works, but then you need to call getClassByAliasinstead of getDefinitionByName. Sorry for the mix-up.
** END EDIT **
You can also use the Embed tag to inject the resource into a separate class file, which you can then reference as expected by using getDefinitionByName, or simply using an import:
package assets {
[Embed(source="../art/Inventory/MegaBerry.png"]
public class MegaBerry extends BitmapData {
}
}
Instead of calling
assetName = getDefinitionByName("Assets.MegaBerry") as Class;
, instead just use:
assetName = Assets["MegaBerry"];
try:
[Embed(source = "../art/Inventory/MegaBerry.png" , symbol="MegaBerry")]
public static var MegaBerry:Class;
In actionscript, objects actually have a name property that is different from the actual variable name as it shows in code.
For example, if you create a variable as follows,
var myBerry = new MegaBerry();
Then getDefinitionByName("myBerry") will return null.
Only when you set the name of the variable by writing myBerry.name = "myBerry", will getDefinitionByName("myBerry") return what you want it to. The name of the object doesn't necessarily have to be equal to the variable name in code.
In your specific case, I don't think you need to use any of that anyways. Have you tried assetName = new MegaBerry() ?
If you want to find out what the fully qualified name of you class really is, you may do the following:
trace(getQualifiedClassName(Assets.MegaBerry));
You may do that from inside Assets.as, for instance.
You can feed that string back to getDefinitionByName() and get a reference to the class.
trace(getDefinitionByName(getQualifiedClassName(SomeClass)));
// output [class SomeClass]
And remember, getDefinitionByName() only gets you references for classes that are in the same scope as the getDefinitionByName call itself. So, if you are loading external SWFs, getting class references will depend on the application domain you are using and the place, where this code executes.

1067: Implicit coercion of a value of type Class to an unrelated type flash.display:DisplayObject

So for instance, I've got three .as files called 'Helicopter.as, Game.as, Blue.as'
and I also have a .fla file called Helicopter.fla (These files are all suppose to link together, to make the helicopter game) . In the Game.as file, I have the following;
if (blue1.hitTestObject(Helicopter))
{
trace("YOU HIT THE BLOCK!");
Helicopter.x = 76;
Helicopter.y = 217;
}
I have drawn the so called 'Helicopter'^ using API in a different file called Helicopter.as using this code;
graphics.beginFill(0x00FF00);
graphics.drawCircle(0, 60, 35);
graphics.endFill();
However, I originally had the "Helicopter' symbol drawn in the Helicopter.fla file (which I've now deleted), and now that I've drawn the 'Helicopter' using API, I get this error;
''1067: Implicit coercion of a value of type Class to an unrelated type flash.display:DisplayObject.''
Flash doesn't recognise the original Helicopter symbol (in the Helicopter.fla file, because I deleted it). But I want the system to detect the 'circle' drawn using API (In the Helicopter.as file). And I have no idea how to how to name the API drawn circle 'Helicopter', thus I'm getting an error. So how do I name the API circle to 'Helicopter', so the Game.as file recognises it. If you have no idea what I'm talking about, then don't worry, because I don't know too. Thank you. If you want, I can paste all the code I've done so far.
Helicopter is a class not a variable, therefore you cannot assign Helicopter.x. You need to create a variable var heli:Helicopter = new Helicopter(); and use heli.x
it also could be that you're not following the programming standards, and Helicopter is in fact a variable and not a Class, though the error seems to indicate otherwise.