savefile changes - part 1
This is the first of several savefile-related changes to follow later. This one is groundwork for those later changes. Remove internal compression schemes (RLECOMP and ZEROCOMP) and discard the savefile_info struct that was primarily used to convey which internal compression schemes had been in use. Relocate some struct definitions into appropriate header files for use by code to come in later changes. Remove the two struct size-related fields from version_info and from the nmakedefs_s. Instead, include a series of bytes near the beginning of the savefile, representing the size of each struct or base data type that impacts the historical savefile content. Those are referred to as the "critical bytes". (Related note: the "you" struct required two bytes, low and high, due to its size). Compare those critical bytes in a savefile against the NetHack build that is reading the savefile. This allows mismatch detection early in the savefile-reading process, and a clean exit, rather than proceeding to read nonsensical values from the file. Include some feedback on what the first mismatch was when encountering one. For arrays stored in the savefile, use loop-logic in the core to write/read the array elements one at a time, rather than in a single blob. This will be required for changes to follow later. (impacts artiexist[], artidisco[], svd.dungeons[], svl.level_info[], svl.level.locations[][], msrooms[] field of mapseen, svb.bases[], svb.disco[] objects[], svm.mvitals[], svs.spl_book[], svd.doors[], go.oracle_loc[], utrack[], wgrowtime[]) This also adds data model to the long version information. This invalidates existing save and bones files due to the changes in the information at the start of the file.
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
|
||||
#ifndef ARTIFACT_H
|
||||
#define ARTIFACT_H
|
||||
|
||||
#include "permonst.h"
|
||||
#include "prop.h"
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define SPFX_NONE 0x00000000L /* no special effects, just a bonus */
|
||||
@@ -73,5 +77,19 @@ enum invoke_prop_types {
|
||||
BLINDING_RAY
|
||||
};
|
||||
|
||||
/* artifact tracking; gift and wish imply found; it also gets set for items
|
||||
seen on the floor, in containers, and wielded or dropped by monsters */
|
||||
struct arti_info {
|
||||
Bitfield(exists, 1); /* 1 if corresponding artifact has been created */
|
||||
Bitfield(found, 1); /* 1 if artifact is known by hero to exist */
|
||||
Bitfield(gift, 1); /* 1 iff artifact was created as a prayer reward */
|
||||
Bitfield(wish, 1); /* 1 iff artifact was created via wish */
|
||||
Bitfield(named, 1); /* 1 iff artifact was made by naming an item */
|
||||
Bitfield(viadip, 1); /* 1 iff dipped long sword became Excalibur */
|
||||
Bitfield(lvldef, 1); /* 1 iff created by special level definition */
|
||||
Bitfield(bones, 1); /* 1 iff came from bones file */
|
||||
Bitfield(rndm, 1); /* 1 iff randomly generated */
|
||||
};
|
||||
|
||||
/* clang-format on */
|
||||
#endif /* ARTIFACT_H */
|
||||
|
||||
@@ -397,38 +397,6 @@
|
||||
/* # define ZLIB_COMP */ /* ZLIB for compression */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal Compression Options
|
||||
*
|
||||
* Internal compression options RLECOMP and ZEROCOMP alter the data
|
||||
* that gets written to the save file by NetHack, in contrast
|
||||
* to COMPRESS or ZLIB_COMP which compress the entire file after
|
||||
* the NetHack data is written out.
|
||||
*
|
||||
* Defining RLECOMP builds in support for internal run-length
|
||||
* compression of level structures. If RLECOMP support is included
|
||||
* it can be toggled on/off at runtime via the config file option
|
||||
* rlecomp.
|
||||
*
|
||||
* Defining ZEROCOMP builds in support for internal zero-comp
|
||||
* compression of data. If ZEROCOMP support is included it can still
|
||||
* be toggled on/off at runtime via the config file option zerocomp.
|
||||
*
|
||||
* RLECOMP and ZEROCOMP support can be included even if
|
||||
* COMPRESS or ZLIB_COMP support is included. One reason for doing
|
||||
* so would be to provide savefile read compatibility with a savefile
|
||||
* where those options were in effect. With RLECOMP and/or ZEROCOMP
|
||||
* defined, NetHack can read an rlecomp or zerocomp savefile in, yet
|
||||
* re-save without them.
|
||||
*
|
||||
* Using any compression option will create smaller bones/level/save
|
||||
* files at the cost of additional code and time.
|
||||
*/
|
||||
|
||||
/* # define INTERNAL_COMP */ /* defines both ZEROCOMP and RLECOMP */
|
||||
/* # define ZEROCOMP */ /* Support ZEROCOMP compression */
|
||||
/* # define RLECOMP */ /* Support RLECOMP compression */
|
||||
|
||||
/*
|
||||
* Data librarian. Defining DLB places most of the support files into
|
||||
* a tar-like file, thus making a neater installation. See *conf.h
|
||||
|
||||
@@ -188,66 +188,71 @@ struct linfo {
|
||||
|
||||
/* what the player knows about a single dungeon level */
|
||||
/* initialized in mklev() */
|
||||
struct mapseen_feat {
|
||||
/* feature knowledge that must be calculated from levl array */
|
||||
Bitfield(nfount, 2);
|
||||
Bitfield(nsink, 2);
|
||||
Bitfield(naltar, 2);
|
||||
Bitfield(nthrone, 2);
|
||||
|
||||
Bitfield(ngrave, 2);
|
||||
Bitfield(ntree, 2);
|
||||
Bitfield(water, 2);
|
||||
Bitfield(lava, 2);
|
||||
|
||||
Bitfield(ice, 2);
|
||||
/* calculated from rooms array */
|
||||
Bitfield(nshop, 2);
|
||||
Bitfield(ntemple, 2);
|
||||
/* altar alignment; MSA_NONE if there is more than one and
|
||||
they aren't all the same */
|
||||
Bitfield(msalign, 2);
|
||||
|
||||
Bitfield(shoptype, 5);
|
||||
};
|
||||
struct mapseen_flags {
|
||||
Bitfield(notreachable, 1); /* can't get back to this level */
|
||||
Bitfield(forgot, 1); /* player has forgotten about this level */
|
||||
Bitfield(knownbones, 1); /* player aware of bones */
|
||||
Bitfield(oracle, 1);
|
||||
Bitfield(sokosolved, 1);
|
||||
Bitfield(bigroom, 1);
|
||||
Bitfield(castle, 1);
|
||||
Bitfield(castletune, 1); /* add tune hint to castle annotation */
|
||||
|
||||
Bitfield(valley, 1);
|
||||
Bitfield(msanctum, 1);
|
||||
Bitfield(ludios, 1);
|
||||
Bitfield(roguelevel, 1);
|
||||
/* quest annotations: quest_summons is for main dungeon level
|
||||
with entry portal and is reset once quest has been finished;
|
||||
questing is for quest home (level 1) */
|
||||
Bitfield(quest_summons, 1); /* heard summons from leader */
|
||||
Bitfield(questing, 1); /* quest leader has unlocked quest stairs */
|
||||
/* "gateway to sanctum" */
|
||||
Bitfield(vibrating_square, 1); /* found vibrating square 'trap';
|
||||
* flag cleared once the msanctum
|
||||
* annotation has been added (on
|
||||
* the next dungeon level; temple
|
||||
* entered or high altar mapped) */
|
||||
Bitfield(spare1, 1); /* not used */
|
||||
};
|
||||
|
||||
struct mapseen_rooms {
|
||||
Bitfield(seen, 1);
|
||||
Bitfield(untended, 1); /* flag for shop without shk */
|
||||
};
|
||||
|
||||
typedef struct mapseen {
|
||||
struct mapseen *next; /* next map in the chain */
|
||||
branch *br; /* knows about branch via taking it in goto_level */
|
||||
d_level lev; /* corresponding dungeon level */
|
||||
struct mapseen_feat {
|
||||
/* feature knowledge that must be calculated from levl array */
|
||||
Bitfield(nfount, 2);
|
||||
Bitfield(nsink, 2);
|
||||
Bitfield(naltar, 2);
|
||||
Bitfield(nthrone, 2);
|
||||
|
||||
Bitfield(ngrave, 2);
|
||||
Bitfield(ntree, 2);
|
||||
Bitfield(water, 2);
|
||||
Bitfield(lava, 2);
|
||||
|
||||
Bitfield(ice, 2);
|
||||
/* calculated from rooms array */
|
||||
Bitfield(nshop, 2);
|
||||
Bitfield(ntemple, 2);
|
||||
/* altar alignment; MSA_NONE if there is more than one and
|
||||
they aren't all the same */
|
||||
Bitfield(msalign, 2);
|
||||
|
||||
Bitfield(shoptype, 5);
|
||||
} feat;
|
||||
struct mapseen_flags {
|
||||
Bitfield(notreachable, 1); /* can't get back to this level */
|
||||
Bitfield(forgot, 1); /* player has forgotten about this level */
|
||||
Bitfield(knownbones, 1); /* player aware of bones */
|
||||
Bitfield(oracle, 1);
|
||||
Bitfield(sokosolved, 1);
|
||||
Bitfield(bigroom, 1);
|
||||
Bitfield(castle, 1);
|
||||
Bitfield(castletune, 1); /* add tune hint to castle annotation */
|
||||
|
||||
Bitfield(valley, 1);
|
||||
Bitfield(msanctum, 1);
|
||||
Bitfield(ludios, 1);
|
||||
Bitfield(roguelevel, 1);
|
||||
/* quest annotations: quest_summons is for main dungeon level
|
||||
with entry portal and is reset once quest has been finished;
|
||||
questing is for quest home (level 1) */
|
||||
Bitfield(quest_summons, 1); /* heard summons from leader */
|
||||
Bitfield(questing, 1); /* quest leader has unlocked quest stairs */
|
||||
/* "gateway to sanctum" */
|
||||
Bitfield(vibrating_square, 1); /* found vibrating square 'trap';
|
||||
* flag cleared once the msanctum
|
||||
* annotation has been added (on
|
||||
* the next dungeon level; temple
|
||||
* entered or high altar mapped) */
|
||||
Bitfield(spare1, 1); /* not used */
|
||||
} flags;
|
||||
struct mapseen_feat feat;
|
||||
struct mapseen_flags flags;
|
||||
/* custom naming */
|
||||
char *custom;
|
||||
unsigned custom_lth;
|
||||
struct mapseen_rooms {
|
||||
Bitfield(seen, 1);
|
||||
Bitfield(untended, 1); /* flag for shop without shk */
|
||||
} msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as svr.rooms[] */
|
||||
struct mapseen_rooms msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as svr.rooms[] */
|
||||
/* dead heroes; might not have graves or ghosts */
|
||||
struct cemetery *final_resting_place; /* same as level.bonesinfo */
|
||||
} mapseen;
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ARTIFACT_H
|
||||
#include "artifact.h"
|
||||
#endif
|
||||
|
||||
/* ### alloc.c ### */
|
||||
|
||||
#if 0
|
||||
@@ -3495,6 +3499,9 @@ extern unsigned long get_current_feature_ver(void);
|
||||
extern const char *copyright_banner_line(int) NONNULL;
|
||||
extern void early_version_info(boolean);
|
||||
extern void dump_version_info(void);
|
||||
extern void store_critical_bytes(NHFILE *) NONNULLARG1;
|
||||
extern int compare_critical_bytes(NHFILE *);
|
||||
extern int get_critical_size_count(void);
|
||||
|
||||
/* ### video.c ### */
|
||||
|
||||
|
||||
@@ -357,8 +357,6 @@ struct version_info {
|
||||
unsigned long incarnation; /* actual version number */
|
||||
unsigned long feature_set; /* bitmask of config settings */
|
||||
unsigned long entity_count; /* # of monsters and objects */
|
||||
unsigned long struct_sizes1; /* size of key structs */
|
||||
unsigned long struct_sizes2; /* size of more key structs */
|
||||
};
|
||||
|
||||
struct savefile_info {
|
||||
@@ -391,8 +389,6 @@ struct nomakedefs_s {
|
||||
unsigned long version_features;
|
||||
unsigned long ignored_features;
|
||||
unsigned long version_sanity1;
|
||||
unsigned long version_sanity2;
|
||||
unsigned long version_sanity3;
|
||||
unsigned long build_time;
|
||||
};
|
||||
extern struct nomakedefs_s nomakedefs;
|
||||
|
||||
@@ -101,6 +101,11 @@ typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
/* Also provide ushort, uint, ulong */
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/* for non-negative L, calculate L * 10 + D, avoiding signed overflow;
|
||||
yields -1 if overflow would have happened;
|
||||
assumes compiler will optimize the constants */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 121
|
||||
#define EDITLEVEL 122
|
||||
|
||||
/*
|
||||
* Development status possibilities.
|
||||
|
||||
@@ -32,6 +32,8 @@ typedef union any {
|
||||
const char *a_string;
|
||||
int (*a_nfunc)(void);
|
||||
unsigned long a_mask32; /* used by status highlighting */
|
||||
int64 a_int64;
|
||||
uint64 a_uint64;
|
||||
/* add types as needed */
|
||||
} anything;
|
||||
#define ANY_P union any /* avoid typedef in prototypes
|
||||
|
||||
Reference in New Issue
Block a user