@@ -129,6 +129,35 @@ static Cvar::Cvar<bool> fs_legacypaks("fs_legacypaks", "also load pk3s, ignoring
129129static Cvar::Cvar<int > fs_maxSymlinkDepth (" fs_maxSymlinkDepth" , " max depth of symlinks in zip paks (0 means disabled)" , Cvar::NONE, 1 );
130130static Cvar::Cvar<std::string> fs_pakprefixes (" fs_pakprefixes" , " prefixes to look for paks to load" , 0 , " " );
131131
132+ builtinPakMap_t builtinPakMap = {};
133+
134+ std::vector<PakInfo> builtinPaks = {};
135+
136+ void ClearBuiltinPaks ()
137+ {
138+ builtinPakMap.clear ();
139+
140+ builtinPaks.clear ();
141+ builtinPaks.shrink_to_fit ();
142+ }
143+
144+ void AddBuiltinPak (const std::string& name, const std::string& version, const embeddedFileMap_t& map)
145+ {
146+ PakInfo *pak = new PakInfo ();
147+ pak->name = Str::Format ( " *%s" , name );
148+ pak->version = version;
149+ pak->checksum = 0 ;
150+ pak->type = pakType_t::PAK_ZIP;
151+ pak->path = Str::Format ( " *%s_%s" , name, version );
152+
153+ builtinPaks.push_back (*pak);
154+
155+ Log::Debug (" Adding builtin pak with %d files: %s" , map.size (), pak->name );
156+ builtinPakMap[pak->name ] = map;
157+
158+ PakPath::LoadPak (*pak);
159+ }
160+
132161bool UseLegacyPaks ()
133162{
134163 return fs_legacypaks.Get ();
@@ -1257,8 +1286,13 @@ static void InternalLoadPak(
12571286 bool hasDeps = false ;
12581287 offset_t depsOffset = 0 ;
12591288 ZipArchive zipFile;
1289+
12601290 bool isLegacy = pak.version .empty ();
12611291
1292+ bool isBuiltin = pak.type == pakType_t::PAK_ZIP && pak.name [ 0 ] == ' *' ;
1293+ bool isDir = pak.type == pakType_t::PAK_DIR;
1294+ bool isZip = pak.type == pakType_t::PAK_ZIP && !isBuiltin;
1295+
12621296 // Check if this pak has already been loaded to avoid recursive dependencies
12631297 for (auto & x: loadedPaks) {
12641298 // If the prefix is a superset of our current prefix, then it already
@@ -1267,13 +1301,15 @@ static void InternalLoadPak(
12671301 return ;
12681302 }
12691303
1270- if (pak.type == pakType_t::PAK_ZIP) {
1304+ if (isBuiltin) {
1305+ fsLogs.WithoutSuppression ().Notice (" Loading builtin pak '%s'..." , pak.path .c_str ());
1306+ } else if (isZip) {
12711307 if (!isLegacy) {
12721308 fsLogs.WithoutSuppression ().Notice (" Loading pak '%s'..." , pak.path .c_str ());
12731309 } else {
12741310 fsLogs.WithoutSuppression ().Notice (" Loading legacy pak '%s'..." , pak.path .c_str ());
12751311 }
1276- } else if (pak. type == pakType_t::PAK_DIR ) {
1312+ } else if (isDir ) {
12771313 if (!isLegacy) {
12781314 fsLogs.WithoutSuppression ().Notice (" Loading pakdir '%s'..." , pak.path .c_str ());
12791315 } else {
@@ -1292,7 +1328,14 @@ static void InternalLoadPak(
12921328 loadedPak.path = pak.path ;
12931329
12941330 // Update the list of files, but don't overwrite existing files, so the sort order is preserved
1295- if (pak.type == pakType_t::PAK_DIR) {
1331+ if (isBuiltin) {
1332+ loadedPak.fd = -1 ;
1333+ for (auto & it : builtinPakMap[pak.name ])
1334+ {
1335+ Log::Debug (" Adding file from builtin pak %s: %s" , pak.name , it.first );
1336+ fileMap.emplace (it.first , std::pair<uint32_t , offset_t >(loadedPaks.size () - 1 , 0 ));
1337+ }
1338+ } else if (isDir) {
12961339 loadedPak.fd = -1 ;
12971340 auto dirRange = RawPath::ListFilesRecursive (pak.path , err);
12981341 if (err)
@@ -1316,7 +1359,7 @@ static void InternalLoadPak(
13161359 if (err)
13171360 return ;
13181361 }
1319- } else if (pak. type == pakType_t::PAK_ZIP ) {
1362+ } else if (isZip ) {
13201363 // Open file
13211364 loadedPak.fd = my_open (pak.path , openMode_t::MODE_READ);
13221365 if (loadedPak.fd == -1 ) {
@@ -1380,16 +1423,16 @@ static void InternalLoadPak(
13801423 // Directories (aka a dpkdir) don't need timestamp.
13811424 // Fixes Windows bug where calling _wstat64i with trailing slash causes "file not found" error.
13821425 // For future stat calls on directories, trim the trailing slash (if exists)
1383- if (pak. type == pakType_t::PAK_ZIP ) {
1426+ if (isZip ) {
13841427 loadedPak.timestamp = FS::RawPath::FileTimestamp (pak.path , err);
13851428 if (err)
13861429 return ;
13871430 }
13881431
13891432 loadedPak.pathPrefix = pathPrefix;
13901433
1391- // Legacy paks don't have version neither checksum
1392- if (!isLegacy) {
1434+ // Legacy and builtin paks don't have version neither checksum
1435+ if (!isLegacy && !isBuiltin ) {
13931436 // If an explicit checksum was requested, verify that the pak we loaded is the one we are expecting
13941437 if (expectedChecksum && realChecksum != *expectedChecksum) {
13951438 SetErrorCodeFilesystem (err, filesystem_error::wrong_pak_checksum, pak.path );
@@ -1406,14 +1449,16 @@ static void InternalLoadPak(
14061449 if (!isLegacy) {
14071450 if (hasDeleted) {
14081451 std::string deletedData;
1409- if (pak.type == pakType_t::PAK_DIR) {
1452+ if (isBuiltin) {
1453+ // Not implemented.
1454+ } else if (isDir) {
14101455 File depsFile = RawPath::OpenRead (Path::Build (pak.path , PAK_DELETED_FILE), err);
14111456 if (err)
14121457 return ;
14131458 deletedData = depsFile.ReadAll (err);
14141459 if (err)
14151460 return ;
1416- } else if (pak. type == pakType_t::PAK_ZIP ) {
1461+ } else if (isZip ) {
14171462 zipFile.OpenFile (deletedOffset, err);
14181463 if (err)
14191464 return ;
@@ -1434,14 +1479,16 @@ static void InternalLoadPak(
14341479 // Load dependencies (non-legacy paks (pk3) only)
14351480 if (loadDeps && hasDeps) {
14361481 std::string depsData;
1437- if (pak.type == pakType_t::PAK_DIR) {
1482+ if (isBuiltin) {
1483+ // Not implemented.
1484+ } else if (isDir) {
14381485 File depsFile = RawPath::OpenRead (Path::Build (pak.path , PAK_DEPS_FILE), err);
14391486 if (err)
14401487 return ;
14411488 depsData = depsFile.ReadAll (err);
14421489 if (err)
14431490 return ;
1444- } else if (pak. type == pakType_t::PAK_ZIP ) {
1491+ } else if (isZip ) {
14451492 zipFile.OpenFile (depsOffset, err);
14461493 if (err)
14471494 return ;
@@ -1491,6 +1538,7 @@ void ClearPaks()
14911538 close (x.fd );
14921539 }
14931540 loadedPaks.clear ();
1541+ FS::ClearBuiltinPaks ();
14941542 FS::RefreshPaks ();
14951543}
14961544#else // BUILD_VM
@@ -1549,7 +1597,18 @@ std::string ReadFile(Str::StringRef path, std::error_code& err)
15491597 }
15501598
15511599 const LoadedPakInfo& pak = loadedPaks[it->second .first ];
1552- if (pak.type == pakType_t::PAK_DIR) {
1600+
1601+ bool isBuiltin = pak.type == pakType_t::PAK_ZIP && pak.name [0 ] == ' *' ;
1602+ bool isDir = pak.type == pakType_t::PAK_DIR;
1603+ bool isZip = pak.type == pakType_t::PAK_ZIP && !isBuiltin;
1604+
1605+ if (isBuiltin) {
1606+ const embeddedFileMapEntry_t& entry = builtinPakMap[pak.name ][path];
1607+ std::string out;
1608+ out.resize (entry.size );
1609+ memcpy (&out[0 ], entry.data , entry.size );
1610+ return out;
1611+ } else if (isDir) {
15531612 // Open file
15541613 File file = RawPath::OpenRead (Path::Build (pak.path , it->first ), err);
15551614 if (err)
@@ -1565,7 +1624,7 @@ std::string ReadFile(Str::StringRef path, std::error_code& err)
15651624 out.resize (length);
15661625 file.Read (&out[0 ], length, err);
15671626 return out;
1568- } else if (pak. type == pakType_t::PAK_ZIP ) {
1627+ } else if (isZip ) {
15691628 // Open zip
15701629 ZipArchive zipFile = ZipArchive::Open (pak.fd , err);
15711630 if (err)
@@ -1604,12 +1663,19 @@ void CopyFile(Str::StringRef path, const File& dest, std::error_code& err)
16041663 }
16051664
16061665 const LoadedPakInfo& pak = loadedPaks[it->second .first ];
1607- if (pak.type == pakType_t::PAK_DIR) {
1666+
1667+ bool isBuiltin = pak.type == pakType_t::PAK_ZIP && pak.name [0 ] == ' *' ;
1668+ bool isDir = pak.type == pakType_t::PAK_DIR;
1669+ bool isZip = pak.type == pakType_t::PAK_ZIP && !isBuiltin;
1670+
1671+ if (isBuiltin) {
1672+ // Not implemented
1673+ } else if (isDir) {
16081674 File file = RawPath::OpenRead (Path::Build (pak.path , it->first ), err);
16091675 if (err)
16101676 return ;
16111677 file.CopyTo (dest, err);
1612- } else if (pak. type == pakType_t::PAK_ZIP ) {
1678+ } else if (isZip ) {
16131679 // Open zip
16141680 ZipArchive zipFile = ZipArchive::Open (pak.fd , err);
16151681 if (err)
@@ -1672,7 +1738,15 @@ std::chrono::system_clock::time_point FileTimestamp(Str::StringRef path, std::er
16721738 }
16731739
16741740 const LoadedPakInfo& pak = loadedPaks[it->second .first ];
1675- if (pak.type == pakType_t::PAK_DIR) {
1741+
1742+ bool isBuiltin = pak.type == pakType_t::PAK_ZIP && pak.name [0 ] == ' *' ;
1743+ bool isDir = pak.type == pakType_t::PAK_DIR;
1744+ bool isZip = pak.type == pakType_t::PAK_ZIP && !isBuiltin;
1745+
1746+ if (isBuiltin) {
1747+ // Not implemented.
1748+ return {};
1749+ } else if (isDir) {
16761750#ifdef BUILD_VM
16771751 Util::optional<uint64_t > result;
16781752 VM::SendMsg<VM::FSPakPathTimestampMsg>(it->second .first , it->first , result);
@@ -1686,7 +1760,7 @@ std::chrono::system_clock::time_point FileTimestamp(Str::StringRef path, std::er
16861760#else
16871761 return RawPath::FileTimestamp (Path::Build (pak.path , it->first ), err);
16881762#endif
1689- } else if (pak. type == pakType_t::PAK_ZIP ) {
1763+ } else if (isZip ) {
16901764 return pak.timestamp ;
16911765 }
16921766
@@ -2636,6 +2710,10 @@ void RefreshPaks()
26362710 if (a.checksum != b.checksum )
26372711 return a.checksum > b.checksum ;
26382712
2713+ // Prefer builtin packages to zip packages.
2714+ if (b.type == pakType_t::PAK_ZIP && a.type == pakType_t::PAK_ZIP && b.name [0 ] == ' *' )
2715+ return true ;
2716+
26392717 // Prefer zip packages to directory packages
26402718 if (b.type == pakType_t::PAK_ZIP && a.type != pakType_t::PAK_ZIP)
26412719 return true ;
@@ -2660,6 +2738,16 @@ static const PakInfo* FindPakNoPrefix(Str::StringRef name)
26602738
26612739const PakInfo* FindPak (Str::StringRef name)
26622740{
2741+ #if defined(BUILD_ENGINE)
2742+ for ( auto & builtinPak : builtinPaks)
2743+ {
2744+ if ( builtinPak.name == name )
2745+ {
2746+ return &builtinPak;
2747+ }
2748+ }
2749+ #endif
2750+
26632751 Cmd::Args pakprefixes (Cvar::GetValue (" fs_pakprefixes" ));
26642752 for (const std::string &pakprefix: pakprefixes)
26652753 {
@@ -2715,7 +2803,12 @@ const PakInfo* FindPak(Str::StringRef name, Str::StringRef version, uint32_t che
27152803 return checksum > pakInfo.checksum ;
27162804 });
27172805
2718- if (iter == availablePaks.begin () || (iter - 1 )->name != name || (iter - 1 )->version != version || !(iter - 1 )->checksum || *(iter - 1 )->checksum != checksum) {
2806+ if (iter == availablePaks.begin ()
2807+ || (iter - 1 )->name != name
2808+ || (iter - 1 )->version != version
2809+ || !(iter - 1 )->checksum
2810+ || *(iter - 1 )->checksum != checksum) {
2811+
27192812 // Try again, but this time look for the pak without a checksum. We will verify the checksum later.
27202813 iter = std::upper_bound (availablePaks.begin (), availablePaks.end (), name, [version](Str::StringRef name1, const PakInfo& pakInfo) -> bool {
27212814 int result = name1.compare (pakInfo.name );
@@ -2728,7 +2821,23 @@ const PakInfo* FindPak(Str::StringRef name, Str::StringRef version, uint32_t che
27282821 });
27292822
27302823 // Only allow zip packages because directories don't have a checksum
2731- if (iter == availablePaks.begin () || (iter - 1 )->type == pakType_t::PAK_DIR || (iter - 1 )->name != name || (iter - 1 )->version != version || (iter - 1 )->checksum )
2824+ if (iter == availablePaks.begin ())
2825+ return nullptr ;
2826+
2827+ PakInfo& pak = (iter - 1 )[0 ];
2828+
2829+ bool isBuiltin = pak.type == pakType_t::PAK_ZIP && pak.name [ 0 ] == ' *' ;
2830+ bool isDir = pak.type == pakType_t::PAK_DIR;
2831+
2832+ if (isBuiltin)
2833+ return nullptr ;
2834+ if (isDir)
2835+ return nullptr ;
2836+ if (pak.name != name)
2837+ return nullptr ;
2838+ if (pak.version != version)
2839+ return nullptr ;
2840+ if (pak.checksum )
27322841 return nullptr ;
27332842 }
27342843
@@ -2944,12 +3053,19 @@ void HandleFileSystemSyscall(int minor, Util::Reader& reader, IPC::Channel& chan
29443053 case VM::FS_PAKPATH_TIMESTAMP:
29453054 IPC::HandleMsg<VM::FSPakPathTimestampMsg>(channel, std::move (reader), [](uint32_t pakIndex, std::string path, Util::optional<uint64_t >& out) {
29463055 auto & loadedPaks = FS::PakPath::GetLoadedPaks ();
3056+
29473057 if (loadedPaks.size () <= pakIndex)
29483058 return ;
2949- if (loadedPaks[pakIndex].type == pakType_t::PAK_ZIP)
3059+
3060+ const LoadedPakInfo& pak = loadedPaks[pakIndex];
3061+ bool isDir = pak.type == pakType_t::PAK_DIR;
3062+
3063+ if (!isDir)
29503064 return ;
3065+
29513066 if (!Path::IsValid (path, false ))
29523067 return ;
3068+
29533069 std::error_code err;
29543070 std::chrono::system_clock::time_point t = RawPath::FileTimestamp (Path::Build (loadedPaks[pakIndex].path , path), err);
29553071 if (!err)
0 commit comments