tecs.files

Where a game reads content from and where it is allowed to write.

nupp.io.files owns every filesystem operation: reading, writing, atomic commits, directory streams, temporaries and metadata. This module keeps the one thing Nupp cannot supply, because it is a property of the product rather than of the platform: which directories belong to this game.

local disk <const> = require("nupp.io.files")

tecs.files.setPreferenceIdentity("Ex Nihilo", "Starfarer")

local slot <const> = tecs.files.writablePath("saves/slot1.json")
disk.createDirectory(tecs.files.writablePath("saves"))
local ok, reason = disk.writeAtomic(slot, bytes)

The three roots#

assetRoot is where shipped content lives and is never a place a build may write. preferencePath and cachePath are the two writable roots, and they differ in durability: saves and settings go under preferencePath, and anything the game can rebuild goes under cachePath, which the operating system may empty between any two runs.

assetPath and writablePath resolve a relative path against the first and the second. Both join without checking existence, because a path that is about to be created is as valid a request as one that is about to be read.

Identity#

setPreferenceIdentity names the publisher and the game, and the two writable roots are named from that pair. Set it before the first writable path resolves. The defaults are "tecs" and "tecs", which are what an engine test and an unnamed tool write under.

Caching#

Each root is resolved once and remembered, because resolving one asks the platform and may create a directory. reset forgets them, which a test that moves HOME between cases needs and nothing else does.

Module contents

Functions

FunctionKindDescription
assetPathfunctionResolves relative against the asset root.
assetRootfunctionReturns the root the engine reads shipped content from.
basePathfunctionReturns the directory the running executable was loaded from.
cachePathfunctionReturns the system cache directory for this game, creating it if absent.
preferenceIdentityfunctionReturns the publisher and game names the writable roots are named from.
preferencePathfunctionReturns the writable directory for this game, creating it if it is absent.
resetfunctionForgets every cached root so the next call resolves again.
setAssetRootfunctionOverrides the asset root, for a test or a tool.
setPreferenceIdentityfunctionSets the publisher and game names the writable roots are named from.
writablePathfunctionResolves relative against the writable root.

Values

ValueKindDescription
ASSET_ROOT_VARIABLEvariableRead-only.
BASE_GLOBALvariableRead-only.
CONTENT_GLOBALvariableRead-only.

Functions#

assetPathfunction#

function assetPath(relative: string): string

Resolves relative against the asset root.

Arguments

NameTypeDescription
relativestring

a path under the content root, with / separators

Returns

TypeDescription
string

the joined path, without checking that anything is there

Raises

  • when relative is empty

assetRootfunction#

function assetRoot(): string

Returns the root the engine reads shipped content from.

TECS_ASSETS wins, which is how a development run reads straight out of a build tree instead of a staged copy. Then the __tecsContent global, since a host knows the layout it installed and this is not something to sniff for. Then basePath, which is where a single-directory build puts everything.

Returns

TypeDescription
string

the root with a trailing separator

basePathfunction#

function basePath(): string

Returns the directory the running executable was loaded from.

Nupp has no portable executable path, so this answers what the host said through the __tecsBase global, then the directory of arg[0], and then an empty string. An empty answer is not a failure: it means the platform declined to say, and a caller falls back to a relative path.

Returns

TypeDescription
string

the directory with a trailing separator, or an empty string

cachePathfunction#

function cachePath(): string

Returns the system cache directory for this game, creating it if absent.

The operating system may empty this directory between any two runs, so only downloads, compiled artifacts, thumbnails and similar derived data belong here. Saves and settings belong under preferencePath.

Returns

TypeDescription
string

the directory with a trailing separator, named from the identity

Raises

  • when the platform has no cache root or the directory cannot be created

preferenceIdentityfunction#

function preferenceIdentity(): string, string

Returns the publisher and game names the writable roots are named from.

The pair starts as "tecs", "tecs" and changes when setPreferenceIdentity succeeds.

Returns

TypeDescription
string

the current publisher, studio or organization name

string

the current game or application name

preferencePathfunction#

function preferencePath(): string

Returns the writable directory for this game, creating it if it is absent.

This is where a build writes durable state. cachePath is the other writable root and holds only data the game can rebuild.

Returns

TypeDescription
string

the directory with a trailing separator, named from the identity

Raises

  • when the platform has no writable root or the directory cannot be created

resetfunction#

function reset(): nil

Forgets every cached root so the next call resolves again.

A test that moves HOME or TECS_ASSETS between cases needs this. A game does not: nothing under a running process changes where these directories are.

Returns

TypeDescription
nil

setAssetRootfunction#

function setAssetRoot(root: string): nil

Overrides the asset root, for a test or a tool.

Arguments

NameTypeDescription
rootstring

the content directory to read from, with or without a trailing separator

Returns

TypeDescription
nil

Raises

  • when root is empty

setPreferenceIdentityfunction#

function setPreferenceIdentity(organization: string, application: string): nil

Sets the publisher and game names the writable roots are named from.

Call this before the first preferencePath, writablePath or cachePath, because each root is resolved once and remembered. A later call changes which directory the next resolution answers.

Arguments

NameTypeDescription
organizationstring

the publisher, studio or organization name

applicationstring

the game or application name

Returns

TypeDescription
nil

Raises

  • when either name is empty

writablePathfunction#

function writablePath(relative: string): string

Resolves relative against the writable root.

Arguments

NameTypeDescription
relativestring

a path under the preference directory

Returns

TypeDescription
string

the joined path, without checking that anything is there

Raises

  • when relative is empty, or when the writable root cannot be resolved

Values#

ASSET_ROOT_VARIABLEvariable#

Read-only. Names the environment variable that overrides the asset root.

BASE_GLOBALvariable#

Read-only. Names the global a host sets to the directory its executable was loaded from. Nupp has no portable executable path, so a host that knows where it is says so here and basePath answers an empty string otherwise.

CONTENT_GLOBALvariable#

Read-only. Names the global a host sets to the content root it installed.