Hi everyone,
Update: The example code given for Augoeides has been patched and is no longer working. The rest of the tutorial is still applicable to other servers, though.
Update 2: it appears many private servers are using glitchy/erroneous code, or are implementing security features, that sometimes makes creating the loader code much more of a challenge. Some private servers are still worth trying but sadly it is a case of "don't get your hopes up". Still feel free to contact me if you need any help.
So this has been requested so many times in the past, and I've helped people with it individually - but never made a public tutorial about it.
It's a very simple process if you have any coding experience, but please respect learners/beginners who have no idea where to start.
If you only care about making an AQWORLDS trainer,
click here.
Introduction
In any Flash trainer we externally load the game's SWF. We do this with the "Loader Code".
Let's look at the loader code:
Loader Code For AQWorlds
import flash.events.Event;
//Comments by Oliboli8769
Security.allowDomain("*");
//URLs as Strings used for easiness
var sURL1 = "https://aqworldscdn.aq.com/game/";
var sURL2 = "https://cdn.aqworlds.com/game/";
var sFile; //used to store game version string
var versionLoader: URLLoader;
var Game: Object;
var swfContext: LoaderContext;
var swfLoader: Loader;
var swfRequest: URLRequest;
GetVersion(); //starts game load
function GetVersion() {
//checks for most recent game version from ASP file
versionLoader = new URLLoader();
versionLoader.addEventListener(Even*****MPLETE, onVersionComplete); //adds event listener for when the ASP is loaded
versionLoader.load(new URLRequest(sURL1 + "gameversion.asp")); //same as https://aqworldscdn.aq.com/game/gameversion.asp
}
function onVersionComplete(param1: Event) {
//ASP file has now been fully loaded
var vars: URLVariables;
vars = new URLVariables(param1.target.data); //reads variables held on loaded ASP
if (vars.status == "success") //checks the 'status' var on ASP
{
//after confirmation
sFile = vars.sFile; //reads game version linkage and saves as the variable sFile
LoadGame(); //now the version is found, we can load the game
}
}
function LoadGame() {
swfContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
swfLoader = new Loader();
swfRequest = new URLRequest(sURL2 + "gamefiles/" + sFile); //using sFile from before as updated game linkage
swfLoader.contentLoaderInfo.addEventListener(Even*****MPLETE, onGameComplete); //adds event listener for the game load
swfLoader.contentLoaderInfo.addEventListener(flash.events.ProgressEvent.PROGRESS, onGameProgress); //adds event listener for how much the game has loaded
swfLoader.load(swfRequest, swfContext);
stage.quality = StageQuality.LOW; //sets stage quality to low, possibly reducing lag (optional)
}
function onGameComplete(loadEvent: Event) {
stage.addChildAt(loadEvent.currentTarge*****ntent, 0); //adds the loaded game content to the stage
loadEvent.currentTarge*****ntent.y = 0.0;
loadEvent.currentTarge*****ntent.x = 0.0;
Game = Object(loadEvent.currentTarge*****ntent); //stores loaded content onto the Object Game
Game.params.sURL2 = sURL2;
Game.params.sTitle = "Trainer Tutorial By OB";
}
function onGameProgress(arg1: flash.events.ProgressEvent): void {
//this can be used for progress bars/loaders before trainers
var percentage: *= arg1.bytesLoaded / arg1.bytesTotal;
trace(percentage * 100); //traces how much the game has loaded as a percentage
return;
}
function SendPacket(packet: String) {
var args: Array = new Array;
var tempArg: String = "";
var var1: String = "";
var done1: Boolean = false;
var var2: String = "";
var done2: Boolean = false;
var done3: Boolean = false;
var done4: Boolean = false;
var i: Number = 1;
while (i < packet.length) {
if (packet.charAt(i) != "%") {
if (done1 && !done2) {
var1 += packet.charAt(i);
} else if (done1 && done2 && !done3) {
var2 += packet.charAt(i);
} else if (done1 && done2 && done3 && done4) {
tempArg += packet.charAt(i);
}
} else {
if (!done1) {
done1 = true;
} else if (done1 && !done2) {
done2 = true;
} else if (done1 && done2 && !done3) {
done3 = true;
} else if (done1 && done2 && done3 && !done4) {
done4 = true;
} else if (done1 && done2 && done3 && done4) {
args.push(tempArg);
tempArg = "";
}
}
i++;
}
var room: String = Game.world.curRoom;
switch (var2) {
case "afk":
room = "1";
break;
case "hi":
room = "1";
break;
case "gar":
room = "1";
break;
case "cmd":
room = "1";
break;
}
trace("Zone Master: " + var1);
trace("Packet Type: " + var2);
trace("Arguements: " + args);
Game.sfc.sendXtMessage(var1, var2, args, "str", room);
}
stop();
As you can see, just scanning over the code, there are a few main steps:
- Requesting for the latest game version - GetVersion()
- Receiving and reading the latest game version - onVersionComplete()
- Using the game version, requesting to load the game - LoadGame()
- Receiving the loaded game - onGameComplete();
For now, we can ignore the functions onGameProgress(), which is just a fancy but unnecessary function for tracking how much of the game has loaded.
We can also ignore the function SendPacket(), which is used for hacking the game later on.
Anyway, cutting to what you really want to know. The load for a private server is the exact same process as above, with possibly a few hiccups.
All we need to do fundamentally, is change the links that the 'loader code' actually loads.
This concerns the variables sURL1 and sURL2 in the code, and a few other parts where there is clearly a URL being loaded.
Looking at the code for AQWorlds, we end up with this:
Version Link:
https://game.aqworlds.com/game/gameversion.asp
*
Game Link:
https://aqworldscdn.aq.com/game/game...e_20160429.swf
*Note that the string of numbers at the end will change, because it is what has been loaded from the version link - the game's version.
Finding these links, for private servers
- Open Google Chrome (or another browser with the same functionality)
- Go to the private server you want to create a bot for, to where you would normally log-in.
- At the top of your screen, go to View>Developer>Developer Tools.
- If you struggle with the step above, alternatively, you can right click anywhere on the page and click "Inspect".
- Once you have the Developer window open, make sure you have the "Network" tab selected.
- Go back to the window of the game, and refresh the page, still keeping the Developer window open.
- You should start to see sources for the page load appear under the Network tab that you've selected.
- Amongst all of these links, look for links similar to the ones used for AQWorlds above (a link ending in gameversion.asp, and an SWF link ending in a string of numbers - a date)
- Save these on a notepad somewhere
Using The Links
Okay so as an example, I'm going to be using the private server Augoeides/HiddenProject.
After following the steps above, I have these two links:
Version Link:
https://www.augoeides.org/gameversion.asp
Game Link:
https://www.augoeides.org/gamefiles/....16-HP.Rr9.swf
Now, it's way too confusing to explain this process. So here's the loader code for HiddenProject, along with annotations to explain what I've done.
Loader Code For HiddenProject
import flash.events.Event;
//Comments by Oliboli8769 - ADAPTED FOR HIDDENPROJECT, CHANGES IN CAPITALS
//Version Link: https://www.augoeides.org/gameversion.asp
//Game Link: https://www.augoeides.org/gamefiles/Client-04.24.16-HP.Rr9.swf
Security.allowDomain("*");
//URLs as Strings used for easiness
var sURL1 = "https://www.augoeides.org/"; //CHANGED THIS LINK FOR VERSION
var sURL2 = "https://www.augoeides.org/"; //HAPPENS TO BE THE SAME AS sURL1, THESE VARIABLES AREN'T NECESSARY, BUT MAKE IT CLEANER
var sFile; //used to store game version string
var versionLoader: URLLoader;
var Game: Object;
var swfContext: LoaderContext;
var swfLoader: Loader;
var swfRequest: URLRequest;
GetVersion(); //starts game load
function GetVersion() {
//checks for most recent game version from ASP file
versionLoader = new URLLoader();
versionLoader.addEventListener(Even*****MPLETE, onVersionComplete); //adds event listener for when the ASP is loaded
versionLoader.load(new URLRequest(sURL1 + "gameversion.asp")); //USING SURL1 FOR GAME VERSION, SAME AS https://www.augoeides.org/gameversion.asp
}
function onVersionComplete(param1: Event) {
//ASP file has now been fully loaded
var vars: URLVariables;
vars = new URLVariables(param1.target.data); //reads variables held on loaded ASP
//if (vars.status == "success") //STATUS CHECK REMOVED FOR HIDDENPROJECT, NOT APPLICABLE
sFile = vars.sFile; //reads game version linkage and saves as the variable sFile
LoadGame(); //now the version is found, we can load the game
}
function LoadGame() {
swfContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
swfLoader = new Loader();
swfRequest = new URLRequest(sURL2 + "gamefiles/" + sFile); //USES sFILE VERSION LOADED FROM VERSION LINK
swfLoader.contentLoaderInfo.addEventListener(Even*****MPLETE, onGameComplete); //adds event listener for the game load
swfLoader.contentLoaderInfo.addEventListener(flash.events.ProgressEvent.PROGRESS, onGameProgress); //adds event listener for how much the game has loaded
swfLoader.load(swfRequest, swfContext);
stage.quality = StageQuality.LOW; //sets stage quality to low, possibly reducing lag (optional)
}
function onGameComplete(loadEvent: Event) {
stage.addChildAt(loadEvent.currentTarge*****ntent, 0); //adds the loaded game content to the stage
loadEvent.currentTarge*****ntent.y = 0.0;
loadEvent.currentTarge*****ntent.x = 0.0;
Game = Object(loadEvent.currentTarge*****ntent); //stores loaded content onto the Object Game
//Game.params.sURL2 = sURL2;
Game.params.sTitle = "HiddenProject Is Loaded";
Game.params.strCode = "lol"; //EXTRA LINE ADDED TO BYPASS THEIR 'PATCH', NOT NEEDED ON OTHER SERVERS
}
function onGameProgress(arg1: flash.events.ProgressEvent): void {
//this can be used for progress bars/loaders before trainers
var percentage: *= arg1.bytesLoaded / arg1.bytesTotal;
trace(percentage * 100); //traces how much the game has loaded as a percentage
return;
}
function SendPacket(packet: String) {
var args: Array = new Array;
var tempArg: String = "";
var var1: String = "";
var done1: Boolean = false;
var var2: String = "";
var done2: Boolean = false;
var done3: Boolean = false;
var done4: Boolean = false;
var i: Number = 1;
while (i < packet.length) {
if (packet.charAt(i) != "%") {
if (done1 && !done2) {
var1 += packet.charAt(i);
} else if (done1 && done2 && !done3) {
var2 += packet.charAt(i);
} else if (done1 && done2 && done3 && done4) {
tempArg += packet.charAt(i);
}
} else {
if (!done1) {
done1 = true;
} else if (done1 && !done2) {
done2 = true;
} else if (done1 && done2 && !done3) {
done3 = true;
} else if (done1 && done2 && done3 && !done4) {
done4 = true;
} else if (done1 && done2 && done3 && done4) {
args.push(tempArg);
tempArg = "";
}
}
i++;
}
var room: String = Game.world.curRoom;
switch (var2) {
case "afk":
room = "1";
break;
case "hi":
room = "1";
break;
case "gar":
room = "1";
break;
case "cmd":
room = "1";
break;
}
trace("Zone Master: " + var1);
trace("Packet Type: " + var2);
trace("Arguements: " + args);
Game.world****otClass.sfc.sendXtMessage(var1, var2, args, "str", room);
}
stop();
Okay so I hope the annotations on the code are enough to help you understand. This is an extremely hard tutorial to make, and in hindsight, I probably should have made a video - but oh well.
Please note that the extra line (Game.params.strCode = "lol") is only necessary for Augoeides/HiddenProject and not any other private server.
What to do from here?
Follow the tutorial linked below. Because you're hacking a private server, 99% of the time the code for AQWorlds is identical. Don't worry, that tutorial is much nicer.
Full AQWorlds Trainer Tutorial:
https://www.mpgh.net/forum/showthread.php?t=891807
Phew, thank god that's over.
Oliboli8769
@
emoric28 thanks for the suggestion. Keep them coming!!