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