Garry's Mod Wiki

Filesystem

This page will explain different things about Gmod's Filesystem.

This page is still being worked and is currently unfinished

Searchpaths

The Filesystem uses search paths to find all necessary files.
A search path is just a normal path to a folder with a given name like GAME
You can add custom search paths by adding them to the garrysmod/cfg/mount.cfg
You can see all search paths here or you can print them with the path command.

The LUA search path is just a redirect to the lsv, lsc or LuaMenu search path depending on your Realm.

Search order

This is how the filesystem currently searches thru the GAME path:

  • All thirdparty search paths (Including the garrysmod/workshop folder)
  • garrysmod/overrides/ folder
  • garrysmod/ folder
  • sourceengine/ folder
  • platform/ folder
  • Mounted Games
  • garrysmod/download/ folder
  • garrysmod/fallbacks folder

This is how the filesystem currently searches thru the MOD path:

  • garrysmod/overrides/ folder
  • garrysmod/ folder
  • garrysmod/fallbacks folder

garrysmod/overrides/

It seems like this search path was recently removed

The overrides folder is used by some .vpk files, and it allows you to override the results of the filesystem.
This can be useful for this like this:
You can create the folder and copy the lua folder into it and for example edit the menu.lua file without having to worry about Steam deleting your changes.

Creating the garrysmod/overrides folder can cause Issues with Gmod when you for example don't copy all Lua Files.

garrysmod/workshop/

The workshop folder only exists in the filesystem.
The workshop folder contains the content of all workshop addons that are mounted. You could create it on your drive and mess with it, but you probably shouldn't.

Performance

The Performance of the filesystem can be different for everything.
Functions like file.Exists, file.Open and file.Size internally call CBaseFileSystem::Open.
And functions like file.Time and file.IsDir use their own code.

Your goal should always be to minimize the amount of search path searched.
For example, if you try to read garrysmod.ver, you could use the GAME path, but the MOD path would be far faster.

file.Exists

file.Exists for example tries to first open the file and if it can't open it, it checks if it's a directory.
Now, if you only need to check if the file exists, you should use file.Open because it skips the directory check.

Opening files

On Windows, the filesystem performance can be a bit different because of filesystem_native.

When opening a file while filesystem_native is set to 1 and the read mode is rb it will first try to useĀ a CWin32ReadOnlyFile to open it.
If it fails, it tries to use a CStdioFile before finally returning.

The Issue with that is that it tries to open the same file two times.
The filesystem also tries to open the file for each search path, and because of that it can make a really noticeable difference if you disable filesystem_native.
Also, the more search paths you have, the bigger the performance improvement from disabling filesystem_native can be.

Functions like file.Time and file.IsDir are not affected by filesystem_native
What are the consequences of disabling filesystem_native?

Example

An Example of the Performance difference. Base Gmod with -noaddons and -noworkshop

local function RunTest() for k=1, 100 do local f = file.Open("garrysmod.ver", "rb", "GAME") if f then f:Close() end end end RunConsoleCommand("filesystem_native", "1") timer.Create("fs_test", 0.1, 10, function() if !GetConVar("filesystem_native"):GetBool() then -- Wait for filesystem_native to be enabled return end local native_start = SysTime() RunTest() local native_end = SysTime() RunConsoleCommand("filesystem_native", "0") timer.Create("fs_test", 0.1, 10, function() if GetConVar("filesystem_native"):GetBool() then -- Wait for filesystem_native to be disabled return end local no_native_start = SysTime() RunTest() local no_native_end = SysTime() print("Native: " .. native_end - native_start) print("No Native: " .. no_native_end - no_native_start) timer.Remove("fs_test") end) end)
Output:
Native: 0.029838299999994 No Native: 0.023882999999998