A small (in progress) documentation of LCF formats (RPG Maker 2000/2003)


Recently I’ve been interested in reverse engineering binary formats. And since I’ve also watched some streams of RPG Maker 2000 games and thought that might be a good place to start without surprises. It wasn’t quite that easy. And understanding the existing open source implementation (EasyRPG) wasn’t that simple, due to it’s mixture of auto-generated and template heavy code.

And while I am going to refer you to some of EasyRPG’s CSV files, there are some base concepts you need to know when you try to parse them yourself.

So far, I’ve only looked at the MapTree, but to my understanding, they all use the same serialization logic. In fact, according to somebody, they use some kind of default Borland Delphi Object Dump format. But I’ve not found any good documentation of that either.

If I continue to explore this format in the future, I’ll update this post.

The name

The format is referred to as LCF, because each of the RPG Maker files start with a magic string beginning with LCF. It is generally accepted that LCF is short for “Lucifer”, which was the development name of RPG Maker 2000.

Although it could obviously also be “Lucifer C[Something] Format”, but since it just seems to be a default delphi serialization format, I’m guessing the string comes from a class name in RPG Makers code, there wouldn’t be a reason to give it a fancy format name.

Data types

Number

Numbers in the format use VLQ, or base 128. The number is read byte for byte. The last 7 bits encode the number, the first bit says if the number continues to the next byte. Here is a pseudo code implementation:

VALUE = 0
DO:
    CURRENT_BYTE = GET_NEXT_BYTE()
    VALUE = VALUE << 7
    VALUE = VALUE | (CURRENT_BYTE & 0b0111_1111)
WHILE VALUE & 0b1000_0000

And here is the EasyRPG implementation.

String

Strings are not null delimited. Instead, string values start with the length of the string in bytes.

For the encoding, the default windows codepage (GetACP) for the current locale is used. EasyRPG uses a custom table for non-windows systems.

If we look for example at the start of an RPG_RT.lmt file, it starts with:

\x0ALcfMapTree

The first byte of which is just the length of the file type afterwards, 10.

Array

Arrays start with the length of the array, directly followed by the elements. Each element starts with the index of the current element, then the actual value.

Object

Objects are segmented into segments that EasyRPG calls “chunks”. Every chunk starts with an index number, then the length of the payload, and then the payload.

This is where the CSV files from EasyRPG come in.

These CSV files describe the type, name and comments for each chunk in all the RPG Maker LCF files.

The chunks with the index 0x00 immediately end the object. They don’t have a length or payload.

Chunks can be omitted if the payload is just the default value. For example, in the map tree file, map entries (MapInfo in the csv file) can have the chunks 0x02 parentMap, 0x03 indentation (nesting level in the tree) and 0x04 type.

But the root node has no parentMap and an indentation of 0, so these are skipped and its first chunk is 0x04.

Children of the root node have the parentMap 0, which is the default and as such is also skipped. They have an indentation of 1 though, so they start with chunk 0x03.

An example, the LcfMapTree file

The RPGMaker 2K map tree contains some meta information about the maps, such as the map name, encounter rates, background music, stuff like that.

It starts with the string \x0ALcfMapTree, as a kind of magic number.

This is followed by an array of MapInfo objects.

Each entry starts with an index number, and then the chucks of MapInfo object.

At the end of the list, a new list starts, which only describes the order of the MapInfo objects in the tree. So it’s just a series of numbers, without index numbers.

After that, a single number that tells you which map is active, so the last map that was selected in the editor.

That’s the end of the file.