Tribes 2 // Mod Development Handbook GitHub

The autoload system

TorqueScript has exec() and nothing else. No dependency declaration, no version constraint, no load order, no way to disable one script without deleting it. The autoload system adds all four, entirely in script, by parsing metadata out of comments.

The boot hook

scripts/autoexec/autoload_launcher.cs — 47 bytes, the whole file [support-script]:

if( !$AutoloadExecuted ) exec("autoload.cs");

It lands in the directory console_end.cs globs for user scripts [script], so it runs at the same point your mod’s entry script does. autoload.cs sits at the archive root, so it resolves as base/autoload.cs through the normal mount stack.

autoload.cs sets its own guard immediately [support-script]:

$AutoloadEnabled = true;
$AutoloadIni = "prefs/autoload.ini";
$AutoloadLog = "prefs/autoload.log";

// set a flag to prevent autoexec.cs or autoload_loader.cs from running again
$AutoloadExecuted = true;

Work that must happen later than autoexec time is deferred into a package named LoadLater [support-script].

The directive header

Metadata is written as ordinary // comments at the top of a .cs file. From support/flag_tracker.cs [support-script]:

// #name = Flag Tracking Support
// #version = 0.0.3
// #date = January 30, 2003
// #category = Support
// #author = Paul Tousignant
// #warrior = UberGuy (FT)
// #email = uberguy@tribalwar.com
// #web = http://scripts.tribalwar.com/uberguy
// #description = Provides information about flag status, events and carrier kills.
// #status = Beta
// #include = support/team_tracker.cs 0.0.4
// #include = support/events 1.0.3
// #include = support/kill_callbacks.cs

The compiler sees comments. autoload.cs opens the file with a FileObject and reads them as data.

Parsing rules

Deliberately loose [support-script]:

function script::get_directive(%this, %text)
{
    return getSubStr(firstWord(strchr(%text, "#")), 1, 10000);
}

function script::get_args(%this, %text)
{
    return trim(getSubStr(strchr(%text, "="), 1, 10000));
}
  • The directive is the first word after the first # anywhere on the line.
  • The argument is everything after the first =, trimmed.
  • So // #version = 1.0 and //#version=1.0 and ` // # version` all parse.
  • Leading blank lines are skipped, then parsing stops at the first line that is not a directive.

That last rule matters: put your whole header block at the very top, with no blank-line-then-comment gaps in the middle, or everything after the break is ignored.

The directives

Directive Effect
#autoload Load this file automatically. Without it the file is only loaded if listed in autoload.ini.
#include = <file> [minVersion] Declare a dependency, optionally with a minimum version. Repeatable.
#name Display name in the script browser
#version Parsed into version / revision / subrevision for comparison
#date Parsed into year / month / day
#author Real name
#warrior In-game player name
#credit / #credits Additional credit, repeatable — the plural is accepted because “lots of people make this typo” [support-script]
#email Repeatable; duplicates are dropped
#web Repeatable; duplicates are dropped
#description One-line summary
#status Free text — Release, Beta, etc.
#category Grouping in the script browser
#hide Hide from the script browser

#include = SELF is a special form the parser recognises [support-script]; it marks a self-dependency used by the loader’s ordering pass.

Version comparison is delegated to a versionCompare() helper, so #include = support/events 1.0.3 means at least 1.0.3.

The autoload scan

autoload::get_autoload(%filename) decides whether a file opts in [support-script]:

%fh = new FileObject();
if(!%fh.openForRead(%filename)) {  return false; }

// skip whitespace
while( (%line $= "") && (!%fh.isEOF()) )
    %line = trim(%fh.readLine());

%fh.close();
%fh.delete();

if( !stricmp(firstWord(strchr(%line, "#")), "#autoload") )
    return true; // #autoload found

return false;

Only the first non-blank line is checked. #autoload must be the first directive in the header, not merely present somewhere in it. This is the single most common reason a script “won’t autoload”.

prefs/autoload.ini

Load order and per-script enable/disable. The loader generates it with a self-documenting header [support-script]:

; Autoload (Script Manager / Preprocessor) initializations file
;
; Use this file to modify the load order of the scripts you have installed.
;
; You can deactivate a script (so it will not load) by placing a ';' at the
; beginning of the line that script is on.
;
; A script will also fail if:
;
; - it doesn't exist
; - its requirements aren't met
; - it generates a syntax error
;
; Note: a script's requirements are determined by the #include directives in
;       its autoload header.
;
; For information on the status of each script, please see the autoload.log
; file after running and/or exiting Tribes 2.
;
; Note: You can add a script to this list and it will be loaded even if it has
;       no #autoload directive in its header, provided all of its requirements
;       (if it has any) are met.

Two behaviours worth extracting from that:

  • Listing a file in the ini loads it even without #autoload — the escape hatch for scripts you did not write.
  • A ; prefix disables a line, so the ini doubles as an enable/disable switchboard.

Only .cs and .gui filenames are accepted; anything else is rejected [support-script].

Failure handling and the log

prefs/autoload.log records the outcome per script. The loader has a dedicated logger for each state [support-script]:

Logger Meaning
logAutoloadStarted Run began
logExecuted Script loaded
logReexecuted Script loaded again
logDeactivated Disabled in the ini
logDoesNotExist Filename in the ini has no file
logCannotReadAutoloadIni / logCannotWriteAutoloadIni Ini I/O failure

When a support-pack-dependent script silently does nothing, read prefs/autoload.log first. It will name the failure. That is a better first move than the console.

Failure causes, per the generated ini header: file missing, requirements not met, or a syntax error in the script.

Command-line switches

Added by the pack, parsed in DispatchLaunchMode() [support-script]:

Switch Effect
-noautoload $AutoloadEnabled = false — skip the whole system
-skipnewautoload Skip the scan for other autoloading .cs files (added 2003-12-19)

Both are useful for isolating whether a bug is yours or the library’s. They are not vanilla switches — they do nothing on an install without the pack. See Launch options.

The script class

autoload.cs defines a script object wrapping FileObject with line-oriented editing [support-script]:

Method Purpose
newScript(%filename, %isfile) Constructor
openForRead / openForWrite / close / isEOF File handling
readLine / writeLine / appendLine Line I/O
insertLine(%text, %n) / replaceLine(%text, %n) Line editing
findInFile(%text, %n) Search
replaceInFile(%search, %replace, %n) Single replace
replaceLinesInFile(%search, %replace, %start, %end) Ranged replace
getLen() Line count
getHeader() Parse the directive block
getAutoload() / requirementsMet() / requires(%file) Dependency queries
isAuthoredBy(%author) / hasEmailAddress(%e) / hasWebAddress(%w) Metadata queries
versionCompare(%text) Version test

This is a genuinely useful general-purpose file toolkit, independent of the autoload system. If you need to read or rewrite text from TorqueScript — including the save() round-trip for object field enumeration — it is already written.

Writing a script that autoloads

// #autoload
// #name = My HUD Extension
// #version = 1.0.0
// #date = July 24, 2026
// #category = HUD
// #author = Your Name
// #warrior = YourTag
// #description = Adds a thing to the HUD.
// #status = Release
// #include = support/callback.cs
// #include = support/events.cs 1.0.4

callback.add(onPlayGuiWake, myModOnPlayGuiWake);

function myModOnPlayGuiWake()
{
   
}

Checklist:

   
#autoload is the first directive Only the first non-blank line is tested
No blank lines inside the header block Parsing stops at the first non-directive line
Every dependency has an #include Otherwise load order is undefined
Version pins where behaviour matters #include = support/events.cs 1.0.4
Check prefs/autoload.log after first run It names the failure if there is one

What this costs you

Taking a support-pack dependency means your users must install support.vl2 too. For a client-side utility that is the normal expectation and the library is worth it. For a server-side gameplay mod it is an unnecessary barrier — see Scope.