Forged Alliance/FAF LUA modding and load-order

Post here if you want to help developing something for FAF.

Forged Alliance/FAF LUA modding and load-order

Postby Sheeo » 16 Sep 2014, 15:05

So this is probably the biggest hurdle when starting to mod/develop Forged Alliance:

- How do you make changes to files without having to restart the game every time?

In this thread I'll explain how Forged Alliance loads files when it starts, and what to do when modding the core lua files.

FA Init

When FA starts without any command line arguments, it looks for a file called SupComDataPath.lua.

This file is a normal lua-file, that is allowed to use FA's IO operations to load directories and compressed directories (zip files) into the virtual file system.

The normal file looks like this:

Code: Select all
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\mods', '/mods')
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\maps', '/maps')
mount_dir(InitFileDir .. '\\..\\gamedata\\*.scd', '/')
mount_dir(InitFileDir .. '\\..', '/')


Where mount_contents is a helper function defined also in that file.

This loads all maps and mods in your ~\Documents\My Games\... folder, followed by the core game files that are located in compressed .scd files.

What's important to note about the load order is that if two directories contain the same file, the first one loaded takes precedence. There are ways to get around this using hooks, that I'll explain in the end.

FAF Init

FAF extends the loading mechanism of FA, by using different init-files: one for each featured mod. I'll simply explain the init_faf.lua file, and leave the rest of them to the reader.

init_faf.lua contains a whitelist of files that it allows to be loaded, this whitelist is implemented using the function "mount_dir_with_whitelist", which is just like the helper function from the normal FA init file, except for the whitelist, only allowing the named files to be loaded.

The actual loading in init_faf is done here:

Code: Select all
-- these are the classic supcom directories. They don't work with accents or other foreign characters in usernames
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\mods', '/mods')
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\maps', '/maps')

-- these are the local FAF directories. The My Games ones are only there for people with usernames that don't work in the uppder ones.
mount_contents(InitFileDir .. '\\..\\user\\My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\mods', '/mods')
mount_contents(InitFileDir .. '\\..\\user\\My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\maps', '/maps')

mount_dir_with_whitelist(InitFileDir .. '\\..\\gamedata\\', '*.nxt', '/')
mount_dir_with_whitelist(InitFileDir .. '\\..\\gamedata\\', '*.nx2', '/')

-- these are using the newly generated path from the dofile() statement at the beginning of this script
mount_dir_with_whitelist(fa_path .. '\\gamedata\\', '*.scd', '/')
mount_dir(fa_path, '/')


This also loads mods and maps, but then comes the change.

First, all .nxt compressed directories are loaded -- but only those in the whitelist. This currently includes: murderparty, labwars, avanced strategic icons and texturepack. They are loaded in alphabetical order.

Followed by .nxt files, .nx2 files are loaded. These comprise compressed directories for each subdirectory of the FA virtual file system: effects, env, loc, lua, modules, schook, projectiles, units, textures and meshes.

After all FAF-files have been loaded, the init file loads the base-game .scd files. Since these are loaded last, files that are in the FAF-directories take precedence and overshadow the base game files.

Hooking

Hooking with the FA virtual file system simply means concatenating files.

Given the following directories and load-order:

cool_mod directory containing:
/schook/lua/file.lua

FAF.scd containing
/lua/file.lua
/schook/lua/file.lua

FA.scd
/lua/file.lua

What ends up in the actual filesystem used by FA is:

/lua/file.lua = FAF.scd/lua/file.lua + cool_mod/schook/lua/file.lua + FAF.scd/schook/lua/file.lua

Where "fileA + fileB" means that fileB has been appended to fileA.

The directory that is used for hooks can be configured in the init.lua file.

Modding

So what can all this knowledge be used for?

ForgedAlliance.exe takes several useful command-line arguments, and it's even possible to make your own. An article on this can be found here: http://supcom.wikia.com/wiki/Command_line_switches.

We can use a custom init file to ease the development process. The following file init file can be used:

Code: Select all
dev_path = 'C:\\Workspace\\forged-alliance-forever-lua'

-- this imports a path file that is written by Forged Alliance Forever right before it starts the game.
dofile(InitFileDir .. '\\..\\fa_path.lua')

path = {}

local function mount_dir(dir, mountpoint)
    table.insert(path, { dir = dir, mountpoint = mountpoint } )
end

local function mount_contents(dir, mountpoint)
    LOG('checking ' .. dir)
    for _,entry in io.dir(dir .. '\\*') do
        if entry != '.' and entry != '..' then
            local mp = string.lower(entry)
            mp = string.gsub(mp, '[.]scd$', '')
            mp = string.gsub(mp, '[.]zip$', '')
            mount_dir(dir .. '\\' .. entry, mountpoint .. '/' .. mp)
        end
    end
end

-- these are the classic supcom directories. They don't work with accents or other foreign characters in usernames
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\mods', '/mods')
mount_contents(SHGetFolderPath('PERSONAL') .. 'My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\maps', '/maps')

-- these are the local FAF directories. The My Games ones are only there for people with usernames that don't work in the uppder ones.
mount_contents(InitFileDir .. '\\..\\user\\My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\mods', '/mods')
mount_contents(InitFileDir .. '\\..\\user\\My Games\\Gas Powered Games\\Supreme Commander Forged Alliance\\maps', '/maps')

mount_dir(dev_path, '/')

-- these are using the newly generated path from the dofile() statement at the beginning of this script
mount_dir(fa_path .. '\\gamedata\\*.scd', '/')
mount_dir(fa_path, '/')

hook = {
    '/schook'
}

protocols = {
    'http',
    'https',
    'mailto',
    'ventrilo',
    'teamspeak',
    'daap',
    'im',
}


At the very top there is the line: dev_path = 'C:\\Workspace\\forged-alliance-forever-lua'. That should be set to wherever the base forged-alliance lua repository has been cloned.

Starting Forged Alliance from the commandline with the following arguments:

Code: Select all
ForgedAlliance.exe /init "init_dev.lua" /EnableDiskWatch /showlog


puts it into a mode where it will look for updates to files that it has loaded. So when you modify a unit file or a blueprint, the game will re-load the file and put it into the active session.

This way, you don't need to restart the game every time you make a change -- you simply need to make a new unit of the type, spawn a new projectile or do whatever it is you're doing.

It's not perfect; some changes will require a full game restart, and certain changes can cause crashes. But it's a lot better than reloading the game for every change, every time.


Hope this helps!
Last edited by Sheeo on 17 Sep 2014, 11:36, edited 1 time in total.
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Re: Forged Alliance/FAF LUA modding and load-order

Postby nine2 » 16 Sep 2014, 16:16

Thank you, this is gold
nine2
Councillor - Promotion
 
Posts: 2416
Joined: 16 Apr 2013, 10:10
Has liked: 285 times
Been liked: 515 times
FAF User Name: Anihilnine

Re: Forged Alliance/FAF LUA modding and load-order

Postby nine2 » 09 Dec 2014, 13:49

If I add in my own .nxt file via using my own init file, it is possible to hook (concatenate) instead of replacing files completely?

I want to be able to modify files without having to copy paste the whole thing. I know this is what a mod does but I explicitly don't want to use a mod to do it.

Thanks for your time.
nine2
Councillor - Promotion
 
Posts: 2416
Joined: 16 Apr 2013, 10:10
Has liked: 285 times
Been liked: 515 times
FAF User Name: Anihilnine

Re: Forged Alliance/FAF LUA modding and load-order

Postby Sheeo » 09 Dec 2014, 13:53

partytime wrote:If I add in my own .nxt file via using my own init file, it is possible to hook (concatenate) instead of replacing files completely?

I want to be able to modify files without having to copy paste the whole thing. I know this is what a mod does but I explicitly don't want to use a mod to do it.

Thanks for your time.


Yep, just put the files into /schook, or actually, any directory in the table defined by the "hook" variable.
Support FAF on patreon: https://www.patreon.com/faf?ty=h

Peek at our continued development on github: https://github.com/FAForever
Sheeo
Councillor - Administrative
 
Posts: 1038
Joined: 17 Dec 2013, 18:57
Has liked: 109 times
Been liked: 233 times
FAF User Name: Sheeo

Re: Forged Alliance/FAF LUA modding and load-order

Postby R_Charger » 21 May 2017, 08:53

I know this topic is very old but where do the .nx5 and .nmd files fit into the loading order hierarchy (or are they not used at all)?

.nmd = nomads?
R_Charger
Avatar-of-War
 
Posts: 141
Joined: 30 Jul 2016, 16:27
Has liked: 9 times
Been liked: 14 times
FAF User Name: Reckless_Charger

Re: Forged Alliance/FAF LUA modding and load-order

Postby CookieNoob » 21 May 2017, 09:00

  • nmd files are for nomads
  • nx5 are for FAFdevelop
  • nx2 are normal FAF
  • nx4 are FAFBeta
  • ...

the other featured mods are kinda self explanatory. You can have a look at the different init files to see which file is loaded when (they are in the /bin directory of your FAF folder)
Check out the next level of maps: viewtopic.php?f=53&t=13014
For adaptivity, customizability and less clutter in the vault.
User avatar
CookieNoob
Priest
 
Posts: 477
Joined: 02 Aug 2014, 17:07
Has liked: 65 times
Been liked: 249 times
FAF User Name: CookieNoob


Return to Contributors

Who is online

Users browsing this forum: No registered users and 1 guest