FAForever Forums
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Login
    The current pre-release of the client ("pioneer" in the version) is only compatible to itself. So you can only play with other testers. Please be aware!

    The MOST detailed UI modding tutorial · hotkey aspect

    Scheduled Pinned Locked Moved Modding & Tools
    uimod
    5 Posts 4 Posters 979 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • I Offline
      illumination
      last edited by

      [Guide for UI modders]
      This is a tutorial for those who want to add their own hotkeys into game.
      I don't know how the original game binds keys to various actions , but the following is a way available for modders
      Firstly , we need to pay attention to this directory , for Windows , it is
      -- C:\Users\User\AppData\Local\Gas Powered Games\Supreme Commander Forged Alliance --
      And you will find a file named game.prefs here . Yes , 'prefs' is the suffix , thus you must tell your Windows which application you want to open it with. Mine is notepad ++
      This is where SUPCOM storages its user datas .
      How to access it in game ? It's a function embedded in Engine , and you can find it in
      -- SupCom\mohodata\lua\user\prefs.lua --
      You will see something named 'GetPreference' here.
      It can be found on supcom wiki , however , only such a perfunctory statement.
      'INFO: obj GetPreference(string, [default])'
      What 'GetPreference' actually does is extracting datas from game.prefs . That's why you can pass 'profile' , or 'profile.profiles' to it , as the game.prefs itself contains these tables.


      Secondly , we should notice that there is a thing called profile.current .
      It is a number , recording how many profiles you have in game.
      Emmm.....
      Is it really that simple ? Of course not.
      Another role it plays is pointing to the current profile , which is used by Player now. New profile would be added to the end of profile table , and its index is just equal to the total sum.
      So you would see these codes .

      if profile.profiles[profile.current] then
      

      As profile.current pointing to the current profile , the current profile must storaged with a index having a value of profile.current , which indicates that all the profiles are storaged in profile.profiles . You would understand the abovementioned code better if you take a look of game.prefs.


      Thirdly , take a look of this line of codes.

      profile.profiles[profile.current][fieldName] = data
      

      If you do have took a look of game.prefs , you would notice the variable called 'fieldName' .
      You can put whatever you want into this variable , even give it a value of 'asdjoiadjgrjsiofgjsdoigr' , though which won't be discerned by game.
      I'm not talking about something magical , but if you want your custom fieldName can be recognized , you need to assume that there're really a ton of lines of fixed codes somewhere you can't reach , saying 'local x = profile.userkeyaction' , or something like that , fixed , unchangeable .
      Thus if you want your codes be recognized by game , especially to put your custom hotkey into use , you must follow the specification .


      The specification I found is following:
      If you want to add your own hotkeys into game , there're two things you need to pay attention to.
      One is action, the another is category.
      Game says : There will be v.category . Then there popped out a rule for modders that if you don't have a element indexed with string 'category' in table , even if this table contains actual command , game won't recognize it.
      Category is necessary , but what value it actually holds is not important. You can say:

      local t = { action = 'rtertghfgh' , category = 'bbhhnjnjfg' }
      

      Just keep category ~= nil , and if there's no such a bbhhnjnjfg category , game will create a new one. You can press F1 to see this category printed out .


      For action , if you don't give it a string path value like
      "UI_Lua import('/mods/apimod/lib/main.lua')._print()"
      The game would remind you that unknown console command not found.
      e.g. The game won't find what is called rtertghfgh.
      But anyway , it runs successfully .
      Keep it in mind that if you don't have a action stuff while still having category , the game will crash at the beginning , because he cannot comprehend a nil value as actual path .
      And if you have both two , you can put them together into one table .
      Usually , we have another element called order , but this is not a thing decisive
      Finally , your codes look like

      local t = {	
      	action = "dxxxx", 
      	category = 'dxddx', 
      	order = 35
      	}
      

      You can add whatever you like into variable t , though they will not be discerned.
      It's also legal.

      local t = {	
      	12,34,45,67,89,90,
      	action = "dxxxx", 
      	category = 'dxddx', 
      	order = 350
      	}
      



      We are not finished yet.
      After completing table t , we need to put t into a larger table .

      local s = {t}
      

      Somewhere we can't see , game loops table s , and for each k,v in s , it loops v to know what category this v has, and what action this v refers to , and prints k as a description of the action in v .
      If you directly pass t as the result , like that

      Prefs.SetToCurrentProfile("UserKeyActions", t)
      

      Things you made won't be shown in game , as the game is attempting to loop a string value. The game would get stuck .


      Once everything set well , you should worry about the description shown out.
      The game shows index of table t in the table s as the description for the t , which is number 1 in this case.
      You can set the index as a string , but that's not convenient.
      Mine solution is :

      local keydes = import('/lua/keymap/keydescriptions.lua').keyDescriptions
      keydes[1] = 'dsdsds'
      

      Note that I said keydes[1] , not keydes['1'] , as the index is number not a string.
      Lua passes table from = rightside to = leftside as referrence , so you can call keydes[1] to modify original table , which is the one game reads datas from.
      Thus one gamemain.lua file does all the thing , no need for modders to put keydescriptions.lua into hook.


      Eventually , the hotkeys bound to custom actions are shown in currentprofile.UserKeyMap .
      Thus , even though you clear UserKeyActions , there's still referrence to the hotkey bound to the cleared one.
      Theoretically , you can make use of \lua\keymap in similar way , to achieve similar function without using UserKeyActions , you can make a try. I suggest you to do these in gamemain.lua , do not put too many files into hook to mess up your mod.

      1 Reply Last reply Reply Quote 1
      • R Offline
        Reckless_Charger
        last edited by Reckless_Charger

        You should read this old forum post (and thread including use of smartselect) :
        https://forums.faforever.com/viewtopic.php?f=40&t=8230

        I 1 Reply Last reply Reply Quote 0
        • I Offline
          illumination @Reckless_Charger
          last edited by

          @reckless_charger I know this . Mine is modifying lua , not game.prefs

          1 Reply Last reply Reply Quote 0
          • R Offline
            Reckless_Charger
            last edited by Reckless_Charger

            Yeah but link may still be useful for others and the first line of your post does say 'This is a tutorial for those who want to add their own hotkeys into game.'

            1 Reply Last reply Reply Quote 0
            • Rodimus_PrimeR Offline
              Rodimus_Prime
              last edited by

              @illumination This was a fantastic read, and I almost have my head around it. Can the integrated hotkey mod be changed in this way? For example, one of the default combinations is 'Upgrade - T3 mobile AA - T3 transport - T3 torpedo bomber'. Could I swap Transport with ASF in that combination? Or would I need to write a new mod for that new hotkey combo?

              1 Reply Last reply Reply Quote 0
              • First post
                Last post