1
0
forked from metin2/client

Improved pack initialization algorithm, archive types are now configurable in the Index file.

This commit is contained in:
Exynox 2025-04-12 07:00:29 +03:00
parent c21c99393d
commit 830e47b00b
6 changed files with 279 additions and 303 deletions

View File

@ -1,249 +1,102 @@
PACK patch1 ZIP
* season3_eu ZIP
patch1 patch2 ZIP
* metin2_patch_snow ZIP
season3_eu metin2_patch_snow_dungeon ZIP
* metin2_patch_etc_costume1 ZIP
patch2 metin2_patch_pet1 ZIP
* metin2_patch_pet2 ZIP
metin2_patch_snow metin2_patch_ramadan_costume ZIP
pack/ metin2_patch_flame ZIP
metin2_patch_snow_dungeon metin2_patch_flame_dungeon ZIP
pack/ metin2_patch_w21_etc ZIP
metin2_patch_etc_costume1 metin2_patch_w21_mobs ZIP
pack/ metin2_patch_w21_mobs_m ZIP
metin2_patch_pet1 metin2_patch_dss_box ZIP
pack/ metin2_patch_costume_soccer ZIP
metin2_patch_pet2 metin2_patch_easter1 ZIP
pack/ metin2_patch_mineral ZIP
metin2_patch_ramadan_costume metin2_patch_w20_sound ZIP
pack/ metin2_patch_ds ZIP
metin2_patch_flame metin2_patch_5th_armor ZIP
pack/ metin2_patch_w20_etc ZIP
metin2_patch_flame_dungeon metin2_patch_dragon_rock ZIP
pack/ metin2_patch_dragon_rock_mobs ZIP
metin2_patch_w21_etc metin2_patch_etc ZIP
pack/ metin2_patch_xmas ZIP
metin2_patch_w21_mobs metin2_patch_eu3 ZIP
pack/ metin2_patch_eu4 ZIP
metin2_patch_w21_mobs_m metin2_patch_mundi ZIP
pack/ metin2_patch_sd ZIP
metin2_patch_dss_box metin2_patch_halloween ZIP
pack/ metin2_patch_party ZIP
metin2_patch_costume_soccer metin2_patch_dance ZIP
pack/ pc ZIP
metin2_patch_easter1 pc2 ZIP
pack/ monster ZIP
metin2_patch_mineral monster2 ZIP
pack/ effect ZIP
metin2_patch_w20_sound zone ZIP
pack/ terrain ZIP
metin2_patch_ds npc ZIP
pack/ npc2 ZIP
metin2_patch_5th_armor tree ZIP
pack/ guild ZIP
metin2_patch_w20_etc item ZIP
pack/ textureset ZIP
metin2_patch_dragon_rock property ZIP
pack/ icon ZIP
metin2_patch_dragon_rock_mobs season1 ZIP
pack/ season2 ZIP
metin2_patch_etc outdoora1 ZIP
pack/ outdoora2 ZIP
metin2_patch_xmas outdoora3 ZIP
pack/ outdoorb1 ZIP
metin2_patch_eu3 outdoorb3 ZIP
pack/ outdoorc1 ZIP
metin2_patch_eu4 outdoorc3 ZIP
pack/ outdoorsnow1 ZIP
metin2_patch_mundi outdoordesert1 ZIP
pack/ outdoorflame1 ZIP
metin2_patch_sd outdoorfielddungeon1 ZIP
pack/ outdoort1 ZIP
metin2_patch_halloween outdoort2 ZIP
pack/ outdoort3 ZIP
metin2_patch_party outdoort4 ZIP
pack/ outdoorwedding ZIP
metin2_patch_dance outdoormilgyo1 ZIP
d:/ymir work/pc/ indoorspiderdungeon1 ZIP
pc indoordeviltower1 ZIP
d:/ymir work/pc2/ indoormonkeydungeon1 ZIP
pc2 indoormonkeydungeon2 ZIP
d:/ymir work/monster/ indoormonkeydungeon3 ZIP
monster outdoortrent02 ZIP
d:/ymir work/monster2/ outdoorguild1 ZIP
monster2 outdoorguild2 ZIP
d:/ymir work/effect/ outdoorguild3 ZIP
effect outdoortrent ZIP
d:/ymir work/zone/ outdoorduel ZIP
zone outdoorgmguildbuild ZIP
d:/ymir work/terrainmaps/ sound ZIP
terrain sound_m ZIP
d:/ymir work/npc/ sound2 ZIP
npc bgm ZIP
d:/ymir work/npc2/ ETC ZIP
npc2 locale_de ZIP
d:/ymir work/tree/ locale_es ZIP
tree locale_fr ZIP
d:/ymir work/guild/ locale_gr ZIP
guild locale_it ZIP
d:/ymir work/item/ locale_nl ZIP
item locale_pl ZIP
textureset/ locale_pt ZIP
textureset locale_tr ZIP
property/ locale_en ZIP
property locale_ro ZIP
icon/ locale_ru ZIP
icon locale_dk ZIP
season1/ locale_cz ZIP
season1 locale_hu ZIP
season2/ uiscript ZIP
season2 uiloading ZIP
metin2_map_a1/ root ZIP
outdoora1
map_a2/
outdoora2
metin2_map_a3/
outdoora3
metin2_map_b1/
outdoorb1
metin2_map_b3/
outdoorb3
metin2_map_c1/
outdoorc1
metin2_map_c3/
outdoorc3
map_n_snowm_01/
outdoorsnow1
metin2_map_n_desert_01/
outdoordesert1
metin2_map_n_flame_01/
outdoorflame1
map_b_fielddungeon/
outdoorfielddungeon1
metin2_map_t1/
outdoort1
metin2_map_t2/
outdoort2
metin2_map_t3/
outdoort3
metin2_map_t4/
outdoort4
metin2_map_wedding_01/
outdoorwedding
metin2_map_milgyo/
outdoormilgyo1
metin2_map_spiderdungeon/
indoorspiderdungeon1
metin2_map_deviltower1/
indoordeviltower1
metin2_map_monkeydungeon/
indoormonkeydungeon1
metin2_map_monkeydungeon_02/
indoormonkeydungeon2
metin2_map_monkeydungeon_03/
indoormonkeydungeon3
metin2_map_trent02/
outdoortrent02
metin2_map_guild_01/
outdoorguild1
metin2_map_guild_02/
outdoorguild2
metin2_map_guild_03/
outdoorguild3
metin2_map_trent/
outdoortrent
metin2_map_trent02/
outdoortrent02
metin2_map_duel/
outdoorduel
gm_guild_build/
outdoorgmguildbuild
sound/ambience/
sound
sound/common/
sound
sound/effect/
sound
sound/monster/
sound
sound/npc/
sound
sound/pc/
sound
sound/ui/
sound
sound/ambience/
sound_m
sound/common/
sound_m
sound/effect/
sound_m
sound/monster/
sound_m
sound/npc/
sound_m
sound/pc/
sound_m
sound/ui/
sound_m
sound/monster2/
sound2
sound/pc2/
sound2
bgm/
bgm
d:/ymir work/special/
ETC
d:/ymir work/environment/
ETC
locale/ca/
locale_ca
locale/ae/
locale_ae
locale/de/
locale_de
locale/es/
locale_es
locale/fr/
locale_fr
locale/gr/
locale_gr
locale/it/
locale_it
locale/nl/
locale_nl
locale/pl/
locale_pl
locale/pt/
locale_pt
locale/tr/
locale_tr
locale/uk/
locale_uk
locale/bg/
locale_bg
locale/en/
locale_en
locale/mx/
locale_mx
locale/ro/
locale_ro
locale/ru/
locale_ru
locale/dk/
locale_dk
locale/cz/
locale_cz
locale/hu/
locale_hu
locale/us/
locale_us
locale/pa/
locale_pa
uiscript/
uiscript
d:/ymir work/ui/
ETC
d:/ymir work/uiloading/
uiloading

102
bin/pack/Index.dev Normal file
View File

@ -0,0 +1,102 @@
patch1 FOLDER
season3_eu FOLDER
patch2 FOLDER
metin2_patch_snow FOLDER
metin2_patch_snow_dungeon FOLDER
metin2_patch_etc_costume1 FOLDER
metin2_patch_pet1 FOLDER
metin2_patch_pet2 FOLDER
metin2_patch_ramadan_costume FOLDER
metin2_patch_flame FOLDER
metin2_patch_flame_dungeon FOLDER
metin2_patch_w21_etc FOLDER
metin2_patch_w21_mobs FOLDER
metin2_patch_w21_mobs_m FOLDER
metin2_patch_dss_box FOLDER
metin2_patch_costume_soccer FOLDER
metin2_patch_easter1 FOLDER
metin2_patch_mineral FOLDER
metin2_patch_w20_sound FOLDER
metin2_patch_ds FOLDER
metin2_patch_5th_armor FOLDER
metin2_patch_w20_etc FOLDER
metin2_patch_dragon_rock FOLDER
metin2_patch_dragon_rock_mobs FOLDER
metin2_patch_etc FOLDER
metin2_patch_xmas FOLDER
metin2_patch_eu3 FOLDER
metin2_patch_eu4 FOLDER
metin2_patch_mundi FOLDER
metin2_patch_sd FOLDER
metin2_patch_halloween FOLDER
metin2_patch_party FOLDER
metin2_patch_dance FOLDER
pc FOLDER
pc2 FOLDER
monster FOLDER
monster2 FOLDER
effect FOLDER
zone FOLDER
terrain FOLDER
npc FOLDER
npc2 FOLDER
tree FOLDER
guild FOLDER
item FOLDER
textureset FOLDER
property FOLDER
icon FOLDER
season1 FOLDER
season2 FOLDER
outdoora1 FOLDER
outdoora2 FOLDER
outdoora3 FOLDER
outdoorb1 FOLDER
outdoorb3 FOLDER
outdoorc1 FOLDER
outdoorc3 FOLDER
outdoorsnow1 FOLDER
outdoordesert1 FOLDER
outdoorflame1 FOLDER
outdoorfielddungeon1 FOLDER
outdoort1 FOLDER
outdoort2 FOLDER
outdoort3 FOLDER
outdoort4 FOLDER
outdoorwedding FOLDER
outdoormilgyo1 FOLDER
indoorspiderdungeon1 FOLDER
indoordeviltower1 FOLDER
indoormonkeydungeon1 FOLDER
indoormonkeydungeon2 FOLDER
indoormonkeydungeon3 FOLDER
outdoortrent02 FOLDER
outdoorguild1 FOLDER
outdoorguild2 FOLDER
outdoorguild3 FOLDER
outdoortrent FOLDER
outdoorduel FOLDER
outdoorgmguildbuild FOLDER
sound FOLDER
sound_m FOLDER
sound2 FOLDER
bgm FOLDER
ETC FOLDER
locale_de FOLDER
locale_es FOLDER
locale_fr FOLDER
locale_gr FOLDER
locale_it FOLDER
locale_nl FOLDER
locale_pl FOLDER
locale_pt FOLDER
locale_tr FOLDER
locale_en FOLDER
locale_ro FOLDER
locale_ru FOLDER
locale_dk FOLDER
locale_cz FOLDER
locale_hu FOLDER
uiscript FOLDER
uiloading FOLDER
root FOLDER

View File

@ -5,8 +5,8 @@ FOR /d %%i IN ("*") DO (
echo Packing %%i echo Packing %%i
rem "C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*" -m0=BZip2 rem "C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*" -m0=BZip2
rem "C:\Program Files\7-Zip-Zstandard\7za.exe" a "%%i.zip" ".\%%i\*" -m0=Zstd rem "C:\Program Files\7-Zip-Zstandard\7za.exe" a "%%i.zip" ".\%%i\*" -m0=Zstd
"C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*" -m0=Copy rem "C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*" -m0=Copy
rem "C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*" "C:\Program Files\7-Zip\7z.exe" a "%%i.zip" ".\%%i\*"
if !errorlevel! neq 0 exit /b !errorlevel! if !errorlevel! neq 0 exit /b !errorlevel!
cls cls

View File

@ -183,10 +183,22 @@ bool CEterPackManager::isExist(const char * c_szFileName)
return isExistInPack(c_szFileName); return isExistInPack(c_szFileName);
} }
bool CEterPackManager::PackExists(const std::string& name, const std::string& container)
bool CEterPackManager::RegisterPack(const char * c_szName, const char * c_szDirectory, const BYTE* c_pbIV)
{ {
auto it = m_PackMap.find(c_szName); if (container == "FOLDER") {
return _access(name.c_str(), 0) == 0;
}
else if (container == "ZIP") {
std::string zipName = name + ".zip";
return _access(zipName.c_str(), 0) == 0;
}
throw std::runtime_error("Unexpected container type: " + container + "!");
}
bool CEterPackManager::RegisterPack(const std::string& name, const std::string& container)
{
auto it = m_PackMap.find(name);
if (it != m_PackMap.end()) if (it != m_PackMap.end())
return true; return true;
@ -196,24 +208,28 @@ bool CEterPackManager::RegisterPack(const char * c_szName, const char * c_szDire
std::shared_ptr<FileProvider> pack; std::shared_ptr<FileProvider> pack;
// TODO: allow configurable containers // Determine requested container type
if (container == "FOLDER")
//pack = std::make_shared<Folder>(c_szName); pack = std::make_shared<Folder>(name);
pack = std::make_shared<ZIP>(std::string(c_szName) + ".zip"); else if (container == "ZIP")
pack = std::make_shared<ZIP>(name + ".zip");
else
throw std::runtime_error("Unexpected container type: " + container + "!");
// Load container data
auto packFiles = pack->listFiles(); auto packFiles = pack->listFiles();
for (auto const& fileName : packFiles) for (auto const& fileName : packFiles)
m_FileMap.insert({ fileName, pack }); m_FileMap.insert({ fileName, pack });
m_PackMap.insert({ c_szName, pack }); m_PackMap.insert({ name, pack });
return true; return true;
} }
catch (std::exception& e) catch (std::exception& e)
{ {
#ifdef _DEBUG #ifdef _DEBUG
Tracef("Unable to load file provider '%s': %s\n", c_szName, e.what()); Tracef("Unable to load file provider '%s': %s\n", name.c_str(), e.what());
#endif #endif
return false; return false;

View File

@ -17,8 +17,8 @@ class CEterPackManager : public CSingleton<CEterPackManager>
}; };
typedef std::list<std::shared_ptr<FileProvider>> TEterPackList; typedef std::list<std::shared_ptr<FileProvider>> TEterPackList;
typedef std::unordered_map<std::string, std::shared_ptr<FileProvider>, stringhash> TEterPackMap; typedef std::unordered_map<std::string, std::shared_ptr<FileProvider>> TEterPackMap;
typedef std::unordered_map<std::string, std::shared_ptr<FileProvider>, stringhash> TFileMap; typedef std::unordered_map<std::string, std::shared_ptr<FileProvider>> TFileMap;
typedef std::shared_ptr<std::vector<char>> TPackDataPtr; typedef std::shared_ptr<std::vector<char>> TPackDataPtr;
public: public:
@ -34,7 +34,8 @@ class CEterPackManager : public CSingleton<CEterPackManager>
bool isExist(const char * c_szFileName); bool isExist(const char * c_szFileName);
bool isExistInPack(const char * c_szFileName); bool isExistInPack(const char * c_szFileName);
bool RegisterPack(const char * c_szName, const char * c_szDirectory, const BYTE* c_pbIV = NULL); bool PackExists(const std::string& name, const std::string& container);
bool RegisterPack(const std::string& name, const std::string& container);
std::string ConvertFileName(std::string fileName); std::string ConvertFileName(std::string fileName);
const TFileMap& GetFileMap(); const TFileMap& GetFileMap();

View File

@ -203,18 +203,31 @@ const char* ApplicationStringTable_GetStringz(DWORD dwID)
int Setup(LPSTR lpCmdLine); // Internal function forward int Setup(LPSTR lpCmdLine); // Internal function forward
bool PackInitialize(const char * c_pszFolder) bool PackInitialize(const std::string& packFolder)
{ {
NANOBEGIN NANOBEGIN
if (_access(c_pszFolder, 0) != 0) if (_access(packFolder.c_str(), 0) != 0)
return true; return true;
std::string stFolder(c_pszFolder); // Initialize variables
stFolder += "/"; bool bPackFirst = true;
std::string stFolder = packFolder + "/";
std::string stFileName;
std::string stFileName(stFolder); #ifdef _DISTRIBUTE
stFileName += "Index"; Tracef("Info: Pack search mode set to archive-first.\n");
// Set Index file name to production value
stFileName = stFolder + "Index";
#else
bPackFirst = false;
Tracef("Info: Pack search mode set to file-first.\n");
// Set Index file name to development value
stFileName = stFolder + "Index.dev";
#endif
// Set up file reader
CMappedFile file; CMappedFile file;
LPCVOID pvData; LPCVOID pvData;
@ -228,52 +241,43 @@ bool PackInitialize(const char * c_pszFolder)
CMemoryTextFileLoader TextLoader; CMemoryTextFileLoader TextLoader;
TextLoader.Bind(file.Size(), pvData); TextLoader.Bind(file.Size(), pvData);
bool bPackFirst = TRUE; // Set up archive manager
const std::string& strPackType = TextLoader.GetLineString(0);
if (strPackType.compare("FILE") && strPackType.compare("PACK"))
{
TraceError("Pack/Index has invalid syntax. First line must be 'PACK' or 'FILE'");
return false;
}
#ifdef _DISTRIBUTE
Tracef("알림: 팩 모드입니다.\n");
//if (0 == strPackType.compare("FILE"))
//{
// bPackFirst = FALSE;
// Tracef("알림: 파일 모드입니다.\n");
//}
//else
//{
// Tracef("알림: 팩 모드입니다.\n");
//}
#else
bPackFirst = FALSE;
Tracef("알림: 파일 모드입니다.\n");
#endif
CTextFileLoader::SetCacheMode(); CTextFileLoader::SetCacheMode();
CEterPackManager::Instance().SetSearchMode(bPackFirst); CEterPackManager::Instance().SetSearchMode(bPackFirst);
CSoundData::SetPackMode(); // Miles 파일 콜백을 셋팅 CSoundData::SetPackMode(); // Miles 파일 콜백을 셋팅
// Read lines and parse tokens
std::string strPackName, strTexCachePackName; std::string strPackName, strTexCachePackName;
for (DWORD i = 1; i < TextLoader.GetLineCount() - 1; i += 2) CTokenVector tokens = CTokenVector();
for (DWORD i = 0; i < TextLoader.GetLineCount() - 1; i++)
{ {
const std::string & c_rstFolder = TextLoader.GetLineString(i); // Split line into tokens
const std::string & c_rstName = TextLoader.GetLineString(i + 1); TextLoader.SplitLineByTab(i, &tokens);
// Check if the read number of tokens is valid
if (tokens.size() != 2)
{
TraceError("Invalid number of tokens on line %d: expected %d, got %d!", i, 2, tokens.size());
return false;
}
// Assign tokens into variables
const std::string& c_rstName = tokens[0];
const std::string& c_rstContainer = tokens[1];
// Load pack
strPackName = stFolder + c_rstName; strPackName = stFolder + c_rstName;
strTexCachePackName = strPackName + "_texcache"; CEterPackManager::Instance().RegisterPack(strPackName, c_rstContainer);
CEterPackManager::Instance().RegisterPack(strPackName.c_str(), c_rstFolder.c_str()); // Try to load texture cache pack if it exists
CEterPackManager::Instance().RegisterPack(strTexCachePackName.c_str(), c_rstFolder.c_str()); strTexCachePackName = strPackName + "_texcache";
if (CEterPackManager::Instance().PackExists(strTexCachePackName, c_rstContainer)) {
CEterPackManager::Instance().RegisterPack(strTexCachePackName, c_rstContainer);
}
} }
CEterPackManager::Instance().RegisterPack((stFolder + "root").c_str(), (stFolder + "root").c_str());
NANOEND NANOEND
return true; return true;
} }