Jump to content

Create your own scaleform using Flash + GFxExporter


Recommended Posts

I was researching for days, and many years ago even more time into editing ugx files, so i am sharing this tutorial for those interested. Maybe someone smarter then me will be able to finally crack the ugx file editing, like it was with interface. Credits at the bottom.

 

This guide is a work in progress as R* Scaleforms are still being digged and discovered day by day.

Ok so this is intended to build and stream your first own scaleform.
I started diggin 1 week ago into this amazing world and after an initial sense of loss, i started understanding how R* handles it.

First of all the basic tools. Youl’ll need:

 Adobe Flash CS6 PRO trial 13 (R* used CS4 and CS5 for its scaleforms but it’s ok)
 GFxExporter 16 (this is used to convert from swf to gfx format, i’ll explain later in the guide, download all the files and place them in a folder)
 JPEXS Free Flash Decompiler 7 (To decompile your scaleform… and not only that)
– FiveM Client and a Server to test with.

Part 1 - Setting everything up for work

Ok so, first of all, don’t launch Adobe Flash Pro yet, we need to create a folder where we will store all of the project first, what you call it is not important, what’s important instead is the package directory, just like how you would set it up in Java or other similar languages.

Inside your folder, create four distinct folders one inside the other, so you can get the following directory YourFolder\com\rockstargames\gtav\levelDesign\ inside this folder is where we are going to put our ActionScript files.

Now you can open Adobe Flash Pro, this is a very old application, i suggest to play with it and its options for a while… in about 1 day of playing you’ll get the hand of it :slight_smile:

Ok once opened, you can get a view like this

 

This is the Classic (base) settings of Flash’s Workspace… if you go in the Top-Right area you can change your Workspace.
I personally use the Developer one with the addition of the actions panel anchored in the Left-Bottom side of the screen as it fits perfectly what we need to do:

 

Part 2 - Creating our Project

Now that we have set our Workspace, we can create a new project, in the Left-Top part of the screen you can see the Project panel, here we can create a new project, to do that just select the drop down bar and click into "New Project…"

image

this window will appear:

image

Here you can set the name of the project for now we’ll call it GuideScaleform, then select the yellow folder icon and navigate to the “YourFolder” folder we mentioned before, the application will set the project path there.
Select the “Create default document” tick as we need it to build the graphic interface of our scaleform and give it a name (it will be your swf / gfx file name)

 Important!! Always set the Destination at Flash Player 8 and Script to ActionScript 2.0

When we’re done click “Create Project” and we have our project like this
image

The file AuthotimeSharedAssets.fla is generated automatically and can be ignored we will not use it but we need it to publish our project into swf so don’t touch it and leave it there.

now we can start working on our Scaleform.

Part 3 - The Drawing

First thing to do, is double clicking the fla file we created, an empty white page will open.
look on the right side of the screen…

 

Make sure that the flash player is version 8 and Action Script is ActionScript2, then we change our project dimensions, the fps can go from 24 to 29 to 30 in some scaleforms, up to you, the size must be 1280 x 720.
Almost all scaleforms uses 1280 x 720 screensize to work with even the 3D ones, some use smaller sizes but for now this will be good for us.

Next step is creating CONTENT and BOUNDING_BOX symbols these 2 are the main parts of the scaleform and i’ll explain later why. Go right side and click on the Add Symbol button (the very first one) or right click on the lower empty space and select “New Symbol",

 

the symbol is a Movie Clip and while it can have the name you want, it must have a linkage to the Action Script, under “ActionScript Linkage ”, check both cases and write in the Identifier box CONTENT .
Repeat the same and in the Identifier box write “BOUNDING_BOX

 

the 2 symbols should look like this
image

now, on the main screen click on that little icon spacer.png 2 on top and select whatever you called BOUNDING_BOX Symbol.

Now click on the Rectangle Tool or press R), create a rectangle, then select the "Selection Tool (or press V), select the rectangle and set its XY position to zero, the color does not matter, you can set the alpha to 0% or not as the code later will set it as invisible anyway.
This symbol represents your screen’s boundaries and will contain the custom scaleform.

Now it doesn’t need to always be 1280x720, for example if you are making a menu and want to render it in 3D or in any mode outside of Fullscreen, the rectangle should probably be the same size as the menu itself. What’s the most important from what I can guess is that the position must be zero’d.

Now using the same little icon spacer.png 2 select the CONTENT symbol to show, THIS is where we are going to draw our scaleform… everything is drawn into the CONTENT symbol.
Now Drag&Drop the BOUNDING_BOX symbol from the library into the CONTENT screen and again, set the BOUNDING_BOX rectangle’s position XY to 0.
you can see when it’s 0 because the little + symbol is on the top-left corner like in the picture

 

 

Now on the timeline in the bottom of your workspace, add a new layer to keep drawing, you can see the layers as steps, each step is a set of drawings that takes you to the end, first layer is the bounding_box’s one, the next layer will make us draw a rectangle inside the bounding box layer, place wherever you want as long as it’s inside the bounding_box layer.
you can draw your rectangle big or small as you want but not too small to let us draw some texts into it.

now adding another layer we select the Text Tool ( T ), we are going to add a text that will not change by script or user input we’ll set it as Static Text

 

In the nearby we’ll be adding a TextBox that will be filled by script via scaleform functions and natives…
Draw it and select Dynamic Text in the drop-down, leave the text box empty, and add an instance name “PlayerNameText

 

 

Since we are adding texts we need to add a font to the scaleform or they won’t be visible at all, to do that select one of the textboxes and click on the “Embed…” button located in the Properties Tab, go to the “Character ranges” category and check All in the list, next, go to the Options tab then under “Linkage” check both boxes and click OK, you should see the font added into the Library panel.

The basic drawing part is done for now.

Part 4 - The ActionScript code

Now the fun part, go up in the project folders navigate into com\rockstargames\gtav\levelDesign folder and in here click on New File icon
image
Set File Type as Action Script and call it BaseScriptUI.as ==> Create it and copy this code into it

class com.rockstargames.gtav.levelDesign.BaseScriptUI extends MovieClip
{
	var BOUNDING_BOX;
    var CONTENT;
    var TIMELINE;

	function BaseScriptUI()
	{
		super();
	}
	function INITIALISE(mc)
	{
		this.TIMELINE = mc;
		this.CONTENT = this.TIMELINE.attachMovie("CONTENT", "CONTENT", this.TIMELINE.getNextHighestDepth());
		this.BOUNDING_BOX = this.TIMELINE.attachMovie("BOUNDING_BOX", "BOUNDING_BOX", this.TIMELINE.getNextHighestDepth());
		this.BOUNDING_BOX._visible = false;
	}
}

This is the BaseScriptUI code, present in every drawn scaleform, it’s the super class for every creation you’ll see why… create a new ActionScript file in the folder and call it the same way you called your fla file

this will be your main Scaleform code and you’re going to copy this base code to start with:

class com.rockstargames.gtav.levelDesign.GUIDESCALEFORM extends com.rockstargames.gtav.levelDesign.BaseScriptUI
{
   function GUIDESCALEFORM()
   {
      super();
   }
   function INITIALISE(mc)
   {
      this.TIMELINE = mc;
      this.CONTENT = this.TIMELINE.attachMovie("CONTENT","CONTENT",this.TIMELINE.getNextHighestDepth());
   }
   function SET_PLAYER_NAME(str)
   {
      this.CONTENT.PlayerNameText.htmlText = str+" !";
   }
}

As you can see i wrote GUIDESCALEFORM all capital… since all scaleforms are wrote like this, i decided to keep it as that.
You can note that the Scaleform itself extends BaseScriptUI this is the reason why we need it and see it in almost every scaleform.
Another thing to note is that i already set a Scaleform function for you, SET_PLAYER_NAME is the function you’ll call to set the empty text box we drew earlier… for convention all the “public” scaleform functions (the ones that can get called by the scripts) are written ALL_CAPITAL_WITH_UNDERSCORES while internal functions are always written lowCapitalWithoutUnderscores

The last part of the work is basically adding the actions and publish our scaleform.
Click on your scene button
image

If you don’t have the Action panel as i do, simply press F9 and anchor the window to one of the side panels.

In the Action window we’re going to paste this code,

var TIMELINE = new com.rockstargames.gtav.levelDesign.GUIDESCALEFORM(); // Constructor of your custom scaleform
TIMELINE.INITIALISE(this);

This is the last code to be passed when publishing, if there are errors anywhere in your ActionScript codes or in the drawing, the swf will be still published but this timeline won’t be, if decompiling your scaleform you can’t find this code, this means you have an error somewhere in your code.
When writing code is good practice to always check for errors and to auto-indent by using these 2 symbols in the editor, if an error appears it will be shown.
image

Part 5 - Publishing

Go to “File” on top and select “Publish Settings”, be sure that the Target is set to Flash Player 8.0 and Script to ActionScript 2.0, then click OK.

Go to “File” again and select “ActionScript Settings”, then set a Classpath to your com folder inside your project folder and click OK.

Now we are ready, go to “File” and select “Publish” (or use Alt + Shift + F12) and in your project folder you’ll see a new “GuideScaleform.swf” file.

Now this is a good time to check if everything is set up properly, if you see something missing, go back and see if you missed something.
To be sure everything is gone as expected, you can also open the swf file with JPEXS Free Flash Decompiler and you’ll see that everything we’ve done is there, check for the timeline too in the “Script => frame 1 => DoAction” file… in the end it should be something like this

 

Finally, open the folder where gfxexport is located, drag the .SFW file onto gfxexport.exe, wait a sec and it should create a .GFX file in our project directory near the .SWF file.

Now here’s the hardest part, be very attentive, take this .GFX file and put into your stream folder.
And congratulations! You just made and installed a custom scaleform in your server! Now all you have to do is call it like any other scaleform by using the name of the file with either your own method or the usual Natives.

Part 6 - What’s next

Digging and trying… i’ve found out you can actually use internal R* tools to better create your code and scaleform, for example, if you add a png file to the scaleform like this:

 

GFxExporter will strip the images and leave only red shapes (yeah the same you saw into other scaleforms) the trick is here… the exporter will take the stripped pics and turn them into .DDS files with weird naming, if you put those .DDS files into a custom .YTD file and place it near your .GFX file with the same name and bam… the scaleform will load the shapes automatically

 

If you still need to load some textures via code, then you can do it like this, there are 2 ways:

  1. Load the texture file via script (RequestStreamedTextureDict()) and then use this code to draw the texture onto a custom symbol in the CONTENT timeline
	function loadTextureIntoMovieClip(txd, texture)
	{
		var thisObj = this;
		var _loc3_ = this._componentsForLoadingImages.length + 1;
		var _loc2_ = new com.rockstargames.ui.core.BaseComponentInfo(_loc3_);
		this._componentsForLoadingImages[_loc3_] = _loc3_;
		_loc2_._depth = _loc3_ + 10;
		_loc2_._mc = this.CONTENT.yourCustomItem; // this is the symbol you created in content like a rectangle turned to symbol
		_loc2_._listener = new Object();
		_loc2_._loader.addListener(this.loaderObject._listener);
		_loc2_._listener.thisObj = thisObj;
		_loc2_._listener.componentID = _loc3_;
		_loc2_._listener.onLoadInit = function(target_mc)
		{
			var _loc2_ = this.thisObj._componentsForLoadingImages[this.componentID];
			_loc2_._loader.removeListener(_loc2_._listener);
			_loc2_._loader = null;
		};
		var _loc5_ = "img://" + txd + "/" + texture;
		_loc2_._loader.loadClip(_loc5_,_loc2_._mc);
	}
  1. Let the game do the work for you without natives using internal calls:
    com.rockstargames.ui.game.GameInterface.call(“REQUEST_TXD_AND_ADD_REF”) this will request the dictionary without using the scripts natives. Its parameters:
1. type (int) -> for generic textures use com.rockstargames.ui.game.GameInterface.GENERIC_TYPE
2. gfx file name (string) -> this is not the name of the scaleform.. but the gfx file.. if you change name to the file.. change name here!
3. txd (string) -> the dictionary of the texture to load
4. (optional) type of texture i think (string) -> it's a string that change in base of needs.. sometimes it's background for backgrounds.. for callscreen is "callscreen_thumbnail", optional in some gfxs
5. alreadyLoaded (bool) -> i think this is a way to check if the texture dict was loaded already.. dunno but it's optional in some gfxs

callback parameters ADD_TXD_REF_RESPONSE:

1. textureDict (string) -> the texture dict requested
2. success (bool) -> true if the request was succesful
3. uniqueId (int) -> not used.. sometimes this and success are inverted ADD_TXD_REF_RESPONSE(textureDict, success, uniqueID) -> ADD_TXD_REF_RESPONSE(textureDict, uniqueID, success)

The callback is called automatically and MUST be included into your scaleform code or else it won’t work… an example:

	function requestTexture(txd)
	{
		if (txd != "" && txd != undefined)
		{
com.rockstargames.ui.game.GameInterface.call("REQUEST_TXD_AND_ADD_REF",com.rockstargames.ui.game.GameInterface.GENERIC_TYPE,"TEST_7",txd);
		}
	}

	function TXD_HAS_LOADED(textureDict, success)
	{
		if (success)
		{
			if (textureDict == this._stockMenuDict)
			{
				this.loadTexture(textureDict,this._bannerTexture,this.bannerSprite);
				this.loadTexture(textureDict,this._bodyTexture,this.bodySprite);
			}
		}
	}

	function loadTexture(txd, texture, container)
	{
		var thisObj = this;
		this.loaderObject._depth = 100;
		this.loaderObject._mc = container;
		this.loaderObject._loader = new MovieClipLoader();
		this.loaderObject._height = this.loaderObject._mc._height;
		this.loaderObject._width = this.loaderObject._mc._width;
		this.loaderObject._x = this.loaderObject._mc._x;
		this.loaderObject._y = this.loaderObject._mc._y;
		this.loaderObject._listener = new Object();
		this.loaderObject._loader.addListener(this.loaderObject._listener);
		this.loaderObject._listener.thisObj = thisObj;
		this.loaderObject._listener.onLoadInit = function(target_mc)
		{
			target_mc._width = this.thisObj.loaderObject._width;
			target_mc._height = this.thisObj.loaderObject._height;
			target_mc._x = this.thisObj.loaderObject._x;
			target_mc._y = this.thisObj.loaderObject._y;
			var _loc2_ = this.thisObj.loaderObject;
			_loc2_._loader.removeListener(_loc2_._listener);
			_loc2_._loader = null;

		};
		var _loc3_ = "img://" + txd + "/" + texture;
		this.loaderObject._loader.loadClip(_loc3_,this.loaderObject._mc);
	}

 

Conclusion

credits: a HUGE thank you to @lacoL for helping me into the digging and learning Flash :smiley:

 

  • Like 4
Link to comment
Share on other sites

I also can extract tga from ugx , maybe even repack them but i don t have time, if anyone interested i can share the tools (they are very old, hard to find). But i cannot repack them, but i think it s because of my limitation.

It should not be very difficult, for someone who knows coding i think, but maybe i m wrong. 

Link to comment
Share on other sites

  • 11 months later...
  • 5 months later...

i just wish to thank you for sharing my Scaleform Guide 😄 i invite you all to join my discord guild where we talk about coding and scaleforms 😄 also.. no credits to the creator bro?? Really?? https://forum.cfx.re/t/how-to-tutorial-create-your-own-scaleform-using-flash-gfxexporter/4763644 this is where the guide was stolen 🙂 Happy to have helped someone creating scaleforms for GTA!
Here the discord invite 
KKN7kRT2vM

Edited by manups4e
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...