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.