Document the new savefile format.

This commit is contained in:
Michael Martin
2013-10-13 05:44:09 -07:00
parent 7138aeca64
commit 634ec1ae7d
+145
View File
@@ -0,0 +1,145 @@
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.
- "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.
- "SISF": Star Info State File. An index into which planetside
resources you have investigated and collected. See
doc/devel/statefiles for more details.
- "DGSF": Defined Group State File. Battlegroup information for
space-based encounters dictated by the plot. See
doc/devel/statefiles for more details.
- "RGSF": Random Group State File. Battlegroup information for random
encounters in interplanetary space. See doc/devel/statefiles for
more details.
THINGS LEFT TO DO BEFORE MERGING
--------------------------------
- Actually enforce little-endianness of everything that hits the disk.
- This is a simple matter of improving the read_* and write_*
functions in load.c and save.c.
- There are 448 bits in GmSt that are actually indices into DGSF. They
shouldn't be there. In fact, they shouldn't even be in the
GAME_STATE array either. They should be an array of DWORDs living
independently in the global state
- First, we should juggle the order of the state bits so that
they're all at the end. That way we can ultimately just truncate
GmSt and everything will be fine. We can do that without
complicating legacy loads much.
- The State Files are (except maybe for Star Info) a horrible mess and
we should not be replicating them in the save file. We should
instead be regenerating them from more structured forms.
- This is complicated by the fact that there are references to the
_GSF chunks in both GlSt (BattleGroupRef) and GmSt
(*_GRPOFFSET*). I have a good handle on what needs to be done to
GmSt, but the significance of the GlSt pointer still requires
research.