tools/eupak: rename "pmdl" in eupak create to europa-prerelease

This more accurately reflects that it was used during development; art was probably the earliest part of the game to be finished, therefore there are lots of leftovers of older formats. Henceforth why the game can parse them.
This commit is contained in:
Lily Tsuru 2025-01-16 01:41:05 -05:00
parent ecca00a708
commit 4c2bda9fbf
2 changed files with 40 additions and 42 deletions

View file

@ -83,8 +83,7 @@ namespace eupak::tasks {
}; };
std::optional<estructs::PakVersion> ParsePakVersion(const std::string& str) { std::optional<estructs::PakVersion> ParsePakVersion(const std::string& str) {
// FIXME: PMDL should be "starfighter-prerelease" if(str == "europa-prerelease") {
if(str == "pmdl") {
return estructs::PakVersion::Ver3; return estructs::PakVersion::Ver3;
} else if(str == "starfighter") { } else if(str == "starfighter") {
return estructs::PakVersion::Ver4; return estructs::PakVersion::Ver4;
@ -107,7 +106,7 @@ namespace eupak::tasks {
parser.add_argument("-V", "--archive-version") parser.add_argument("-V", "--archive-version")
.default_value("starfighter") .default_value("starfighter")
.help(R"(Output archive version. Either "pmdl", "starfighter" or "jedistarfighter".)") .help(R"(Output archive version. Either "europa-prerelease", "starfighter" or "jedistarfighter".)")
.metavar("VERSION"); .metavar("VERSION");
parser.add_argument("-s", "--sector-aligned") parser.add_argument("-s", "--sector-aligned")
@ -124,9 +123,17 @@ namespace eupak::tasks {
.default_value(false) .default_value(false)
.implicit_value(true); .implicit_value(true);
// FIXME: At some point for accurate rebuilds we should also accept a JSON manifest file // FIXME: At some point for bit-accurate rebuilds we should also accept a JSON manifest file
// that contains: Package version, sector alignment, package build time, order of all files (as original) and their modtime, so on. // that contains:
// Then a user can just do `eupak create --manifest manifest.json` and it'll all be figured out // - Package version,
// - sector alignment (for v5),
// - package build time,
// - data order of all files
// - TOC order of all files
// - file TOC data (modtime, TOC index, so on)
// Then a user can just do `eupak create --manifest manifest.json` and it'll all be done for them
//
// `eupak extract` should optionally generate this manifest for the user
// (I have not dreamt up the schema for this yet and this relies on other FIXMEs being done so this will have to wait.) // (I have not dreamt up the schema for this yet and this relies on other FIXMEs being done so this will have to wait.)
// clang-format on // clang-format on
@ -141,11 +148,9 @@ namespace eupak::tasks {
} }
int CreateTask::Parse() { int CreateTask::Parse() {
auto& args = currentArgs; currentArgs.verbose = parser.get<bool>("--verbose");
currentArgs.inputDirectory = fs::path(parser.get("--directory"));
args.verbose = parser.get<bool>("--verbose"); currentArgs.outputFile = fs::path(parser.get("output"));
args.inputDirectory = fs::path(parser.get("--directory"));
args.outputFile = fs::path(parser.get("output"));
if(parser.is_used("--archive-version")) { if(parser.is_used("--archive-version")) {
const auto& versionStr = parser.get("--archive-version"); const auto& versionStr = parser.get("--archive-version");
@ -157,18 +162,18 @@ namespace eupak::tasks {
return 1; return 1;
} }
} else { } else {
args.pakVersion = estructs::PakVersion::Ver4; currentArgs.pakVersion = estructs::PakVersion::Ver4;
} }
args.sectorAligned = parser.get<bool>("--sector-aligned"); currentArgs.sectorAligned = parser.get<bool>("--sector-aligned");
if(args.sectorAligned && args.pakVersion != estructs::PakVersion::Ver5) { if(currentArgs.sectorAligned && currentArgs.pakVersion != estructs::PakVersion::Ver5) {
std::cout << "Error: --sector-aligned is only valid for creating a package with \"-V jedistarfighter\".\n" std::cout << "Error: --sector-aligned is only valid for creating a package with \"-V jedistarfighter\".\n"
<< parser; << parser;
return 1; return 1;
} }
if(!eupak::fs::is_directory(args.inputDirectory)) { if(!eupak::fs::is_directory(currentArgs.inputDirectory)) {
std::cout << "Error: Provided input isn't a directory\n" std::cout << "Error: Provided input isn't a directory\n"
<< parser; << parser;
return 1; return 1;
@ -178,22 +183,19 @@ namespace eupak::tasks {
} }
int CreateTask::Run() { int CreateTask::Run() {
// we should not be modifying arguments past this point
const auto& args = currentArgs;
auto currFile = 0; auto currFile = 0;
auto fileCount = 0; auto fileCount = 0;
// Count how many files we're gonna add to the archive // Count how many files we're gonna add to the archive
for(auto& ent : fs::recursive_directory_iterator(args.inputDirectory)) { for(auto& ent : fs::recursive_directory_iterator(currentArgs.inputDirectory)) {
if(ent.is_directory()) if(ent.is_directory())
continue; continue;
fileCount++; fileCount++;
} }
std::cout << "Going to write " << fileCount << " files into " << args.outputFile << '\n'; std::cout << "Going to write " << fileCount << " files into " << currentArgs.outputFile << '\n';
if(args.sectorAligned) { if(currentArgs.sectorAligned) {
std::cout << "Writing a sector aligned package\n"; std::cout << "Writing a sector aligned package\n";
} }
@ -216,11 +218,11 @@ namespace eupak::tasks {
std::vector<eio::pak::Writer::FlattenedType> files; std::vector<eio::pak::Writer::FlattenedType> files;
files.reserve(fileCount); files.reserve(fileCount);
for(auto& ent : fs::recursive_directory_iterator(args.inputDirectory)) { for(auto& ent : fs::recursive_directory_iterator(currentArgs.inputDirectory)) {
if(ent.is_directory()) if(ent.is_directory())
continue; continue;
auto relativePathName = fs::relative(ent.path(), args.inputDirectory).string(); auto relativePathName = fs::relative(ent.path(), currentArgs.inputDirectory).string();
auto lastModified = fs::last_write_time(ent.path()); auto lastModified = fs::last_write_time(ent.path());
// Convert to Windows path separator always (that's what the game wants, after all) // Convert to Windows path separator always (that's what the game wants, after all)
@ -233,7 +235,7 @@ namespace eupak::tasks {
eio::pak::File file; eio::pak::File file;
eio::pak::FileData pakData = eio::pak::FileData::InitAsPath(ent.path()); eio::pak::FileData pakData = eio::pak::FileData::InitAsPath(ent.path());
file.InitAs(args.pakVersion, args.sectorAligned); file.InitAs(currentArgs.pakVersion, currentArgs.sectorAligned);
// Add data // Add data
file.SetData(std::move(pakData)); file.SetData(std::move(pakData));
@ -253,21 +255,21 @@ namespace eupak::tasks {
indicators::show_console_cursor(true); indicators::show_console_cursor(true);
std::ofstream ofs(args.outputFile.string(), std::ofstream::binary); std::ofstream ofs(currentArgs.outputFile.string(), std::ofstream::binary);
if(!ofs) { if(!ofs) {
std::cout << "Error: Couldn't open " << args.outputFile << " for writing\n"; std::cout << "Error: Couldn't open " << currentArgs.outputFile << " for writing\n";
return 1; return 1;
} }
CreateArchiveReportSink reportSink(fileCount); CreateArchiveReportSink reportSink(fileCount);
eio::pak::Writer writer(args.pakVersion); eio::pak::Writer writer(currentArgs.pakVersion);
using enum eio::pak::Writer::SectorAlignment; using enum eio::pak::Writer::SectorAlignment;
eio::pak::Writer::SectorAlignment alignment = DoNotAlign; eio::pak::Writer::SectorAlignment alignment = DoNotAlign;
if(args.sectorAligned) if(currentArgs.sectorAligned)
alignment = Align; alignment = Align;
writer.Write(ofs, std::move(files), reportSink, alignment); writer.Write(ofs, std::move(files), reportSink, alignment);

View file

@ -44,14 +44,12 @@ namespace eupak::tasks {
} }
int InfoTask::Parse() { int InfoTask::Parse() {
auto& args = currentArgs;
try { try {
args.verbose = parser.get<bool>("--verbose"); currentArgs.verbose = parser.get<bool>("--verbose");
args.inputPath = eupak::fs::path(parser.get("input")); currentArgs.inputPath = eupak::fs::path(parser.get("input"));
if(fs::is_directory(args.inputPath)) { if(fs::is_directory(currentArgs.inputPath)) {
std::cout << "Error: " << args.inputPath << " appears to be a directory, not a file.\n"; std::cout << "Error: " << currentArgs.inputPath << " appears to be a directory, not a file.\n";
return 1; return 1;
} }
@ -67,12 +65,10 @@ namespace eupak::tasks {
} }
int InfoTask::Run() { int InfoTask::Run() {
const auto& args = currentArgs; std::ifstream ifs(currentArgs.inputPath.string(), std::ifstream::binary);
std::ifstream ifs(args.inputPath.string(), std::ifstream::binary);
if(!ifs) { if(!ifs) {
std::cout << "Error: Could not open file " << args.inputPath << ".\n"; std::cout << "Error: Could not open file " << currentArgs.inputPath << ".\n";
return 1; return 1;
} }
@ -81,7 +77,7 @@ namespace eupak::tasks {
reader.ReadHeaderAndTOC(); reader.ReadHeaderAndTOC();
if(reader.Invalid()) { if(reader.Invalid()) {
std::cout << "Error: Invalid PAK/PMDL file " << args.inputPath << ".\n"; std::cout << "Error: Invalid PAK/PMDL file " << currentArgs.inputPath << ".\n";
return 1; return 1;
} }
@ -90,13 +86,13 @@ namespace eupak::tasks {
// This is the best other than just duplicating the body for each pak version.. :( // This is the best other than just duplicating the body for each pak version.. :(
if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver3) if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver3)
version = "Version 3 (PMDL)"; version = "Version 3 (Starfighter/Europa pre-release, May-July 2000?)";
else if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver4) else if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver4)
version = "Version 4 (Starfighter)"; version = "Version 4 (Starfighter)";
else if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver5) else if constexpr(std::decay_t<decltype(header)>::VERSION == estructs::PakVersion::Ver5)
version = "Version 5 (Jedi Starfighter)"; version = "Version 5 (Jedi Starfighter)";
std::cout << "Archive " << args.inputPath << ":\n"; std::cout << "Archive " << currentArgs.inputPath << ":\n";
std::cout << " Created: " << FormatUnixTimestamp(header.creationUnixTime, DATE_FORMAT) << '\n'; std::cout << " Created: " << FormatUnixTimestamp(header.creationUnixTime, DATE_FORMAT) << '\n';
std::cout << " Version: " << version << '\n'; std::cout << " Version: " << version << '\n';
std::cout << " Size: " << FormatUnit(header.tocOffset + header.tocSize) << '\n'; std::cout << " Size: " << FormatUnit(header.tocOffset + header.tocSize) << '\n';
@ -107,7 +103,7 @@ namespace eupak::tasks {
// Print a detailed file list if verbose. // Print a detailed file list if verbose.
for(auto& [filename, file] : reader.GetFiles()) { for(auto& [filename, file] : reader.GetFiles()) {
if(args.verbose) { if(currentArgs.verbose) {
std::cout << "File \"" << filename << "\":\n"; std::cout << "File \"" << filename << "\":\n";
file.VisitTocEntry([&](auto& tocEntry) { file.VisitTocEntry([&](auto& tocEntry) {
std::cout << " Created: " << FormatUnixTimestamp(tocEntry.creationUnixTime, DATE_FORMAT) << '\n'; std::cout << " Created: " << FormatUnixTimestamp(tocEntry.creationUnixTime, DATE_FORMAT) << '\n';