Virtual File System

Description

A layered virtual file system for engine + application data. It holds an ordered list of mounts; a single-file lookup returns the first mount that has the file (so an application can override an engine default by relative path), and an “enumerate all” unions across mounts. Today the only backend is DirectoryMount (a folder on disk); a PakMount (Valve-style archive) can be added later with no call-site changes, because everything goes through VirtualFileSystem instead of touching disk directly. Logical paths are forward-slash, relative to a Data root (e.g. "XML/Documents/UI.xml").

See Paths for how the mounts are set up, and Attributes & Conventions for the layering model.

API summary

MemberKindSummary
Mount(IDataMount) / MountFirst(IDataMount)staticAppend / prepend a mount (priority order).
TryResolveFile(rel, out full)staticFirst mount that has the file.
ResolveFile(rel)staticFirst mount with the file, else the primary mount’s path (write target / clear errors).
ResolveDir(relDir)staticFirst mount containing the directory.
Open(rel)staticStream from the first mount that has the file.
EnumerateAll(relDir, pattern)staticUnion of files across all mounts; first mount wins on a name clash.

IDataMount (the backend contract)

FileExists(rel) · DirExists(rel) · Open(rel)Stream · GetFullPath(rel)· Enumerate(relDir, pattern).

DirectoryMount : IDataMount

Maps logical paths onto a real folder (Root). The current (and only) backend.

Fields & Properties

private static readonly List<IDataMount> _mounts = new();   // highest priority first
public static IReadOnlyList<IDataMount> Mounts => _mounts;

Methods

Single-file lookup — first mount wins

ResolveFile / TryResolveFile / ResolveDir / Open walk the mounts in order and stop at the first that has the path. This is what lets an app override an engine-default file simply by shipping its own copy at the same relative path.

Enumeration — union across mounts

EnumerateAll concatenates every mount’s matches under relDir, de-duplicating by file name (the higher-priority mount wins). Used by directory-driven loaders — samplers, inputs, fonts — so an app inherits the engine’s defaults and adds its own.

  • Paths — mounts the application’s Data plus the engine project’s Data (fallback)
  • XML-XSD / Bootstrapper — consumers that load through the VFS