Angband
Data Structures | Macros | Typedefs | Functions | Variables
savefile.c File Reference

Savefile loading and saving main routines. More...

#include <errno.h>
#include "angband.h"
#include "game-world.h"
#include "init.h"
#include "savefile.h"

Data Structures

struct  blockheader
struct  blockinfo

Macros

#define BUFFER_INITIAL_SIZE   1024
#define BUFFER_BLOCK_INCREMENT   1024
#define SAVEFILE_HEAD_SIZE   28
#define SAVE_U32B(v)
#define RECONSTRUCT_U32B(from)

Typedefs

typedef int(* loader_t )(void)

Functions

void note (const char *message)
 

Utility


static void sf_put (byte v)
 

Base put/get


static byte sf_get (void)
void wr_byte (byte v)
 

Accessor functions


void wr_u16b (u16b v)
void wr_s16b (s16b v)
void wr_u32b (u32b v)
void wr_s32b (s32b v)
void wr_string (const char *str)
void rd_byte (byte *ip)
void rd_u16b (u16b *ip)
void rd_s16b (s16b *ip)
void rd_u32b (u32b *ip)
void rd_s32b (s32b *ip)
void rd_string (char *str, int max)
void strip_bytes (int n)
void pad_bytes (int n)
static bool try_save (ang_file *file)
 

Savefile saving functions


bool savefile_save (const char *path)
 Attempt to save the player in a savefile.
static bool check_header (ang_file *f)
 

Savefile loading functions


static errr next_blockheader (ang_file *f, struct blockheader *b)
 Get the next block header from the savefile.
static loader_t find_loader (struct blockheader *b, const struct blockinfo *loaders)
 Find the right loader for this block, return it.
static bool load_block (ang_file *f, struct blockheader *b, loader_t loader)
 Load a given block with the given loader.
static void skip_block (ang_file *f, struct blockheader *b)
 Skip a block.
static bool try_load (ang_file *f, const struct blockinfo *loaders)
 Try to load a savefile.
static int get_desc (void)
const char * savefile_get_description (const char *path)
 Try to get the 'description' block from a savefile.
bool savefile_load (const char *path, bool cheat_death)
 Load a savefile.

Variables

static const byte savefile_magic [4] = { 83, 97, 118, 101 }
 The savefile code.
static const byte savefile_name [4] = "VNLA"
struct {
   char   name [16]
   void(*   save )(void)
   u32b   version
savers []
 Savefile saving functions.
static struct blockinfo loaders []
 Savefile loading functions.
static bytebuffer
static u32b buffer_size
static u32b buffer_pos
static u32b buffer_check
static char savefile_desc [120]

Detailed Description

Savefile loading and saving main routines.

Copyright (c) 2009 Andi Sidwell andi@.nosp@m.takk.nosp@m.aria..nosp@m.org

This work is free software; you can redistribute it and/or modify it under the terms of either:

a) the GNU General Public License as published by the Free Software Foundation, version 2, or

b) the "Angband licence": This software may be copied and distributed for educational, research, and not for profit purposes provided that this copyright and statement are included in all such copies. Other copyrights may also apply.

Macro Definition Documentation

#define BUFFER_BLOCK_INCREMENT   1024

Referenced by sf_put().

#define BUFFER_INITIAL_SIZE   1024

Referenced by try_save().

#define RECONSTRUCT_U32B (   from)
Value:
((u32b) savefile_head[from]) | \
((u32b) savefile_head[from+1] << 8) | \
((u32b) savefile_head[from+2] << 16) | \
((u32b) savefile_head[from+3] << 24);

Referenced by next_blockheader().

#define SAVE_U32B (   v)
Value:
savefile_head[pos++] = (v & 0xFF); \
savefile_head[pos++] = ((v >> 8) & 0xFF); \
savefile_head[pos++] = ((v >> 16) & 0xFF); \
savefile_head[pos++] = ((v >> 24) & 0xFF);

Referenced by try_save().

#define SAVEFILE_HEAD_SIZE   28

Referenced by next_blockheader(), and try_save().

Typedef Documentation

typedef int(* loader_t)(void)

Function Documentation

static bool check_header ( ang_file f)
static


Savefile loading functions

Check the savefile header file clearly inicates that it's a savefile

References FALSE, file_read(), savefile_magic, savefile_name, and TRUE.

Referenced by savefile_get_description(), and try_load().

static loader_t find_loader ( struct blockheader b,
const struct blockinfo loaders 
)
static

Find the right loader for this block, return it.

References i, blockinfo::loader, blockheader::name, blockinfo::name, streq, blockheader::version, and blockinfo::version.

Referenced by try_load().

static int get_desc ( void  )
static

References rd_string(), and savefile_desc.

Referenced by savefile_get_description().

static bool load_block ( ang_file f,
struct blockheader b,
loader_t  loader 
)
static

Load a given block with the given loader.

References buffer, buffer_check, buffer_pos, buffer_size, FALSE, file_read(), mem_alloc(), mem_free(), blockheader::size, and TRUE.

Referenced by savefile_get_description(), and try_load().

static errr next_blockheader ( ang_file f,
struct blockheader b 
)
static
void note ( const char *  message)
void pad_bytes ( int  n)

References wr_byte().

void rd_byte ( byte ip)
void rd_s16b ( s16b ip)
void rd_s32b ( s32b ip)

References rd_u32b().

Referenced by rd_dungeon_aux(), rd_history(), rd_misc(), and rd_player().

void rd_string ( char *  str,
int  max 
)
void rd_u16b ( u16b ip)
void rd_u32b ( u32b ip)
const char* savefile_get_description ( const char *  path)

Try to get the 'description' block from a savefile.

Try to get a description for this savefile.

Fail gracefully.

References check_header(), file_close(), file_open(), FTYPE_TEXT, get_desc(), load_block(), MODE_READ, my_strcpy(), blockheader::name, next_blockheader(), savefile_desc, skip_block(), and streq.

Referenced by list_saves().

bool savefile_load ( const char *  path,
bool  cheat_death 
)
bool savefile_save ( const char *  path)
static byte sf_get ( void  )
static

References buffer, buffer_check, buffer_pos, and buffer_size.

Referenced by rd_byte(), rd_u16b(), and rd_u32b().

static void sf_put ( byte  v)
static
static void skip_block ( ang_file f,
struct blockheader b 
)
static

Skip a block.

References file_skip(), and blockheader::size.

Referenced by savefile_get_description().

void strip_bytes ( int  n)

References rd_byte().

Referenced by rd_ignore(), and rd_player().

static bool try_load ( ang_file f,
const struct blockinfo loaders 
)
static
static bool try_save ( ang_file file)
static
void wr_byte ( byte  v)
void wr_s16b ( s16b  v)
void wr_s32b ( s32b  v)

References wr_u32b().

Referenced by wr_dungeon_aux(), wr_history(), and wr_misc().

void wr_string ( const char *  str)
void wr_u16b ( u16b  v)
void wr_u32b ( u32b  v)

Variable Documentation

byte* buffer
static
u32b buffer_check
static

Referenced by load_block(), sf_get(), sf_put(), and try_save().

u32b buffer_pos
static

Referenced by load_block(), sf_get(), sf_put(), and try_save().

u32b buffer_size
static

Referenced by load_block(), sf_get(), sf_put(), and try_save().

struct blockinfo loaders[]
static
Initial value:
{
{ "description", rd_null, 1 },
{ "rng", rd_randomizer, 1 },
{ "options", rd_options, 1 },
{ "messages", rd_messages, 1 },
{ "monster memory", rd_monster_memory, 1 },
{ "object memory", rd_object_memory, 1 },
{ "quests", rd_quests, 1 },
{ "artifacts", rd_artifacts, 1 },
{ "player", rd_player, 1 },
{ "ignore", rd_ignore, 1 },
{ "misc", rd_misc, 1 },
{ "player hp", rd_player_hp, 1 },
{ "player spells", rd_player_spells, 1 },
{ "gear", rd_gear, 1 },
{ "stores", rd_stores, 1 },
{ "dungeon", rd_dungeon, 1 },
{ "objects", rd_objects, 1 },
{ "monsters", rd_monsters, 1 },
{ "traps", rd_traps, 1 },
{ "chunks", rd_chunks, 1 },
{ "history", rd_history, 1 },
}

Savefile loading functions.

char name[16]
void(* save)(void)
char savefile_desc[120]
static
const byte savefile_magic[4] = { 83, 97, 118, 101 }
static

The savefile code.

Savefiles since ~3.1 have used a block-based system. Each savefile consists of an 8-byte header, the first four bytes of which mark this as a savefile, the second four bytes provide a variant ID.

After that, each block has the format:

  • 16-byte string giving the type of block
  • 4-byte block version
  • 4-byte block size
  • 4-byte block checksum ... data ... padding so that block is a multiple of 4 bytes

The savefile deosn't contain the version number of that game that saved it; versioning is left at the individual block level. The current code keeps a list of savefile blocks to save in savers[] below, along with their current versions.

For each block type and version, there is a loading function to load that type/version combination. For example, there may be a loader for v1 and v2 of the RNG block; these must be different functions. It has been done this way since it allows easier maintenance; after each release, you need simply remove old loaders and you will not have to disentangle lots of code with "if (version > 3)" and its like everywhere.

Savefile loading and saving is done by keeping the current block in memory, which is accessed using the wr_* and rd_* functions. This is then written out, whole, to disk, with the appropriate header.

So, if you want to make a savefile compat-breaking change, then there are a few things you should do:

  • increment the version in 'savers' below
  • add a loading function that accepts the new version (in addition to the previous loading function) to 'loaders'
  • and watch the magic happen.

TODO:

  • wr_ and rd_ should be passed a buffer to work with, rather than using the rd_ and wr_ functions with a universal buffer
  • Magic bits at beginning of savefile

Referenced by check_header(), and savefile_save().

const byte savefile_name[4] = "VNLA"
static

Referenced by check_header(), and savefile_save().

struct { ... } savers[]

Savefile saving functions.

Referenced by try_save().

u32b version

Referenced by try_save().