Configuration and Data Sources
Engine-owned documentation. This page explains reusable configuration parsing, runtime settings, mounted data sources, file lookup, and cache storage. Project-specific config values and content folder policy belong to the embedding project.
Purpose
Use this page when changing how the engine reads .fomain/config data, applies command-line or sub-config overrides, mounts resource directories/packs, reads files, or stores cached resource data.
Read this together with:
- BuildWorkflow.md for configure/build entry points.
- BakingPipeline.md for resource-pack production.
- GeneratedApiAndMetadata.md for generated settings and metadata inputs.
- ClientRuntime.md, ServerRuntime.md, and Tools.md for runtime/tool consumers.
Source paths inspected
Source/Common/ConfigFile.hSource/Common/ConfigFile.cppSource/Common/Settings.hSource/Common/Settings.cppSource/Common/Settings.incSource/Common/DataSource.hSource/Common/DataSource.cppSource/Common/FileSystem.hSource/Common/FileSystem.cppSource/Common/CacheStorage.hSource/Common/CacheStorage.cppSource/Essentials/DiskFileSystem.hSource/Essentials/DiskFileSystem.cppSource/Essentials/Platform.hSource/Essentials/Platform.cppSource/Frontend/ApplicationInit.cppSource/Client/Client.cppSource/Client/Updater.cppSource/Client/ResourceManager.hSource/Client/ResourceManager.cppSource/Tools/Baker.hSource/Tools/Baker.cppSource/Tools/ConfigBaker.hSource/Tools/ConfigBaker.cppBuildTools/cmake/stages/Codegen.cmakeBuildTools/cmake/stages/ScriptsAndBaking.cmakeBuildTools/cmake/stages/Packages.cmake- related tests under
Source/Tests/
Layer map
- Config text parser —
ConfigFileparses sections, keys, values, repeated sections, optional collected content, and first-section reads. - Settings model —
Settings.incdeclares setting groups;Settings.*turns config files, command-line overrides, internal config, defaults, auto-settings, sub-configs, and resource-pack declarations intoGlobalSettings. - Data-source abstraction —
DataSourcemounts disk directories and pack files behind a uniform file-list/open interface. - File-system view —
FileSystemcombines mounted data sources, exposesFileHeader,File,FileReader, andFileCollection, and resolves file reads by path/name. - Cache storage —
CacheStoragepersists named string/data entries for reusable cache consumers. - Low-level disk access —
DiskFileSystemperforms direct disk operations below mounted engine resources.
Config parsing
Source/Common/ConfigFile.* owns syntax-level parsing. ConfigFileOption controls optional behavior:
CollectContentpreserves section content for consumers that need raw block text.ReadFirstSectionsupports workflows that only need the first section.
The parser stores owned strings internally and returns string_view values from parsed sections. Consumers must not assume those views outlive the ConfigFile instance.
Runtime settings
Source/Common/Settings.inc is the central generated-like declaration file for setting groups and individual settings. Settings.h exposes:
ResourcePackInfo— name, input directories/files, recursive flag, side flags, and baker list.SubConfigInfo— named config overlays and setting maps.GlobalSettings— combined client/server/baking/base settings with apply/save/custom-setting operations.
GlobalSettings applies input through:
ApplyConfigAtPath()andApplyConfigFile()for config files;ApplyCommandLine()for runtime/build-tool overrides;ApplyInternalConfig()for generated internal config;ApplySubConfigSection()for named overlays;ApplyDefaultSettings()andApplyAutoSettings()for engine defaults/derived values.
ConfigBaker (Source/Tools/ConfigBaker.cpp) bakes the config by re-deriving each sub-config from the root and saving every registered setting; a setting that GlobalSettings::Save() does not emit is reported as Uninitialized server/client setting <name> and fails the bake. Save() only emits settings present in _appliedSettings, which is populated from the keys of every applied config plus a fixed auto-settings allow-list seeded in the baking-mode GlobalSettings constructor. Author-tunable settings reach _appliedSettings by being enumerated in the embedding project’s config; settings that are resolved at runtime and never authored in any config (platform/build flags, monitor size, command-line/git/compatibility values, and Client.UserWritablePath) must be added to that auto-settings allow-list, or baking fails. When adding such a runtime-only engine setting to Settings.inc, register it in the auto-settings list in the same change.
Custom settings have two read shapes. Use FindCustomSetting() when missing keys are normal and should stay in the nullable pointer vocabulary. Use GetCustomSetting() only for compatibility with the historical non-null sentinel behavior: it returns the stored value when present and _emptySetting when absent.
Do not document one embedding project’s .fomain contents as universal engine behavior. Use project docs for concrete values; use this page for the engine mechanics that consume them.
Client startup has one extra resolution step for installed layouts: ResolveUserWritablePath(settings) in Source/Frontend/ApplicationInit.cpp resolves Client.UserWritablePath before the local-config cache is read. The writable-path knobs (Client.UserWritablePath, Baking.CacheResources) live in the config and sub-config, which are applied earlier, so the cache location is known without consulting the command line. The command line is then applied to the live settings exactly once, after the config, sub-config and local config, so it takes final precedence over all of them; a single pass also keeps +-append overrides (-Setting +value) from accumulating twice. That single pass logs each Set <name> to <value> override. In that log, settings whose name contains one of the masking tokens are printed as Set <name> to ***, so a credential such as Auth.WebTokenVerifySecret never appears in plaintext (server logs may be shared). The tokens are the Common.SecretSettingTokens setting (a case-insensitive substring list, default secret token password apikey), which GlobalSettings::IsSecretSettingName() reads. Command-line overrides are logged only on the final pass — after ApplyDefaultSettings() and the config file have run — so the list is already populated, and an embedding project extends it through config to cover credentials the generic tokens miss (Last Frontier sets Common.SecretSettingTokens = secret token password apikey dsn so Sentry.Dsn is masked). Empty means portable unless an INSTALLED marker sits next to the executable; * resolves through Platform::GetUserDataBase() plus Common.GameName; an explicit path is resolved directly. If the target directory or required cache/resource subdirs cannot be created, the resolver logs a warning and reverts to portable layout.
Resource packs and data sources
ResourcePackInfo describes resource-pack inputs that bakers and runtimes consume. The bake side uses BakingContext / BakerDataSource in Source/Tools/Baker.*; the runtime side uses mounted DataSource and FileSystem abstractions.
DataSource provides two built-in mount shapes:
MountDir(dir, recursive, non_cached, maybe_not_available)for disk directory resources;MountPack(dir, name, maybe_not_available)for packed resource data.
FileSystem then combines sources and offers:
AddDirSource(),AddPackSource(),AddPacksSource(), andAddCustomSource();FilterFiles(),GetAllFiles(), and existence checks;ReadFile(),ReadFileText(), andReadFileHeader();FileReaderhelpers for endian-aware binary reads.
Mount order matters for lookup behavior. When changing it, verify the runtime/tool path that owns the resource pack, not only the parser.
Installed clients keep the read-only base resources mounted from ClientResources and layer the writable resource overlay from fs_make_writable_path(UserWritablePath, ClientResources) on top in client/updater paths. The updater writes resource patches into that overlay, so current files win lookup/hash checks without modifying the install directory. Native runtime binary update paths are owned by ClientUpdater.md.
Cache storage
Source/Common/CacheStorage.* stores named binary/string cache entries behind HasEntry(), GetString(), GetData(), SetString(), SetData(), and RemoveEntry(). It is separate from resource packs: cache entries are mutable runtime/tool artifacts, while baked resources are generated from configured inputs. Client-side cache consumers resolve relative cache paths through fs_make_writable_path(UserWritablePath, CacheResources), so portable clients keep cache next to the executable and installed clients write under the per-user root.
Build and package routing
BuildTools/cmake/stages/Codegen.cmakegenerates internal config inputs used by runtime settings.BuildTools/cmake/stages/ScriptsAndBaking.cmakewires resource baking/script compilation that consumeResourcePackInfoand baking settings.BuildTools/cmake/stages/Packages.cmakepackages resources for runtime targets.Source/Tools/ConfigBaker.*bakes config resources; full bake orchestration is in BakingPipeline.md.
Tests to inspect
Focused tests for this area:
Source/Tests/Test_CacheStorage.cppSource/Tests/Test_ConfigFile.cppSource/Tests/Test_DataSource.cppSource/Tests/Test_DiskFileSystem.cppSource/Tests/Test_FileSystem.cppSource/Tests/Test_Settings.cppSource/Tests/Test_ConfigBaker.cpp
Related consumers are covered by resource, client, server, script, and baker tests listed in Testing.md.
Change routing
- Config grammar and parsed section/key behavior:
Source/Common/ConfigFile.*. - Setting groups, defaults, command-line/config/sub-config application:
Source/Common/Settings.*andSettings.inc. - Installed-client writable-root resolution:
Source/Frontend/ApplicationInit.cpp,Source/Essentials/Platform.*, andSource/Essentials/DiskFileSystem.*. - Mounted resource lookup:
Source/Common/DataSource.*andFileSystem.*. - Raw disk operations:
Source/Essentials/DiskFileSystem.*. - Runtime resource consumption:
Source/Client/ResourceManager.*plus owning runtime docs. - Resource-pack generation: BakingPipeline.md and
Source/Tools/*Baker.*.
Validation checklist
- Run the focused parser/settings/filesystem/cache tests for the changed area.
- If resource-pack shape or mount order changes, run at least one bake path and one runtime/tool consumer path.
- If command-line or sub-config behavior changes, verify the embedding project config that exercises it, but keep project-specific values in project docs.
- If packaging/resource staging changes, re-check WebDebugging.md, AndroidDebugging.md, and ClientUpdater.md as applicable.
- Update BakingPipeline.md or BuildToolsPipeline.md when build-stage ownership changes.