Document the new savefile format.
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user