Skip to content

Late Applying

Hawkmax edited this page Oct 10, 2025 · 7 revisions

Description

If String Interpolation wasn’t challenging enough, then Late Applying is for you.
Because of the varying timing of resolution, this feature can become quite complex.

When does RichJSON resolve?

Normal Apply

When reading any JSON file with raptor (including LG and RACE),
RichJson temporarily disables certain commands so they can be handled later during the Late Apply phase.

Disabled Commands:
#self, #twin, #invoke, #choose, #script, #find, #spawn, #states, #ui_root, #ui
After reading any JSON file with raptor, these commands are going to be enabled again.

Late Apply

To process Late Apply, the data struct must be resolved again.
There are two options:

1. Manually
Call the rich_json_apply function:

/// @func rich_json_apply(_struct, _add_to_cache = true, _cryptkey = FILE_CRYPT_KEY)
/// @desc Resolves RichJson expressions when contained in _struct
/// @param {struct} _struct (root struct)
/// @param {bool} _add_to_cache = true  (are files going to be cached)
/// @param {string} _cryptkey = FILE_CRYPT_KEY
/// @returns {struct} _struct
function rich_json_apply(_struct, _add_to_cache = true, _cryptkey = FILE_CRYPT_KEY) {

2. Automatically
When using the raptor instance_create function or the raptor Skin System, Late Apply happens automatically in the create event, provided by _raptorBase.

Why is it important to understand Late Apply?

Because the tricky part is that commands can be influenced by late apply commands, which can be complex sometimes.
In addition, features like Constructor and Interface also have late apply behavior, which will be covered later.

Important

The following examples are not Best Practices.
They are only intended to demonstrate possible use cases.

Example 1 Random Monsters

Before Apply

// Image you want some random looking monsters
// spider.json
{
    "sprite_index": "#asset:sprSpiderIdle_type{#choose:1,2,3,4,5}"
}

After Normal Apply

Note

The #asset command is not resolved because of the late apply command #choose

// somewhere in gml code:
var init_data = file_read_struct("monsters/spider.json");

{
    "sprite_index": "#asset:sprSpiderIdle_type{#choose:1,2,3,4,5}"
}

After Late Apply

// somewhere in gml code:
// Since instance_create automatically resolves RichJson, the spiders will get random sprites:
var spider1 = instance_create(20, 20, Spider, init_data);
var spider2 = instance_create(20, 40, Spider, init_data);
var spider3 = instance_create(20, 60, Spider, init_data);

{
    "sprite_index": _sprite id_
}

Example 2 Preprocessing

Before Apply

// Image you want to make some preprocessing
// spider.json
{
    // the function 'calculate_health_points' is initialized in the create event of the spider object
    "hp": "#self#invoke:calculate_health_points"
}

After Normal Apply

Note

#self and #invoke are late apply commands

// somewhere in gml code:
var init_data = file_read_struct("monsters/spider.json");

{
    "hp": "#self#invoke:calculate_health_points"
}

After Late Apply

// somewhere in gml code:
var spider = instance_create(20, 20, Spider, init_data);

{
    "hp": _calculated hp value_
}

Example 3 Modular Content Creation

Before Apply

// Image you have a base file and a specific monster file
// base.json
{
    "name": null,
    "hp": "#self#invoke:calculate_health_points",
    "stats_text": null
}
// spider.json
{
    "name": "Spider",
    "stats_text": "Name: {#ref:name} \n HP: {#self:hp}"
}

After Normal Apply

// somewhere in gml code:
var init_data = struct_join(
    file_read_struct("monsters/base.json"),
    file_read_struct("monsters/spider.json")
);

{
    "name": "Spider",
    "hp": "#self#invoke:calculate_health_points",
    "stats_text": "Name: Spider \n HP: {#self:hp}"
}

After Late Apply

// somewhere in gml code:
var spider = instance_create(20, 20, Spider, init_data);

{
    "name": "Spider",
    "hp": 30,
    "stats_text": "Name: Spider \n HP: 30"
}

Author’s Recommendation: next read #twin

Clone this wiki locally