-
Notifications
You must be signed in to change notification settings - Fork 27
Scaleform Editing: The Basics
THIS IS A WIP CONVERSION OF THE GUIDE FROM ME3TWEAKS.COM.
It is going to be updated to modern standards and will have fixed links and formatting in future updates.
This guide will show you the basic of how interfaces work in the Mass Effect trilogy of games, both Original and Legendary versions. Extraction and repacking of GUIs is specific to ME3, but the actual use of JPEXs to modify the interface applies to all SWF files, and other games using scaleform. In this guide I will be referring to PCC files - Mass Effect's variant of the UPK file format. Other Unreal Engine 3 games may have a different main file type, just substitute it with your game's.
This is the introductory part of this guide that covers the concepts and implementation of an SWF file. The second part of this guide is where the actual editing is done, but you will need to know how an SWF file works in order to be able to edit them effectively.
There are the tools you will need to follow this guide.
- Legendary Explorer - You can also download it from ME3Tweaks Mod Manager's tools menu
- JPEXs - Flash player compiled file editor. You'll also need to install Java 8 or later to run the application. I personally recommend Amazon Coretto's distribution of the JDK.
- HxD Hex Editor - For learning how the UI is stored in game files. This is mostly applicable to non Mass Effect games.
- GUIs in the original Mass Effect series
- Manually extracting a GUI
- ME3 GUI Transplanter
- SWF File Assets
- SWF Header
- SWF Shapes
- SWF MorphShapes
- SWF Sprites
- SWF Frames
- SWF Others
- SWF Scripts
GUI editing is very complex. You will need to understand the idea of program disassembly to effectively follow this guide.
Mass Effect 1, 2 and 3 are all built on top of a modified version of Unreal Engine 3. Unreal Engine 3 supports Scaleform GFx, which is a middleware layer for the engine which allows developers to write interfaces in Adobe Flash Player and deploy them into a game. Adobe Flash scales to different sizes very well, and back in the middle to late 2000s was a pretty well known language for web development. Recently the push to HTML5 has effectively killed flash player, so there likely won't be many more games using SWF based interfaces.
Mass Effect 3 combat HUD GUI showing PC Power Wheel and Subtitles GUIs
Flash player files are files with the extension of SWF (ShockWave Flash) and SWC (ShockWave Compressed). Mass Effect 3 uses SWF, which are compressed by the PCC they are in, or by the SFAR their containing PCC is in.
To understand how a GUI is stored in Mass Effect 3, we will manually extract a GUI file from a binary export and modify it to produce a working SWF file. You can skip to the next part if you aren't interested in the technical details, just extract some GUI files using the command line options shown below.
First we open up ME3Explorer's Package Editor (previously known as PCC Editor 2). GUI files are located inside of specific PCC files, but for our example we will look in Startup.pcc, which contains a lot of different GUI files that are used quite often. Startup.pcc is part of the basegame, so you will find it in the BIOGame/CookedPCConsole folder. You should copy this to a different folder that we will be working in.
If you are working in any game besides Mass Effect 3, you must decompress the PCC to extract the GUI, or write tools that will decompress it for you. For this guide, we will use such a tool, my ME3 GUI Transplanter tool. My tool works with both compressed and decompressed PCC files.
For the sake of learning how to extract a GUI on your own, we will extract 1 GUI manually, and from then on use my tool to automatically extract them on demand.
ME3Explorer has pretty good support has good support for viewing the PCC package format. We can view a list of exports, their hex data, properties, etc. For this, we will be finding GUI files, which have a class of GfxMovieInfo in Mass Effect 3 and BioSWF for Mass Effect. I am not sure what it is in Mass Effect 2.
These exports typically have the letter SF in them, which stands for ScaleForm. In Mass Effect 3, we have exports most times prefixed with GUI_SF_, which indicate the package and binary exports of a GUI file. The package name is typically the GUI file name prefixed with GUI_SF, however a few ones like DesignUI (progressbars, timers, and counters) don't really have a naming convention, so look for things like designui.
Open Startup.pcc in Package Editor, and we switch the Exports tab from the main interface On the left, we can see the GfxMovieInfo exports. These are SWF files directly embedded as the data of an export, along with a few other pieces of information about the GUI file.
We can verify this is a GUI SWF file by looking at the Info tab and seeing that this is indeed a GfxMovieInfo class of export.
You by now have probably noticed that many of these interface files are called ME2 - not ME3. Almost all of the main HUD was simply a light update of Mass Effect 2's interfaces. A couple of recolors, maybe a slight change in how something works, and eventually the game was so far along refactoring it would have been more work than it was worth. Interestingly due to this, there is some leftover data, such as Mass Effect 2 style healthbars still in the game (if they can be used properly is another question).
We will be manually extracting the data of this export to produce a valid SWF file. Select the ME2_HUD export, and then on the toolbar select Debug => Get Complete Dump. This will dump the data of the export into a .bin file. Save this anywhere you like. This data includes the header of the export (0x0 to 0x20), the raw data (with an array property header), and a list of referenced game textures. We will need to snip out the header and array property information so that the SWF can load into JPEXs for editing.
At this point, rename the .bin file you saved earlier as a .swf file, and open it in HxD. We will need to tweak this file a bit.
At the top of this file, in the right hand side, we can see an ASCII interepetation of the bytes on the left. You may notice at 0x20 we see GFX - the header of the SWF file (GFx ScaleForm). We need to delete the first 32 (0x20) bytes of this file (highlighted in the image), so highlight them and delete them so GFX is the first 3 bytes of the file. HxD may say this changes the size of the file, continue anyways.
Save this file. Technically the list of references is still at the bottom of the SWF, but since the SWF header doesn't point to this data, it won't be used. You can safely keep it in, or just clip it off at the end of the binary. You can find this by finding the start of the references array in ME3Explorer and deleting from that offset (take into account that you've clipped the first 32 bytes already).
At this point we now have extracted a working SWF file. A lot of work huh? Moonshine developed some code that could extract this for you, and I improved it and implemented it into my ME3 GUI Transplanter tool (as well as fixed some bugs it had). It will do all of this for you.
The GUI transplanter has a command line interface. Versions 1.0.0.5 and below had a GUI version, but it was very limited in what it could do and no longer works in 1.0.0.6 and above.
For reference, the commands we will need to use for this guide are detailed as follows.
Transplanter-CLI.exe --gui-extract [--inputfile or --inputfolder] [pcc file or folder containing pcc files] Extracts all GUI files from specified PCC or folder of PCCs Transplanter-CLI.exe --injectswf [--inputfile or --inputfolder] [swf or folder of swfs] --targetfile PCCFILE Replaces the SWF (or all SWFS if --inputfolder) in the targetfile that have matching Package.Exportname.swf filenames. Adding -v will print out more detailed information about what is being replaced.
To dump all GUI files, simply use --inputfolder with a folder or a lot of pccs (such as an unpacked DLC or the basegame). GUI files with the same name will be 100% identical, so you will only need to keep one unique copy of each. You can search for .swf in Windows Explorer, sort by name, and then cherry pick each unique SWF from the list to copy to a new folder.
To inject an SWF (or a folder of SWFs) back into a file, use the --injectswf parameter along with --inputfile (swf file path) or --inputfolder (folder of swfs). Additionally you need to supply --targetfile, which points to a PCC file that you want to inject into. The names of the SWF files must match the export's package.filename format (GUI_SF_Mail.Mail.swf for GUI_SF_Mail.Mail for example). Keep backups of your files as things can go wrong easily.
GUI Transplanter has more options for things like data dumping from pcc's and more advanced GUI options which you can get from its command line help, but we won't be using them in this guide, and for most cases you will never need them.
Up until now we have only worked on extracting a GUI. Now comes the hard part - actually modifying the GUIs themselves. There will be a lot of technical information here and there's quite a lot of ground to cover. Let's load up this file in JPEXs. I am using 8.0.1 of the software for this tutorial, so things may look different if you're in a newer version.
When opening our extracted SWF files we will almost always be presented with the dialog shown above. SWFs can reference other SWF for resources, in this case it is referencing gfxfontlib, which contains fonts used to draw text. These typically aren't useful to load since we can't actually preview anything in JPEXs for this game's SWFs, so most times you can hit No to all. In some instances it may be useful to say yes (assuming you have the specified file at the listed location to load) as it will resolve a few variable names.
JPEXs is written in java, in a custom look and feel. For the most part it works - but there are some quirks. Dialogs will get stuck behind other windows and won't come back up unless you alt tab to the application (the same issues that happen in Mod Manager too). Searching is case-sensitive and must be turned off to do easier searching. You must manually click "Next" on search to find the next result, as pressing enter won't work. Things like this can make using the software a bit of a drag, but its the best free tool so it's what we're going to use.
On the left hand side of the screen you see a tree of different categories that are part of the SWF file. We will go through each tree to explain what each one does. For more in depth documentaiton you may want to look up an ActionScript Reference document. While I can't find any for ActionScript 2, ActionScript 3 is pretty similar and backwards compatible with AS2.
The header of the SWF file indicates thing such as compression type (Mass Effect 3's are not compressed, while Mass Effect 1's are), SWF file spec of the file (in this instance Flash Player 8), frame rate, the stage size, and other basic information.
The most import thing we will be looking at in this screen later will be the Display Rect, which is the stage size. This is the size of the content area, which in this case is 1280x720 (16:9). Most GUI files in ME3 are 720p because that's what the consoles output at. A few exceptions are made, where most times they will be in 1024x768 (4:3) or 1280x1024 (5:4). In SWF files, most units are twips, which are 1/20 of a pixel. It makes things more complicated, but just remember the 1/20 of a pixel and use it to calculate a simple value in x,y coordinates. If a value looks kind of random, try dividing it by 20 to get the pixel value, which might make more sense.
Shapes are scalable objects in flash player files. They are simple, as they cannot have a timeline, they don't respond to input events, and they can't be grouped into a cluster to form a more complex object. On the right side you can see some of the embedded shapes. Some of them are blank because they are contained in the pcc file as a texture, and externally referenced (which doesn't work in JPEXs and never will).
Note the numbers to the right of the DefineShapeX values. These are IDs for the object. These will be used when identifying what object you are looking at.
Morphshapes are essentially animated shapes. Things like the glow effect of the power recharge indicator are examples of morphshapes. They have IDs the same as shapes, but other than that there isn't much we can do to edit these.
Sprites are essentially more powerful shapes (technically they subclass different objects, but for this tutorial one can think of them as better shapes). They can respond to input events (e.g. a button) and can be clustered (like a group of buttons). They can't have a timeline attached to them however.
Since sprites can cluster (add children to themselves) they sometimes will have no image data associated with them, but will contain a list of shapes or even other sprites in them. These have their own "content area" with a top left of 0,0. Expanding a sprite entry in the list can lead to a list of frames, upon expanding you will see things placing objects and removing them.
Frames, to my knowledge, can be used in the convential sense of frames (at a framerate of 30, 30 frames will be executed per second). Each frame can have data like adding, moving, or replacing an object. Frames can also be used to keep items in a state (like a state machine), where you can gotoAndStop to hold a state. For example, you could make a sprite (lets say a button) go to a visible state, and hold it. When something else happens, you can make it go to the hidden frame which puts it into the hidden state. Using states in this manner are typically done by using the FrameLabel. If you click on it, it will reveal the name of the label (e.g. activated, visible, blinking etc). There is also gotoAndPlay, which goes to a specific frame and will begin play from there until it either loops, ends, or is told to stop. I'm not a flash developer so my knowledge is really only from using JPEXs decompiler. While you can use labels (which is a string) in both of the goto methods, you can also pass in an integer frame number it seems.
We will be looking at frames a bit more later.
Texts are text that are rendered onto the screen. Things like your ammo count, remaining grenades, and other text are almost always done through the use of a Text object.
On the right side of the above screenshot you probably are noticing some HTML - flash player can render limited HTML text, which gives us some decent flexibility with what we can do with a text object. However, you cannot simply just click edit here and edit away - it won't be able to save (cannot find the font). Instead, you will need to go into Raw Edit, which is done via right clicking:
In this mode you get a list of all types of properties you can edit. For the area Initial String, you can see a rendered version of the HTML text. To edit the HTML around the text, you must go into edit mode and then select the item, where it will revert to standard HTML text rather than rendered. Note that when you specify an HTML tag that is also the same as one of the properties, the HTML tag will supercede the text object property. For example, if you wrap a a string in but set textColor to blue, the text will render as red.
Frames, as a category of the SWF, control the placement of sprites, shapes, morphshapes, and text on the stage itself. As sprites can also contain these, you may need to drill through a few objects to find what you are looking for. For the most part, to change placement of UI elements, you will need to do so here. The biggest difficulty of changing element positioning on screen is the fact that it takes a lot of time. For every change you will need to boot the game and view it to make sure it is what you want.
In the above image, you can see a list of objects being placed onto the stage. This SWF has only 1 frame, the starter frame, so we don't need to worry about goto's at all for the stage itself. Clicking on an item will let you edit properties such as placement (Translate X/Y in MATRIX, in TWIPS) as well as other properties of that object placement.
On some frames, you are able to get a thumbnail preview of what it may look like. I am unsure if this is built by Flash Builder when it makes the file or if its done by JPEXS in low resolution, but if click on the frames category you may be able to see a preview like this on the right side:
Opening the preview will lead to a blank page as JPEXS does not know how to render GFX properly.
You may notice in the above image that all of the items are conveniently named so its fairly easy to figure things out. Not all SWFs will have this feature, so you will have to find the ID (the number in parenthesis) and find it in sprites/shapes/morphshapes/texts. Using this information you can piece together what the object is supposed to be, such as enemy health bar or such.
The others category holds some information about the SWF similar to header, but includes a list of things like imported assets (from other SWFs), exported assets (available to other SWFs and the game engine), and external resources (resources from the game). Using this one could possibly add more elements to an SWF file, but it would be a lot of work for each asset.
In the above image, an export with the name of ME2_HUD_GD in the same package as this SWF will hold the gradient it is importing.
Scripts. Scripts scripts scripts. We will be doing almost all of our work in the scripts section, as it is by far the most flexible item in the SWF you can edit. We have nearly fully compilability here - we can write new code, call (to a limited extent) game functions, reposition elements and change variables (in the SWF).
For Mass Effect 3, scripts that will be useful are typically located in 2 locations in this category: in packages/screens/, and as the only item under frame 1 (DoAction). This frame 1 script is called as soon as the SWF is loaded to be used on the screen. This is where most specialized placement is done and items are turned on or off. Even if this frame has a blank script, writing code here will always execute before you see the first call to draw on the screen.
Typically you will find these useful scripts to be either/or, so if screens is present then frame 1 will be empty, conversely if frame 1 is not empty then you typically won't find a /packages/screens folder.
Scripts offer a ton of power to us, however the catch is their complexity, as we will be writing all of our new code in ActionScript 2 disassembly. That nice looking code on the left? Your code will interpret to that, but what we write won't be anywhere near as pretty,
This guide will be in no way shape or form a guide on writing flash player disassembly code. That's not the goal of this guide, but I will cover the basics to get us through it and a few other neat examples in the guide.
Ready to get editing? Lets get going.