Sorry, I only just got the @ now due to being overwhelmed with other forum notifications. I haven’t really seen any detailed explanations of the frontend menu system so I guess I’ll start from the beginning.
Within decompiled scaleform files, the term “pausemenu” is what natives / game script call “frontend” menu as essentially, they are the same UI but the actual in game pause menu is handled by the engine whereas “frontend” is manipulated by game scripts. This can cause much confusion as scaleform makes no mention of “frontend” except for some numerical control constants whereas natives have distinct pause menu functions as well as frontend ones.
When a frontend menu is being loaded (usually when ACTIVATE_FRONTEND_MENU
is called) the game uses data loaded from the data/ui/pausemenu.xml
file to figure out what functions it will call the pausemenu/frontend scaleforms with. The pause menu version being loaded determines what “screen” will be loaded initially, what “header” to use, the flags which the scaleform and UI backend within the game engine will use, the “pause menu contexts” to initially activate and the hud colour to be used on all menu items by default.
For the example frontend shown here, everything below the SETTINGS - PLAYERS - DETAILS
bar is considered the frontend itself whereas that bar and all above is considered the “frontend header” which you control with the BEGIN_SCALEFORM_MOVIE_METHOD_ON_FRONTEND_HEADER
native. Internally, the header is just another part of the root frontend menu object and some methods you call within the frontend will call methods on the header.
A menu “screen” will specify a GFx file to load, said GFx file will contain a class that extends com.rockstargames.gtav.pauseMenuPages.PauseMenuBasePage
called the menu “page”. Like all other scaleforms, when this file is loaded, it will set the TIMELINE
variable to an instance of said class however it also calls the method LOADED_PAGE
on its 3rd level parent which will be a class that extends com.rockstargames.gtav.pauseMenu.pauseMenuItems.PauseMenuContentBase
. Only one such class exists, that being com.rockstargames.gtav.pauseMenu.PAUSE_MENU_SP_CONTENT
.
A menu “page” defines what menu “columns” to load, each column being a class that extends com.rockstargames.gtav.pauseMenu.pauseComponents.PauseMenuComponentBase
. If a column wants to take advantage of the data slot interface, it needs to contain a “model” that extends com.rockstargames.ui.components.GUIModel
which contains a “view” that extends com.rockstargames.gtav.pauseMenu.pauseMenuItems.PauseMenuViewBase
. The view is then responsible for creating instances of and arranging the "item"s contained within it. The class for said item extends com.rockstargames.gtav.pauseMenu.pauseMenuItems.PauseMenuBaseItem
.
Succinctly, a screen loads a page that contains 1 or more components that in this context are known as columns. Components that implement data slots have a model that contains an instance of a view that contains 1 or more items.
The class inheritance is very important here to understand where the data goes when you call, for example, the SET_DATA_SLOT
method as the parameters get passed down through many layers of abstraction.
The parameters to SET_DATA_SLOT
and UPDATE_SLOT
are as follows however, some item implementations also use some of these “standard” parameters.
Argument Index |
Name |
Type |
Description |
0 |
Column Index |
INT |
The column containing the slot to set the data of. |
1 |
slotIndex |
INT |
The index of slot to set the data of. |
2 |
menuID |
INT |
Used to keep track of what item of the pause menu this slot belongs to. You should use IDs from com.rockstargames.gtav.constants.PauseMenuLUT where it makes sense to do so. |
3 |
uniqueID |
INT |
Used to uniquely identify items within a view. You can really use anything you want however, integers greater than 1000 can have special functions and execute actions when clicked that you’d otherwise not want to happen so, to be safe, don’t use anything greater than 1000. |
4 |
type |
INT |
The subtype of this item. |
5 |
initialIndex |
INT |
The initial index to show in a list item. |
6 |
isSelectable |
BOOL |
A boolean controlling if the item can be selected. Unselectable items are greyed out when displayed and skipped over in navigation. |
7 onwards |
|
Any |
Additional data used by the implementation of the item. |
The process of figuring out what item implementations are used by what page gets annoying if you don’t have all the decompiled scaleform script easily searchable so I recommend you extract all actionscript from all of the scaleforms and put it into one directory you can search through. You also need to reference pausemenu.xml
but since we’ll be doing this in FiveM, you want to use the file located in your FiveM Application Data at citizen\common\data\ui\pausemenu.xml
.
I haven’t exactly got it down to a science yet but when a screen loads, it loads every <Item>
with it. If those items have their <MenuAction>
set as MENU_OPTION_ACTION_LINK
then, the screen corresponding to the <MenuUniqueId>
will also be loaded. The menu screen <depth>
tag helps in this as <depth>
= 0
screens are almost always headers, <depth>
= 1
screens are columns and <depth>
= 2
screens are context menus, the ones that contain options to kick players and such.
As an example, we’ll take a look at FE_MENU_VERSION_CORONA
. So, we go from <InitialScreen>MENU_UNIQUE_ID_HEADER_CORONA</InitialScreen>
to a <Item> <cTextId>PM_SCR_SET</cTextId> <MenuAction>MENU_OPTION_ACTION_LINK</MenuAction> <MenuUniqueId>MENU_UNIQUE_ID_CORONA_SETTINGS</MenuUniqueId> </Item>
to a <cGfxFilename>PAUSE_MENU_PAGES_CORONA</cGfxFilename>
meaning the file containing the page for the initial state of the menu version FE_MENU_VERSION_CORONA
is pause_menu_pages_corona.swf
.
The first frame of that GFx file puts an instance of com.rockstargames.gtav.pauseMenuPages.PAUSE_MENU_PAGES_CORONA
onto the TIMELINE
so that’s our page!
The setupPage
function of this page looks like this:
function setupPage()
{
super.setupPage();
this.column1 = this.addColumn("freemodeList",1,0);
this.column2 = this.addColumn("freemodeDetails",2,580);
this.column3 = this.addColumn("freemodeMap",3,580);
this.column4 = this.addColumn("mpFriendsList",4,290);
this.setupColumns(this.column1,this.column2,this.column3,this.column4);
this.setupColScroll([this.column1,this.column2,this.column3,this.column4],[true,false,false,false]);
}
The column at index 0 is an instance of the class registered as "freemodeList"
and is offset by 0
on the x-axis. Column index 1 is a "freemodeDetails"
instance offset by 580
, appearing in the 3rd column visually. Column index 2 is a "freemodeMap"
instance also appearing in the 3rd column, underneath the first component. Column index 3 is a "mpFriendsList"
instance appearing in the 2nd column visually.
These strings, internally called linkageID
s, point to whichever class is registered with Object.registerClass(linkageID, class)
. For this example, here are all referenced classes and their actual names:
"freemodeList"
→ com.rockstargames.gtav.pauseMenu.pauseComponents.PAUSE_MENU_FREE_MODE
"freemodeDetails"
→ com.rockstargames.gtav.pauseMenu.pauseComponents.PAUSE_MENU_FREEMODE_DETAILS
"freemodeMap"
→ com.rockstargames.gtav.pauseMenu.pauseComponents.PAUSE_MENU_FREEMODE_MAP
"mpFriendsList"
→ com.rockstargames.gtav.pauseMenu.pauseComponents.PAUSE_MP_MENU_FRIENDS_LIST
"freemodeListItem"
→ com.rockstargames.gtav.pauseMenu.pauseMenuItems.singleplayer.PauseMenuFreemodeItem
This is the INITIALISE
function of component for column 0:
function INITIALISE(mc)
{
// [snip]
this.model = new com.rockstargames.gtav.pauseMenu.pauseMenuItems.singleplayer.PauseMenuFreemodeModel();
this.model.createView(0,{id:0,x:0,y:0,rowSpacing:2,columnSpacing:0,container:this.CONTENT,linkage:["freemodeListItem"],visibleItems:16,selectstyle:com.rockstargames.ui.components.GUIView.SCROLL_SELECTSTYLE});
// [snip]
}
For the 0th column, that has a this.model
of com.rockstargames.gtav.pauseMenu.pauseMenuItems.singleplayer.PauseMenuFreemodeModel
with a view that uses the class registered as "freemodeListItem"
as it’s item class.
Looking into com.rockstargames.gtav.pauseMenu.pauseMenuItems.singleplayer.PauseMenuFreemodeItem
, we can finally see how the parameters we pass to SET_DATA_SLOT
actually get rendered and used!
Within said class, the function this.__get__data()
gets an array of the parameters after argument 6 and other functions refer to previously documented names of the class. The interesting stuff is within the __set__data(_d)
override. We can see that argument 7 is the itemLeftText
, argument 8 controls the verifiedMC
(verified [badge] Movie Clip) and so on.
Now that we know how to get our items to display however we want, how do we tell when the player has selected an item and most importantly which item they’ve selected? I discovered some natives through decompiled scripts to help with such which were already shared however, I’ve now also discovered where that data comes from.
When scaleform calls the game interface method LAYOUT_CHANGED
or LAYOUT_CHANGED_FOR_SCRIPT_ONLY
, the native 0x2E22FEFA0100275E
is set to true for one frame and the native 0x7E17BE53E1AAABAF
will return the 1st, 3rd and 2nd parameters to the game interface call in specifically that order. Similarly, when TRIGGER_PAUSE_MENU_EVENT
is called, the native 0xF284AC67940C6812
will return true for one frame and according to decompiled scripts, the native 0x36C1451A88A09630
should be used to get the 1st and 3rd parameters to the game interface call however, 0x7E17BE53E1AAABAF
works all the same.
0x7E17BE53E1AAABAF
's parameters are effectively:
void 0x7E17BE53E1AAABAF(int* previousMenuState, int* selectedItemMenuId, int* selectedItemUniqueId);
// previousMenuState: The previous menuState of the pause menu - 1000. The previous menuState is usually set to the menuID of the last selected item.
// selectedItemMenuId: The menuID - 1000 of the currently selected item. Is -1 if the menu state wasn't changed since the last trigger.
// selectedItemUniqueId: The uniqueID of the currently selected item.
This is of great use to us as TRIGGER_PAUSE_MENU_EVENT
will be called any time the user selects a frontend option and perhaps also when the user attempts to scroll a list item, I haven’t been able to verify such yet. Additionally, LAYOUT_CHANGE
is called any time that the selected item changes allowing us to know what the user has selected and when they’ve actually selected it.
I’ll get these properly documented when I’ve got time 
That’s all I’ve got for frontend research, let me know if something doesn’t make sense as I basically wrote all of this down over the course of a day. Perhaps an effort could be made to document all of the different components and item implementations for future use…