File formats

From PZwiki
Revision as of 06:32, 14 November 2013 by Fuebar (talk | contribs) (-- documentation on game file formats)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

map_sand.bin

A simple contiguous array of big-endian 32-bit integers. On loading, each integer is stored in a specific global option variable used to control things like zombie attributes and game speed, when the power will go out, etc. All the options you can set at the creation of a Sandbox game. Useful for tweaking options after you've already created your game.

Note: If the world version is < 5 (world version is read in as a big-endian 32-bit integer from map_ver.bin the same way these are), you have to leave out Temperature and Rain when reading in variables.

   int Zombies, Distribution, Survivors, Speed, DayLength, StartMonth, StartTime, WaterShut, ElecShut, Loot, Temperature, Rain;
   static class ZombieStats
   {
       static int Speed, Strength, Toughness, Transmission, Mortality, Reanimate, Cognition, Memory, Decomposition, Sight, Hearing, Smell;
   }
BigEndianBinaryReader br; // implementation left out for brevity. anything that can read four bytes in big-endian order from a file works.
Zombies = br.ReadInt32(); Distribution = br.ReadInt32(); . . . Rain = br.ReadInt32();
ZombieStats.Speed = br.ReadInt32(); . . . ZombieStats.Smell = br.ReadInt32(); // order is essential, exactly as listed above in the int declarations

If any new Sandbox options are added in you'll have to check /zombie/SandboxOptions.class (decompile it with Java Decompiler) and look at the load() function.

Example file contents:

   00 00 00 03 | 00 00 00 01 | 00 00 00 01 | 00 00 00 03
   00 00 00 05 | 00 00 00 07 | 00 00 00 01 | 00 00 00 05
   etc., total of six lines of this length

TexturePacks (.pack files)

These are the files located in /media/texturepacks/, Characters.pack, Tiles.pack, and UI.pack. Reading them is simple, the implementation will probably be 20 or 30 lines long.

Each file contains a number of 'pages' which are basically PNG images with an associated array of offset coordinates, widths, heights, and names, that are specify smaller rectangles on the PNG file that are to be copied into their own individual images. This is called a texture atlas and is a common practice in game development.

The integers in this file are little-endian, i.e. the least significant bytes come first. This is the default on my system, so no special stream reader was required, but you may have to use/write a little-endian reader if your system defaults to big-endian.

The first four bytes of the file specify a 32-bit integer, which tells you how many pages (atlas images) are located within. Every byte after this belongs to a page, and follows the structure outlined below.

   int32, length of the char[] to follow
   char[], name of this texture page
   int32, number of entries in the page
   int32, represents a boolean value, true if non-zero. Titled 'mask' in the code, honestly not sure what it does. Not necessary for extraction purposes.
[entries - outlined below]
byte[], PNG data, byte[] { 49, 45, 4E, 44, AE, 42, 60, 82, EF, BE, AD, DE } marks the end of the file, they don't have to be included in the PNG's byte array. The next page starts immediately after the byte pattern specified above.

The first entry comes immediately after the mask int32, there are as many entries as determined by the int preceding mask. You'll probably want to create a struct/class to hold the info contained in each entry, though you could do with indexed arrays as well. Each entry contains the info you need to copy the subimages out of the PNG data, and some information irrelevant to that as well. The format is most easily demonstrated with code.

   int32, length of the char[] to follow
   char[], name of this specific subtexture
   int32, x-coord of the upper left corner of this subimage on the subtexture
   int32, y-coord of the upper left corner of this subimage on the subtexture
   int32, width of the subtexture
   int32, height of the subtexture
   int32, number of pixels of transparent padding to the left of the image (i.e., x offset)
   int32, number of pixels of transparent padding on top of the image (i.e., y offset)
   int32, actual width of the subtexture, after including padding. Sometimes width + x-offset is less than this value, in which case padding is required on the right as well.
   int32, actual height of the subtexture, after including padding. Sometimes height + y-offset is less than this value, in which case padding is required at the bottom as well.

In simpler terms, the first int32 of the entry contains the length of the char array defining its name that follows it. The next eight int32s fill the values { x, y, w, h, ox, oy, fx, fy }. After the last int32 of the subtexture's entry, if we're not on the last subtexture, the following int32 will define the length of the char array defining that subtexture's name and so on.

(x, y) = offset within the entire PNG the image begins at
(w, h) = size of the image on the atlas
(ox, oy) = offset within the (fx, fy) bounds to put the upper left corner of the image we got from (x, y)
(fx, fy) = full desired size of the images, for most inventory images this is 32x32

For example, the Apple inventory item entry on the page 'ninventory0' has the following values: x = 184, y = 274, w = 28, h = 32, ox = 3, oy = 0, fx = 32, fy = 32;

So to get this image, we'd load the PNG data following these entries into memory, use some method to cut a 28x32 subtexture out of the PNG at (184, 274), and then write those pixels into a 32x32 image beginning at (3, 0).