When the full game was released, the new file's name was called ALL.PKR, but UnPKR still worked on it, and people could pull all kinds of things out of the file. But they didn't have any way to put them back in. So they came to me and they said "you must make a RePKR program so we can change our PKR files". But while a RePKR was reasonably easy to write, making one easy to use was another thing altogether. So I didn't release anything, and people whined and bitched for months.
Then I posted the PKR format on the main THPS forum at Delphi. Over the next several weeks, three RePKR style programs were released by other people. The first one ran on the command line, so nobody liked it because they had to be able to read to use it. The second one was a nice happy graphical interface for Windows, and people liked it because it was easier to use, but it couldn't put files into the PKR unless a file with the same name was already there and the new data was no larger than the existing data. The third one could put larger files into the PKR, but it was a command line program and nobody liked it any better than the first one even if it was technically superior.
Now, I don't mean to sound arrogant here, but I'm really disappointed. I wanted to watch the community solve three major problems that I could see in the RePKR idea:
There's nothing flashy here for you to download yet. I'm more concerned with addressing the need for those three problems above to be solved. Toward this end, I have designed the PKF command language and stated some simple rules for mod distribution files.
The rules are very simple indeed. A PKR file can contain fewer files than the ALL.PKR in THPS2 came with, as clearly evidenced by DEMO.PKR in the demo. All we need to do is agree on a file extension standard: when a PKR file is complete, containing everything you need to rename it ALL.PKR and use it in THPS2, the file is of course named with a PKR extension. When the file is INCOMPLETE, and must be merged with a complete file to produce a playable data set, the file is named with the PKD extension.
Given that, we need only examine the PKR/PKD file format and define a series of commands that can be placed in a script file and used by mod developers to create distribution files automatically. The same command scripting language can be used to combine these distribution files with the ALL.PKR file for use in the game. So without further ado, let's look at the file format.
This information is followed by a series of 40-byte directory entries. The number of these entries is specified in the third field of the header, and each contains the following information:
This information is followed by a series of 48-byte file entries. The number of these entries is specified in the fourth field of the header, and each contains the following information:
From the three structures above, we can determine a few basic assumptions about the PKR/PKD file format which always hold true if the file is properly written.
Some basic C structures to represent this data are as follows:
typedef struct PK_HEAD_STRUC { char ident[4]; int unknown; // always 1 int num_dirs; int num_files; } PK_HEAD; typedef struct PK_DIR_STRUC { char path[32]; int file_offset; int file_count; } PK_DIR; typedef struct PK_FILE_STRUC { char name[32]; int unknown; // always -2 int data_offset; int data_len1; int data_len2; // always == data_len2 } PK_FILE; typedef struct PK_INDEX_STRUC { PK_HEAD head; PK_DIR *dir; PK_FILE *file; } PK_INDEX;
A useful C++ source file which implements several useful PKR/PKD functions as a class interface will be available in the near future. As of February 17, 2001 this class interface is entering the debugging and testing phase.
Given the reasonable simplicity of the format, only a few commands are really needed. After all, the only thing we ever need to say to build the PKR/PKD file is what to call the data in the index, where to get the data that goes into the file in the first place, and whether this file should be included in PKD builds. That could be handled with one simple command, in a pinch, but we're trying to make this easier -- so we'll use seven. (Trust me, it really is easier.)
Syntax: PKF {version}
{version}
A series of four decimal digits uniquely identifying the version of this standard
used to produce the file initially. These digits are not separated from one
another in any way, and appear as MMmm where MM indicates the major version and
mm indicates the minor version. A leading or trailing zero is added when either
the major or minor version consists of only a single digit, so version 1.0 of
the standard is written as 0100 and version 1.1 is written 0110.
It is considered appropriate (though not, strictly speaking, part of the standard) to follow the PKF command with a comment identifying the generating application. The format of this comment is unspecified.
Syntax: ONFAIL {action}
{action}
One of the following case-insensitive actions.
The ONFAIL activity actually takes place in only one circumstance with version 1.0 of the command language, and that circumstance is that a specified source path in the PKF file was not found. This may be extended to an ONERROR {error} {action} syntax in future versions, if the extensions warrant more complex error handling.
The IMPORT command specifies entries to be saved in PKR files, but not PKD files.
Syntax: IMPORT {name},{path}
{name}
The entry to place in the final file. All {name} parameters share the same
syntax, consisting of one or more subdirectories delimited by the slash
character / (ASCII 47), and a filename. The maximum length of the filename
is 31 characters, and the maximum length of all subdirectories is also 31
characters. This string can therefore never be more than 62 characters long.
The string is enclosed in double quote " characters (ASCII 34), and is case
sensitive, so "AUDIO" is not the same as "audio". Most notably, there is no
initial / character in the name: "/audio/" is an illegal {name} parameter. To
specify the top-level or root directory of the layout, use a pair of double
quotes with no text between them: "".
{path}
The path to the data for this entry. The path is an absolute filesystem path
enclosed within double quotes, including the drive, all subdirectories
(delimited by \ characters and NOT / characters), and the name of the file on
the local drive. If the local file indicated is a PKR or PKD file, individual
data files within it may be specified by adding a | character (ASCII 124) and
appending the {name} identifying the appropriate data file. For example, to
load audio/BONELESS09.WAV from the all.pkr file on drive C in the \THPSPC
directory, you would use a {path} parameter
of "C:\THPSPC\all.pkr|audio/BONELESS09.WAV".
Both the {name} and {path} parameters can be "wildcarded" by leaving off the final filename on both parameters to execute the command on all files and subdirectories of the specified path. If the name is left off on only one parameter, a matching name is added to the other parameter. Examples:
The EXPORT command specifies entries to be saved in both PKR and PKD files. It is primarily useful when entire directories are imported and only a few files within those directories are desired in PKD files.
Syntax: EXPORT {name}
{name}
The entry to export to the final file.
See the {name} parameter under IMPORT.
The INCLUDE command specifies entries to be saved in both PKR and PKD files. It is equivalent to executing both an IMPORT and EXPORT command on the same {name} parameter.
Syntax: INCLUDE {name},{path}
{name}
The entry to place in the final file.
See the {name} parameter under IMPORT.
{path}
The path to the data for this entry.
See the {path} parameter under IMPORT.
The EXCLUDE command specifies entries to be saved in PKR files, but not PKD files. Much like the EXPORT command, this is primarily used to fine-tune wildcarded INCLUDE statements. Executing an INCLUDE and EXCLUDE on the same {name} parameter is equivalent to the IMPORT command.
Syntax: EXCLUDE {name}
{name}
The entry to exclude from the final file.
See the {name} parameter under IMPORT.
REMOVE removes entries from the PKR layout, once again for fine-tuning wildcard imports and exports. Situations may arise in which your imported or included directories have contents you would like to leave out of saved files completely -- subdirectories or archives with backups of previous versions, for example.
Syntax: REMOVE {name}
{name}
The entry to remove in the final file.
See the {name} parameter under IMPORT.