summaryrefslogtreecommitdiff
path: root/doc/devel/savefile
diff options
context:
space:
mode:
Diffstat (limited to 'doc/devel/savefile')
-rw-r--r--doc/devel/savefile149
1 files changed, 149 insertions, 0 deletions
diff --git a/doc/devel/savefile b/doc/devel/savefile
new file mode 100644
index 0000000..306c1ab
--- /dev/null
+++ b/doc/devel/savefile
@@ -0,0 +1,149 @@
+ SAVEFILE FORMAT
+ ---------------
+
+This document represents a work in progress. The save format described
+here will evolve before finalization for 0.8.
+
+The old save file format used a custom compressor and was very finicky
+about padding and alignment for machines that were not even in use
+anymore. It was also extremely fragile and hard for modders to extend.
+
+The new save format seeks to alleviate these problems.
+
+ GENERAL FORMAT
+ --------------
+
+All multibyte values are little-endian. There are no alignment
+restrictions inherent in the format.
+
+The save file begins with a 32-bit identifier and version number (a
+"magic number") that identifies it as a particular version of an UQM
+save file. If the format changes in a way that older versions of UQM
+cannot read it, either the identifier or the version number should
+change.
+
+The vanilla UQM system has a save number of 0x01534d55, which, if
+interpreted as a byte stream is UMS (Ur-quan Masters Save) and a
+binary 1 (version 1). Vanilla UQM reserves the tags "UMSx" for all x
+for use to evolve the core save format. Modders are encouraged, but
+not required, to also use the fourth bit as a version number.
+
+Following the 32-bit file identifier comes a series of chunks. All
+chunks have the same general format: a 32-bit tag, similar to that of
+the file as a whole, followed by a 32-bit integer specifying the size
+of the chunk, and then that many bytes of data.
+
+Bytes in a chunk tag should all be in the range 0x20-0x7E -- that is,
+they should be printable ASCII characters. Chunks are traditionally
+referred to by their tag names.
+
+Chunks whose tag has a least significant byte in the range 0x41-0x5a,
+inclusive---that is to say, whose names start with a capital
+letter---are mandatory. If you extend the set of mandatory chunks, you
+must increase the version of the file. Tags that do not start with a
+capital letter may be ignored by other versions of UQM that otherwise
+understand that data version.
+
+(Why would you want to have ignorable bits of save file? Such chunks
+may contain helpful but ancillary information. For instance, at the
+time of this writing, there is an outstanding bug that life forms are
+un-stunned if you save and load in orbit. One could add a new chunk
+that tracks the stunned status of life forms on the planet you're in
+orbit around, and just revert to the old behavior if it's not there or
+if you're running on a version without that fix. Such an ancillary
+data chunk would have a tag like "stun" or "biot".)
+
+Note also that despite being "mandatory", it is not the case that all
+chunks will be present in all save files. Different data is saved out
+depending on the situation you saved in.
+
+Unless otherwise specified, chunks may be stored in any order in the
+save file.
+
+ CHUNK INVENTORY
+ ---------------
+
+- "Summ": Summary. This chunk must come first. This chunk
+ carries the flagship configuration information and some overview
+ information that is displayed on the savegame view screen. It is of
+ variable length, because the last element of this chunk is the name
+ of the save as chosen by the user.
+
+- "GlSt": Global State. This chunk must come second, after
+ Summ. Represents most of the data in the global state structure in
+ globdata.h. BattleGroupRef is excised from this; its value is
+ computed later on.
+
+- "GmSt": Game State. This chunk must come third, after GlSt. This is
+ the gigantic bitfield that the GET_GAME_STATE macros modify. It is
+ variably-sized; excess bytes in this array will be ignored, and if
+ there are insufficient bytes in the save file, the remaining bits
+ will be initialized to zero. Modders setting extra event flags may
+ be able to import a legacy game into a sensible state by choosing
+ their defaults judiciously.
+
+- "Evts": Events. An array of values describing scripted future
+ events.
+
+- "Enct": Encounters. Details of battle groups that are pursuing you
+ through HyperSpace.
+
+- "RacQ": Available Race Queue. Which species are active in the game,
+ where they are, etc. Corresponds to avail_race_q.
+
+- "IGpQ": Interplanetary Group Queue. Battlegroup information for
+ ships in your current star system, if you're in a current star
+ system. It is currently unclear whether or not this ever needs to
+ exist, but in keeping with legacy logic, it will appear whenever you
+ are in a star system but not in the middle of an encounter.
+
+- "NpcQ": NPC Queue. Battlegroup information for ships you are in the
+ middle of encountering. This should only appear if your loaded
+ activity is "IN_ENCOUNTER" and loading the game will trigger the red
+ alert.
+
+- "ShpQ": Ship Queue. Battlegroup information for your flagship's
+ escort fleet.
+
+- "Star": Star Description. Basic indexing information to indicate
+ which star system you are in.
+
+- "Scan": Scanner Masks. This is a semi-structured tree of DWORDs that
+ represents which planetary resources have been captured or
+ removed. It is a format roughly similar to the old star info
+ statefile format (see doc/devel/statefile) but little-endianness is
+ enforced, making this chunk endian-safe where the old statefile dump
+ was not.
+
+- "BtGp": Battle Group. Defines the relevant information for all ships
+ in a given star system. This includes an "encounter ID" - randomly
+ generated fleets have an encounter ID of zero, and ones built by the
+ plot have an 32-bit identifier. Vanilla UQM reserves the first 32
+ encounter IDs for itself, and uses 15 of them (random encounter,
+ Ur-Quan Probe, Shofixti Survivor, Zoq-Fot-Pik Emissary, Unzervalt
+ Guardian, nine Melnorme Traders, and the final boss). This also
+ includes the expiration date for random encounters and which system
+ they are relevant to. Much of this information was originally stored
+ in randgrp.dat, but it has echoes in defgrp.dat as well. The data
+ here is a ragged 2D array of a slight extension of the SHIP_FRAGMENT
+ structure. There is one BtGp chunk per defined group. (Since one of
+ these is defined at game start, and the random encounter structure
+ has values that mean 'no encounter present', there should always be
+ at least two of these chunks in any save.)
+
+- "Grps": Active Battle Groups. These are IP_GROUP structures to
+ supplement the SHIP_FRAGMENTs specified in BtGp chunks. They give
+ more detailed information about the precise location and disposition
+ of each ship in the system you are either in or most recently left.
+
+ THINGS LEFT TO DO
+ -----------------
+
+The last 448 bits in GmSt probably shouldn't exist. However, we should
+not remove them from the source base (and thus the save file) until
+after other pending commits have been merged. When this happens, we
+can break out those bits into an array of DWORDs instead. The loading
+code basically ignores those GmSt bits by overwriting them while
+loading later chunks, and GmSt is an expandable array in the first
+place, so removing those final bits from the Game State array should
+be compatible in both directions.