Elevdump

From ActiveWiki
Revision as of 20:22, 15 March 2021 by Chris (talk | contribs) (→‎Read Elevation Format)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

An elevdump is a file that contains the terrain data of the world. It can be used to backup and restore terrain. Together with the atdump (world attributes) and propdump (world property) it forms a complete backup of a world.

Elevdump structure

elevdump version 2

An elevdump file starts with a line containing the version number used by the SDK. There are currently two versions. Version 2 is used from 4.1.

Every line in a elevdump is a terrain node. The data in the line is seperated by spaces and tell things about the position of the node, the heights and textures used in the node. To understand what terrain nodes are and how terrain works, please see SDK Terrain for more information.

Below is an example line:

0 0 32 64 8 1 1 0 0
  • The 1st part (0) is the X coordinate of the terrain page.
  • The 2nd part (0) is the Z coordinate of the terrain page.
  • The 3rd part (32) is the X coordinate of the node, relative to its page.
  • The 4th part (64) is the Z coordinate of the node, relative to its page.
  • The 5th part (8) is the radius of the node. (multiply this by 2 to get AW_TERRAIN_NODE_SIZE.)
  • The 6th part (1) is the number of textures used in this node.
  • The 7th part (1) is the number of heights used in this node. (1 means flat node.)
  • The 8th part (0 0) contains first all texture numbers (in this case one zero) and thereafter all heights in cm.

Code Sniplets

Write Elevation Format

FILE* fp = NULL;

static void handle_terrain_result(int rc)
{
    if (!fp)
        return;

    if (rc == RC_SUCCESS && !aw_bool(AW_TERRAIN_COMPLETE))
    {
        aw_terrain_next();
        return;
    }
    if (rc != RC_SUCCESS)
    {
        // TODO: inform user about an error
    }

    if (fp)
    {
        fclose(fp);
        fp = NULL;
    }
}

static void handle_terrain_data(void)
{
    int* heights;
    unsigned short* textures;
    unsigned int    len;
    int             node_size;
    int             i;

    if (!fp)
        return;

    node_size = aw_int(AW_TERRAIN_NODE_SIZE);

    textures = (unsigned short*)aw_data(AW_TERRAIN_NODE_TEXTURES, &len);
    heights = (int*)aw_data(AW_TERRAIN_NODE_HEIGHTS, &len);

    fprintf(fp, "%d %d %d %d %d %d %d", 
            aw_int(AW_TERRAIN_PAGE_X), aw_int(AW_TERRAIN_PAGE_Z),
            aw_int(AW_TERRAIN_NODE_X), aw_int(AW_TERRAIN_NODE_Z), node_size / 2,
            aw_int(AW_TERRAIN_NODE_TEXTURE_COUNT),
            aw_int(AW_TERRAIN_NODE_HEIGHT_COUNT));

    fprintf(fp, " %d", *textures++);
    if (aw_int(AW_TERRAIN_NODE_TEXTURE_COUNT) > 1)
    {
        for (i = 1; i < 64; i++)
            fprintf(fp, " %d", *textures++);
    }

    fprintf(fp, " %d", *heights++);
    if (aw_int(AW_TERRAIN_NODE_HEIGHT_COUNT) > 1)
    {
        for (i = 1; i < 64; i++)
            fprintf(fp, " %d", *heights++);
    }

    fprintf(fp, "\n");
}

void elevdump()
{
    if (fp)
    {
        // already open
        return;
    }

    if (!(fp = fopen("elevdump.txt", "w")))
    {
        // unable to open file
        return;
    }

    fprintf(fp, "elevdump version 2\n");

    aw_callback_set(AW_CALLBACK_TERRAIN_NEXT_RESULT, handle_terrain_result);
    aw_event_set(AW_EVENT_TERRAIN_DATA, handle_terrain_data);

    aw_int_set(AW_TERRAIN_VERSION_NEEDED, 2);
    aw_int_set(AW_TERRAIN_PAGE_X, 0);
    aw_int_set(AW_TERRAIN_PAGE_Z, 0);
    aw_int_set(AW_TERRAIN_NODE_X, 0);
    aw_int_set(AW_TERRAIN_NODE_Z, 0);
    aw_int_set(AW_TERRAIN_NODE_SIZE, 0);

    aw_terrain_next();
}

Read Elevation Format

static FILE* fp = NULL;

static void load_node(void)
{
    int             rc;
    int             page_x;
    int             page_z;
    int             node_x;
    int             node_z;
    int             s;
    int             texture_count;
    int             height_count;
    int             val;
    int             i;

    unsigned short  textures[64];
    int             heights[64];

    if (!fp)
        return;

    rc = fscanf(fp, "%d %d %d %d %d %d %d",
                &page_x, &page_z,
                &node_x, &node_z, &s,
                &texture_count, &height_count);
    if (rc == EOF)
    {
        fclose(fp);
        fp = NULL;
        return;
    }

    if (texture_count < 0 || texture_count > 64 ||
        height_count < 0 || height_count > 64)
    {
        fclose(fp);
        fp = NULL;
        // TODO: inform user about invalid format
        return;
    }

    for (i = 0; i < texture_count; i++)
    {
        fscanf(fp, "%d", &val);
        textures[i] = (unsigned short)val;
    }
    for (i = 0; i < height_count; i++)
    {
        fscanf(fp, "%d", &val);
        if (server_build() >= MIN_WORLD_BUILD_TERRAIN_V2)
            heights[i] = val;
    }

    aw_int_set(AW_TERRAIN_PAGE_X, page_x);
    aw_int_set(AW_TERRAIN_PAGE_Z, page_z);
    aw_int_set(AW_TERRAIN_NODE_X, node_x);
    aw_int_set(AW_TERRAIN_NODE_Z, node_z);
    aw_int_set(AW_TERRAIN_NODE_SIZE, s * 2);
    aw_int_set(AW_TERRAIN_NODE_TEXTURE_COUNT, texture_count);
    aw_int_set(AW_TERRAIN_NODE_HEIGHT_COUNT, height_count);

    aw_data_set(AW_TERRAIN_NODE_TEXTURES, (char*)textures,
                texture_count * sizeof(unsigned short));
    aw_data_set(AW_TERRAIN_NODE_HEIGHTS, (char*)heights,
                height_count * sizeof(int));

    if (rc = aw_terrain_load_node())
    {
        fclose(fp);
        fp = NULL;
        // TODO: inform user about an error
    }
}

static void handle_node_result(int rc)
{
    if (!fp)
        return;

    if (rc == RC_SUCCESS)
        load_node();
    else
    {
        //TODO: inform user about an error
        if (fp)
        {
            fclose(fp);
            fp = NULL;
        }
    }
}

void elevload(void)
{
    int           rc;

    if (fp)
    {
        // already open;
        return;
    }

    fp = fopen("elevdump.txt", "r");
    if (fscanf(fp, "elevdump version %d", &version) != 1 || version != 2)
    {
        // invalid format
        fclose(fp);
        fp = NULL;
        return;
    }

    aw_callback_set(AW_CALLBACK_TERRAIN_DELETE_ALL_RESULT, NULL);
    if (rc = aw_terrain_delete_all())
    {
        // deleting old terrain failed
        fclose(fp);
        fp = NULL;
        return;
    }

    aw_callback_set(AW_CALLBACK_TERRAIN_LOAD_NODE_RESULT, handle_node_result);
    load_node();
}

See Also