1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. GTA Network forum is now in archive mode.

Intro to Scaleform: Instructional Buttons

Discussion in 'Tutorials/Documentations' started by Katalina, May 22, 2017.

  1. Katalina

    Katalina Member Developer

    Messages:
    23
    Likes Received:
    26
    Joined:
    May 14, 2017
    Just as a foreward: Scaleform is BIG. It's a complicated and slow mess. Almost everything about how GTA5 and Scaleform work together is somewhere inside this decompiled code repo: https://github.com/Xaymar/Grand-Theft-Auto-5, search for unk_0x67D02A194A2FC2BD

    A few things to note as we go into Scaleform usage:
    • The bottom right corner of your screen is always 1280x720. It will stretch and scale itself to fit your screen, this tutorial will not cover the math needed to make square pixels from this mess.
    • Not all scaleforms will work, and not everything GTA5 does is possible in GTA:N at this time.
    • Scaleform is slow. It will take a *very* long time to do a lot of things. i.e.: Adding 128 instructional buttons takes 2~ seconds on an i7-6900K and will time your players out going any longer without a frame.
    • Scaleforms are globally shared. If a user opens the pause menu, your instructional button menu will be overwritten. I do not cover prevention of this.
    Now, let's get to it.

    Code:
    let sc
    
    API.onResourceStart.connect(() => {
      sc = API.requestScaleform('instructional_buttons')
      sc.CallFunction('SET_DATA_SLOT_EMPTY')
    })
    
    This is the first bit of code we need. First, the client API loads the scaleform, `instructional_buttons`, and because GTA: Network itself uses this scaleform, we have to clear it.

    You can call Scaleform functions with `scaleform.CallFunction(functionName, ...args)`, which mirrors how you do this in C++/C# with ScriptHookV and friends. In this case, we're calling SET_DATA_SLOT_EMPTY with no arguments. You'll see this more later.

    Code:
    let sc
    
    API.onResourceStart.connect(() => {
      sc = API.requestScaleform('instructional_buttons')
      sc.CallFunction('SET_DATA_SLOT_EMPTY')
     
      sc.CallFunction('SET_DATA_SLOT', 0, 100, 'Left Click')
    })
    
    Our player needs to know what side their left mouse button is on, so we'll tell them here. In this Scaleform, we can use SET_DATA_SLOT to add entries. For reference, SET_DATA_SLOT's arguments are SET_DATA_SLOT(int slot, int or string key, string text). The slot argument is the position on the bar the entry will be on. Slot 0 is farthest right, slot 1 is left of slot 0, and so on. We'll talk about the key's string argument at the end.

    Code:
    let sc
    
    API.onResourceStart.connect(() => {
      sc = API.requestScaleform('instructional_buttons')
      sc.CallFunction('SET_DATA_SLOT_EMPTY')
     
      sc.CallFunction('SET_DATA_SLOT', 0, 100, 'Left Click')
    
      sc.CallFunction('DRAW_INSTRUCTIONAL_BUTTONS', -1)
    })
    
    Second to last important call, DRAW_INSTRUCTIONAL_BUTTONS, it takes one argument, either -1 or any other number. Setting this to -1 places every button on a single line, and wraps if it's too long. Otherwise, setting this to anything else will place them all on their own lines. This might be useful in some cases.

    Examples:
    -1
    [​IMG]
    1
    [​IMG]


    Code:
    let sc
    let ready = false
    
    API.onResourceStart.connect(() => {
      sc = API.requestScaleform('instructional_buttons')
      sc.CallFunction('SET_DATA_SLOT_EMPTY')
    
      sc.CallFunction('SET_DATA_SLOT', 0, 100, 'Left Click')
    
      sc.CallFunction('DRAW_INSTRUCTIONAL_BUTTONS', -1)
      ready = true
    })
    
    API.onUpdate.connect(() => {
      if (ready) {
        API.renderScaleform(sc, 0, 0, 1280, 720)
      }
    })
    
    So and now we have a functional instructional HUD. Yaaaaay!

    Since we're rendering every frame, we use an onUpdate event handler. API.renderScaleform() takes a scaleform instance, an x, y, width, and height. the screen bounds, regardless of resolution are at 1280 wide and 720 high. Period.

    We've added a ready flag to make sure the scaleform doesn't render when it doesn't work yet, you might utilize that in other ways.

    So what do we have?
    [​IMG]

    Wooooo! May your players never be confused again!

    But WAIT KATALINA. WHAT ARE THE DATA SLOT KEYS? WHAT DO THEY MEAN?

    Here's all the numbered ones (if you still don't see the one you want, see the next block of text.)
    [​IMG]
    I don't know why these are in spanish. My locale is English. I'll study this more.

    So what do you do if you need to display a key that isn't up there? You can use arbitrary keys!
    Code:
      sc.CallFunction('SET_DATA_SLOT', 0, 't_F', 'it says F! -->')
    
    You can set the SET_DATA_SLOT key to a string of 1 or 2 characters, you *must* prefix it with t_.
    [​IMG]

    Code:
    let sc
    let ready = false
    
    API.onResourceStart.connect(() => {
      sc = API.requestScaleform('instructional_buttons')
      sc.CallFunction('SET_DATA_SLOT_EMPTY')
    
      sc.CallFunction('SET_DATA_SLOT', 0, 't_F', 't_F')
      sc.CallFunction('SET_DATA_SLOT', 1, 't_G1', 't_G1')
      sc.CallFunction('SET_DATA_SLOT', 2, 't_M', 't_M')
      sc.CallFunction('SET_DATA_SLOT', 3, 't_<a', 't_<a')
    
      sc.CallFunction('DRAW_INSTRUCTIONAL_BUTTONS', -1)
      ready = true
    })
    
    API.onUpdate.connect(() => {
      if (ready) {
        API.renderScaleform(sc, 0, 0, 1280, 720)
      }
    })
    
    Extra Resources

    You are now an Master of Instructional Buttons. An true hero!
    If you still have questions, leave a reply.
     
    Last edited: May 22, 2017
  2. Alecsander Hoppe

    Alecsander Hoppe New Member

    Messages:
    1
    Likes Received:
    0
    Joined:
    May 12, 2017
    Thank you so much.

    Tip: if you need write something bigger and custom in SET_DATA_SLOT you can use: w_ (replacing t_)

    Example:
    Code:
    sc.CallFunction('SET_DATA_SLOT', 0, 'w_ENTER', 'w_ENTER')
    Result:
    [​IMG]
     
    Last edited: Jun 26, 2017
  3. Nils Gereke

    Nils Gereke New Member

    Messages:
    1
    Likes Received:
    0
    Joined:
    Feb 26, 2017
    Is it possible for Scaleform.CallFunction(..arguments[]) to return a value?
     

Share This Page