Text reader files
Text reader files have the file extension .zrd
, which could stand for Zipper Reader. Until 2022, I only knew of binary reader files. However, there exist text reader files, for example DefaultCtlConfig.zrd
.
Investigation (MW3)
Although it was assumed the reader files were Lisp-like from the binary reader files, the text reader files confirm this:
(
⇥ KEYS (
⇥ ⇥ (CMD_ALPHASTRIKE ⇥ keya(0x9c) ⇥ joybtn(0x6))
⇥ ⇥ (CMD_AMS_TOGGLE ⇥ keya(0x1e))
...
⇥ )
⇥ AXES (
⇥ ⇥ (Throttle ⇥ joystick(Z) ⇥ slope(-0.500000) ⇥ intercept(0.500000) ⇥ deadzone(0.050000))
⇥ ⇥ (Twist ⇥ joystick(Rz) ⇥ slope(-1.000000) ⇥ intercept(0.000000) ⇥ deadzone(0.000000))
⇥ ⇥ (Pitch ⇥ joystick(Y) ⇥ slope(1.000000) ⇥ intercept(0.000000) ⇥ deadzone(0.000000))
⇥ ⇥ (LR ⇥ joystick(X) ⇥ slope(-1.000000) ⇥ intercept(0.000000) ⇥ deadzone(0.000000))
⇥ )
)
Note that the whitespace delimiter used is a tab (indicated as ⇥ above).
There are a lot of interesting quirks with this lisp dialect. First, the whitespace delimiters are definitely tab, carriage return (CR), and line feed (LF), i.e. CR+LF don't seem to have a syntactic value. This is not unusual, but it isn't clear if a space is a valid delimiter. This also ties into the fact that strings don't seem to be quoted.
From the binary reader files, we know there are only four data types:
- Integers (i32)
- Floating-point numbers (f32, "floats")
- Strings
- Lists
Interestingly, the text reader files hint that at least mentally, there were more. For example, it seems like strings are always upper-case, and lower-case strings are symbols. This also leads to a concept of a "function" data type in the text reader, for example joybtn(0x6)
. In other Lisps, this would've been written as (joybtn 0x6)
. Also, maps/dictionaries are simply lists with implicit key-value pairs.
We don't know how the text reader files are precisely lexed. If I had to guess from binary reader files, the example above would be expressed in pseudo-JSON as follows:
[
"KEYS",
[
["CMD_ALPHASTRIKE", "keya", [0x9c], "joybtn", [0x6]],
["CMD_AMS_TOGGLE", "keya", [0x1e]],
...
],
"AXES",
[
["Throttle", "joystick", ["Z"], "slope", [-0.5], "intercept", [0.5], "deadzone", [0.05]],
["Twist", "joystick", ["Rz"], "slope", [-1.0], "intercept", [0.0], "deadzone", [0.0]],
["Pitch", "joystick", ["Y"], "slope", [1.0], "intercept", [0.0], "deadzone", [0.0]],
["LR", "joystick", ["X"], "slope", [-1.0], "intercept", [0.0], "deadzone", [0.0]]
]
]
I believe the engine has an implicit schema, in that it tries to find string values by index, and then any information/arguments it needs are retrieved from index + 1.
There are still questions. For example, what happens if we mess with the order of "AXES"? Presumably when parsing, it looks at list index 0 to figure out what to put where in already existing data structures in the engine.
Control configuration
The MechWarrior 3 engine uses DirectInput for controls. This also matches the key codes (keya
) in the DefaultCtlConfig.zrd
, they are DirectInput key codes. Below is a converter: