LEX (File Format)/C example

From Custom Mario Kart
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
LE-CODE Logo (Vertical).png

While the specifications for LEX files have always been publicly available here on Tockdom some people expressed concerns about implementation differences when implemening LEX themselves, so we're making the LEX-related code parts from LE-CODE available here. All the code on this particular Tockdom page is under the MIT license "Copyright 2023 Wiimm & Leseratte" so there should be no licensing issues putting it into any kind of distribution, open-source or closed-source.

Structures

lex_header_t

typedef struct lex_header_t
{
    char	magic[4];	// always LEX_BIN_MAGIC
    u16		major_version;	// usually LEX_MAJOR_VERSION
    u16		minor_version;	// usually LEX_MINOR_VERSION
    u32		size;		// size of this file (header+streams)
    u32		element_off;	// offset of first lex_element_t, 32-bit aligned
}
__attribute__ ((packed)) lex_header_t;

lex_element_t

typedef struct lex_element_t
{
    u32		magic;		// identification of section
    u32		size;		// size of 'data' (this header excluded)
    u8		data[];		// section data, 32-bit aligned
}
__attribute__ ((packed)) lex_element_t;


Section-independant code

The main hook for LEX files is at 80512820, just before a track's KMP file is getting loaded. In that place we open the LEX file (if present), reset all modifications previously done (lex_file_reset), then start parsing the lex file (lex_file_parse).

    lex_ptr = open_szs_subfile(file_open_data_addr, 1, "course.lex", 0); // call to 805411fc
    lex_file_reset();
    lex_file_parse();
    set_online_time_limit_by_lex(lex_set1_data.apply_online_sec);

The lex_file_parse sets up various global variables that are then checked by other hooks around the code whenever needed (and has special handling for the cannon subsection CANN because of legacy reasons):

void lex_file_parse()


The lex_file_reset function is called every time a new track loads as well, and resets all modifications done by a LEX file so the next track starts with a clean state. The cannon speed modifications will be directly reset here, any other modifications just set a bunch of global variables to their proper state and the functions hooking into the game code will react accordingly:

void lex_file_reset()


Section-dependant code

Nearly every LEX section has dedicated hooks and code in the LE-CODE.

Dedicated code for the CANN, FEAT and CTDN sections

The FEAT section of a LEX file is a pure metadata section. LE-CODE does not contain any implementation code for this section. This section was requested by MrBean as a kind of signal to CTGP (or other distributions) which particular special features (LEX or otherwise) a track uses. The full spec of this section will eventually be put on Tockdom as well when it's fully finished; the state in progress can be found in the source code of the SZS tools.

The CANN section also has no dedicated code elsewhere, the code for the cannon speeds is already included in the parser above.

The CTDN section is not used at all in the LE-CODE, it's only useful for distributions that support the Countdown race mode. It was requested by Kazuki and you may find a proper implementation at Countdown Mode Beta8 Mod.

Dedicated code for the SET1 section

The SET1 section of a LEX file contains multiple short settings that don't really need their own section. This section will probably be extended in the future, but only in a compatible way.

As for the currently defined parameters, `START-ITEM` is only metadata that can be used by external tools, and `ITEM-POS-FACTOR` and `APPLY-ONLINE-SEC` are implemented in the LE-CODE.

ITEM-POS-FACTOR


APPLY-ONLINE-SEC


Dedicated code for other sections

The LE-CODE also has dedicated code for the HIPT section (rules on when to hide the position tracker in a race), RITP section (rules to randomize which item routes are taken by Bullet Bills and Red shells) and TEST/DEV1 sections.

Implementations for the HIPT and RITP section in LE-CODE will be added later - these are more deeply integrated with the rest of the code than I had though so that'll take some more work to extract these.

Implementations of the TEST section aren't really useful without support for Extended presence flags, so that code will also be added later.

The DEV1 section has no proper implementation - it's the section type we are using when adding new features (before defining an actual section) or for quick testing. It randomly changes whenever we need it to, and no actual released track should contain such a section.