Hi,
My 2 ¢
vsav
and vlog
files are written in a particular format.
!VCSK<key><payload>
where <key>
is a 2-byte (0-255) encryption key. This key is used to decode the rest of the <payload>
. The key
is encoded in two bytes c1
and c2
as
c1 = (enc_map[key & 0xF0] >> 4)
c2 = (enc_map[key & 0x0F])
where enc_map
maps a value to it’s hex character representation
0 -> 0, 1 -> 1, ..., 10 -> 'a', ..., 15 -> 'f'
Each character (8bit information) in <payload>
is written as 2 bytes. A byte of information byte
- as int
- is written as
b = byte ^ key
c1 = enc_map[(b & 0xF0) >> 4]
c2 = enc_map[(b & 0x0F)]
and c1
and c2
is written to the output stream.
To read back a byte of information, the inverse transformation is used
b1 = dec_hex(c1) << 4
b2 = (dec_hex(c2) ^ key)
byte = (c1 | c2) & 0xFF
where
dec_hex: c -> c - dec_map[c]
and dec_map
is
0x30 → 0x30, 0x31 → 0x30, …, 0x39 → 0x30
0x41 → 0x37, 0x42 → 0x37, …, 0x46 → 0x37
0x61 → 0x57, 0x62 → 0x57, …, 0x66 → 0x57
To read back the key
, the same transformation is used, with key=0x0
.
Before encryption of the <payload>
it consists of “lines” of commands, separated by an escape character 0x27
. In BNF
<payload> ::= <lines>
<lines> ::=
| <line>
| <line> 0x27 <lines>
The <line>
s as commands to be interpreted by the CommandEncoder
set on the module. To place a piece, for example, the line would be
+/<id>/<piece type>/<piece state>
where
-
<id>
is a unique integer identifier - typically the current time with millisecond precision
-
<piece type>
is all the trait types of the piece encoded
-
<piece state>
is all the trait states of the piece encoded
To add a stack, a line would be
+/<id>/stack/<board>;<x>;<y>;<piece ids>;@@<layer>
where <x>
,<y>
are coordinates in the image of the <board>
coordinate system. A move is
M/<piece id>/<new board>/<new x>/<new y>/<new over>/<old board>/<old x>/<old y>/<old over>/<player>
with the same meaning of <... board>
, <... x>
, <... y>
as above, and <... over>
is the piece ID which the moved piece is under, and <player>
is the player id of the player making the move. A move is typically followed by a state update
D/<piece id>/<new piece state>
Other module components can also add <line>
s to the save or log file. The PlayerRoster
, for example, will write player definitions.
The <piece type>
and <piece state>
above are a little tricky. Each trait (including BasicTrait
) of a piece defines a type, and possibly a state. Each traits type or state element values are written separated by ;
. The values may contain some special characters which are then escaped by a \
. The types and states of all traits are then assembled, separated by a \t' (TAB). The
\tbetween the _n_'th and _n+1_'th (counting from 0) trait is prefixed by _n_
`.
A vlog
file is essentially a vsav
file followed by a set of LOG
commands. LOG
commands are
LOG\t<other command>
Here, <other command>
is any of the commands issued by the module. For example, a chat entry is
LOG\tCHAT<text>
where <text>
is the chat message. But <other command>
can also be moves, state changes, and so on.
With this, one can write code that will generate a vlog
or vsav
file. I have a Python module for that you can find on GitLab. The module is really intended to take a PDF file containing images, one per page, and a JSON file with metadata per page (what is the image, size of image, whether to define zones, grids, regions, etc. in the image), and generate a (draft) module. When used like this, one can give a patch Python script that can manipulate the module, including adding a vsav
file generated programmatically. For a somewhat complicated example see this Afrika Korps Print’n’Play and VASSAL module. Here, I generate the image PDF via LaTeX and my package wargame_tex.
A few thoughts on the messaging format used. Clearly the message format was designed so as to facilitate low-bandwidth network communication. However, I think there are some inherent problems with the format. It is quite easily broken by data (the message Bad data
that you sometimes see in VASSAL). Also, since the entire type and state of a piece is written, and the piece constructed from that, it can cause issues with upgraded modules. That’s of course why there’s the VASSAL tool to update piece definitions. However, that only works after a vlog
or vsav
file has been loaded and traversed, which can be too late. I would suggest to use a more readily decodeable format - say JSON. To keep the network traffic down, one could simply transmit the parts of the JSON that needs updating. One could of course also use XML, but that tends to carry more overhead.
Anways, as I said in the beginning, my 2 ¢
Yours,
Christian