Anatomy of an FGD (and How to Write Your Own)
(January 7, 2018)
Since the beginning, Worldcraft has featured a "SmartEdit" mode that makes setting the properties of entities and items easier. The functions available in the SmartEdit mode are made available to Worldcraft through what it calls "Forge Game Data" files, or FGDs. (Remember that Worldcraft's original name during development was The Forge.) All Worldcraft-like editors, plus editors like TrenchBroom, support these for defining entity properties.
An FGD is simply a plain text file that defines the keyvalues and spawnflags of a particular entity. It looks complicated, but it's actually quite simple when you get down to it.
Why use FGDs?
The reasoning behind FGDs becomes obvious the moment you turn off SmartEdit:
Older editors simply display a list of keyvalues. Keyvalue names tend to be terse and more than a bit ambiguous; for this light entity, the
style keyvalue sets blinking patterns through certain number values, but which numbers mean which almost certainly requires checking a reference guide. For spawnflags, the process involves even more arbitrary numbers.
Compare with SmartEdit on:
FGDs serve a valuable function in shielding the end user from having to put in strange, arbitrary values, but why learn to write your own? After all, custom FGDs can commonly be found on the internet. If someone else has already done that work, why bother learning it yourself?
Consider two scenarios: that of a mapper on a modding team and that of someone using custom map compilers. A custom FGD defining a mod's new entities should be written to make it as easy as possible for end users (and teammates) to make maps for that mod. Similarly, if a custom compiler features new functions for lighting, visibility optimization, or other improvements, a custom FGD makes taking advantage of those new features as simple as using the built-in features.
FGDs define entities in one of three classes:
@PointClass for point entities,
@SolidClass for brush entities, and
@BaseClass for a generic class that the other two can inherit values from.
@BaseClass entities don't appear on their own, but they work the same. (Source Hammer supports a few other classes as well, including
@FilterClass. For brevity and clarity, as well as not confusing anyone writing an FGD for Quake or GoldSrc, we'll disregard these.)
Let's take a look at the definition for
worldspawn, the basic entity that all non-entity brushes belong to, as seen in
@SolidClass = worldspawn : "World entity" [ message(string) : "Map Description / Title" skyname(string) : "environment map (cl_skyname)" sounds(integer) : "CD track to play" : 1 light(integer) : "Default light level" WaveHeight(string) : "Default Wave Height" MaxRange(string) : "Max viewable distance" : "4096" chaptertitle(string) : "Chapter Title Message" startdark(choices) : "Level Fade In" : 0 = [ 0 : "No" 1 : "Yes" ] gametitle(choices) : "Display game title" : 0 = [ 0 : "No" 1 : "Yes" ] newunit(choices) : "New Level Unit" : 0 = [ 0 : "No, keep current" 1 : "Yes, clear previous levels" ] mapteams(string) : "Map Team List" defaultteam(choices) : "Default Team" : 0 = [ 0 : "Fewest Players" 1 : "First Team" ] ]
The first (and main) part of this is the entity declaration, which defines its class, name, and a short description:
@SolidClass = worldspawn : "World entity" 
worldspawn as a brush entity, with a description of "World entity". You can also specify one or more base classes with a
base() declaration. Any properties (keyvalues and spawnflags) in the base class will also appear in the classes that cite it as a base.
@SolidClass base(Targetname) = func_monsterclip : "Monster clip brush" 
func_monsterclip as a brush entity that inherits the properties of the
Targetname class, which looks like this:
@BaseClass = Targetname [ targetname(target_source) : "Name" ]
You define the entity's properties between the brackets on the end of the entity declaration. If your entity has no properties, you can leave the brackets empty. (Worldcraft's FGD parser ignores whitespace, so feel free to put as many blank lines as you want between them and their properties for ease of reading.)
Property declarations come next. They have a very similar format to the entity declaration, with the keyvalue, a property type, and a description written in that order:
message(string) : "Map Description / Title"
In this case,
message is the keyvalue,
(string) is the way the property will display in Worldcraft, and
"Map Description / Title" is the description that'll display in Worldcraft. The colon (
:) character is used as a separator in FGD files.
As you can see, the "Map Description / Title" field in Worldcraft can have text entered into it. This corresponds to the
message keyvalue in
worldspawn. There's four main types of property types:
integer is functionally identical to
string, but is reserved for numbers rather than letters. (Some editors, notably J.A.C.K., support
float for values with decimals as well as
integer, but Worldcraft doesn't support this. If you're looking for backwards compatibility, use
Keyvalues with the
choices property type require a separate set of brackets. This is perhaps the most useful of the property types, as the end user can select from clearly-labeled options rather than arbitrary numbers.
@BaseClass = RenderFxChoices [ renderfx(choices) :"Render FX" : 0 = [ 0: "Normal" 1: "Slow Pulse" 2: "Fast Pulse" 3: "Slow Wide Pulse" 4: "Fast Wide Pulse" 9: "Slow Strobe" 10: "Fast Strobe" 11: "Faster Strobe" 12: "Slow Flicker" 13: "Fast Flicker" 5: "Slow Fade Away" 6: "Fast Fade Away" 7: "Slow Become Solid" 8: "Fast Become Solid" 14: "Constant Glow" 15: "Distort" 16: "Hologram (Distort + fade)" ] ]
This defines a base class named
RenderFxChoices with a single property: a list of choices for the
renderfx keyvalue. It's important to remember the equals (=) sign when defining a list of choices.
flags property lets you define spawnflags in the same way as you define choices. These will appear in the "Flags" tab in Worldcraft. Be sure to use this only with the
spawnflags keyvalue, however; otherwise, it won't have the desired results.
Here are the spawnflags for the
Monster base class:
spawnflags(Flags) = [ 1 : "WaitTillSeen" : 0 2 : "Gag" : 0 4 : "MonsterClip" : 0 16: "Prisoner" : 0 128: "WaitForScript" : 0 256: "Pre-Disaster" : 0 512: "Fade Corpse" : 0 ]
And the resulting output:
Remember what we said earlier about the colon (
:) being used as a separator? You can define a default value for any keyvalue by appending a colon and then the value, in quotes if necessary.
wait(integer) : "delay before close, -1 stay open " : 4
This keyvalue, from the
Door base class, will automatically have a value of 4 when the end user ties this entity to a brush. Oftentimes, you'll see 0 being used as a placeholder value in spawnflags, so they don't start activated.
Summarizing FGD files
To summarize, let's go over a few basic functions of and found in FGD files:
- FGDs can only define entities and their properties, not create new ones.
- You define an entity as either a
@BaseClass(whose values can be included in another entity), a
@PointClass(for point entities), or a
@SolidClass(for brush entities).
- A keyvalue can display as either an
flags, which affect how Worldcraft displays the property.
The best way to learn the structure of an FGD is to peek through the ones included with the game, or the ones you can find on the internet. They look a lot more complicated than they really are.