Thursday, March 25, 2010

Detour Serialization API

I implemented some helpers to make the Detour navmesh data serialization simpler. I chose to simplify the method I disucussed in my earlier post. A bit more for you guys to implement, but the feedback was that most people would not use my advanced features anyway. Once you get to the point of making save games and run into a problem, let me know. I try to improve the API.

Detour API Changes

This change induced a couple of API changes.

First you will notice that the init() function has changed:

    bool init(const dtNavMeshParams* params);

I simply moved the parameters to a struct, the behavior is the same. I also added a function to return the init values, so it makes easier to store the navmesh state.

Second change is in addTile():

    dtTileRef addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef = 0);

The tile coordinates are gone, they are now stored in the tile data instead. So they need to be passed to the dtCreateNavMeshData instead:

        params.tileX = tx;
params.tileY = ty;
...
if (!dtCreateNavMeshData(&params, &navData, &navDataSize))

The obscure boolean flag is gone now, and I added an enum flag instead (DT_TILE_FREE_DATA). Much more readable now.

There is new paramter too, lastRef. It can be used to put the tile at specified location and to restore the salt. This ensures that dtPolyRefs which are stored to disk will remain valid after a save game.

You will also see that removeTile() lost the coordinates too:

    bool removeTile(dtTileRef ref, unsigned char** data, int* dataSize);

The function uses tile reference to specify which tile to remove. I added a bunch of accessors to convert between tile pointers and refs and to query tiles at certain locations.

This allows to save and load tiles without loosing the navmesh state. See Sample_TileMesh::saveAll() and Sample_TileMesh::loadAll() as an example how to use this new functionality to save and load a whole dynamic navmesh state.

dtMeshHeader now has userId field too, which can be used to identify a navigation mesh, and you could load it from your resource pack instead of reading and writing the whole navmesh with your save game.

Delta State

New addition to storing navigation mesh structure, I added functionality to store just a navmesh tile state. This is useful if you change the polygon area type or flags at runtime and wish to restore that state after you have loaded your level.

First there is a function which returns the amount of space (in bytes) which is required to save the stave of the tile:

    int getTileStateSize(const dtMeshTile* tile) const;

Now that you have allocated a buffer (you may want to allocate just one buffer which is maximum of all the buffer sizes and reuse it), you can fill it with the data using following function:

    bool storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;

And the just dump that data to disk.

When you want to restore the state, just read the data and call this functions:

    bool restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);

That's it. A little less automatic than what I hoped. Save games are special, and when to store and what is so game specific that I don't want to build too much of that into the core library.

No comments:

Post a Comment