/
dieoska
/
ddnet
Обзор
Документация
Войти
/
dieoska
/
ddnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/tools/map_extract.cpp
167 строк
5 KB
Robert Müller
Cleanup `CDataFileReader::Close` function
16 мар 2025, 23:58
16 мар 2025, 23:58
0fed184
Код
Авторство
О чём код?
// Adapted from TWMapImagesRecovery by Tardo: https://github.com/Tardo/TWMapImagesRecovery #include <base/logger.h> #include <base/system.h> #include <engine/gfx/image_loader.h> #include <engine/shared/datafile.h> #include <engine/storage.h> #include <game/mapitems.h> static void PrintMapInfo(CDataFileReader &Reader) { const CMapItemInfo *pInfo = static_cast<CMapItemInfo *>(Reader.FindItem(MAPITEMTYPE_INFO, 0)); if(pInfo) { const char *pAuthor = Reader.GetDataString(pInfo->m_Author); log_info("map_extract", "author: %s", pAuthor == nullptr ? "(error)" : pAuthor); const char *pMapVersion = Reader.GetDataString(pInfo->m_MapVersion); log_info("map_extract", "version: %s", pMapVersion == nullptr ? "(error)" : pMapVersion); const char *pCredits = Reader.GetDataString(pInfo->m_Credits); log_info("map_extract", "credits: %s", pCredits == nullptr ? "(error)" : pCredits); const char *pLicense = Reader.GetDataString(pInfo->m_License); log_info("map_extract", "license: %s", pLicense == nullptr ? "(error)" : pLicense); } } static void ExtractMapImages(CDataFileReader &Reader, const char *pPathSave) { int Start, Num; Reader.GetType(MAPITEMTYPE_IMAGE, &Start, &Num); for(int i = 0; i < Num; i++) { const CMapItemImage_v2 *pItem = static_cast<CMapItemImage_v2 *>(Reader.GetItem(Start + i)); if(pItem->m_External) continue; const char *pName = Reader.GetDataString(pItem->m_ImageName); if(pName == nullptr || pName[0] == '\0') { log_error("map_extract", "failed to load name of image %d", i); continue; } char aBuf[IO_MAX_PATH_LENGTH]; str_format(aBuf, sizeof(aBuf), "%s/%s.png", pPathSave, pName); Reader.UnloadData(pItem->m_ImageName); if(pItem->m_Version >= 2 && pItem->m_MustBe1 != 1) { log_error("map_extract", "ignoring image '%s' with unknown format %d", aBuf, pItem->m_MustBe1); continue; } CImageInfo Image; Image.m_Width = pItem->m_Width; Image.m_Height = pItem->m_Height; Image.m_Format = CImageInfo::FORMAT_RGBA; Image.m_pData = static_cast<uint8_t *>(Reader.GetData(pItem->m_ImageData)); log_info("map_extract", "writing image: %s (%dx%d)", aBuf, pItem->m_Width, pItem->m_Height); if(!CImageLoader::SavePng(io_open(aBuf, IOFLAG_WRITE), aBuf, Image)) { log_error("map_extract", "failed to write image file. filename='%s'", aBuf); } Reader.UnloadData(pItem->m_ImageData); } } static void ExtractMapSounds(CDataFileReader &Reader, const char *pPathSave) { int Start, Num; Reader.GetType(MAPITEMTYPE_SOUND, &Start, &Num); for(int i = 0; i < Num; i++) { const CMapItemSound *pItem = static_cast<CMapItemSound *>(Reader.GetItem(Start + i)); if(pItem->m_External) continue; const char *pName = Reader.GetDataString(pItem->m_SoundName); if(pName == nullptr || pName[0] == '\0') { log_error("map_extract", "failed to load name of sound %d", i); continue; } const int SoundDataSize = Reader.GetDataSize(pItem->m_SoundData); char aBuf[IO_MAX_PATH_LENGTH]; str_format(aBuf, sizeof(aBuf), "%s/%s.opus", pPathSave, pName); Reader.UnloadData(pItem->m_SoundName); IOHANDLE Opus = io_open(aBuf, IOFLAG_WRITE); if(Opus) { log_info("map_extract", "writing sound: %s (%d B)", aBuf, SoundDataSize); io_write(Opus, Reader.GetData(pItem->m_SoundData), SoundDataSize); io_close(Opus); Reader.UnloadData(pItem->m_SoundData); } else { log_error("map_extract", "failed to open sound file for writing. filename='%s'", aBuf); } } } static bool ExtractMap(IStorage *pStorage, const char *pMapName, const char *pPathSave) { CDataFileReader Reader; if(!Reader.Open(pStorage, pMapName, IStorage::TYPE_ABSOLUTE)) { log_error("map_extract", "error opening map '%s'", pMapName); return false; } const CMapItemVersion *pVersion = static_cast<CMapItemVersion *>(Reader.FindItem(MAPITEMTYPE_VERSION, 0)); if(pVersion == nullptr || pVersion->m_Version != 1) { log_error("map_extract", "unsupported map version '%s'", pMapName); return false; } log_info("map_extract", "Make sure you have the permission to use these images and sounds in your own maps"); PrintMapInfo(Reader); ExtractMapImages(Reader, pPathSave); ExtractMapSounds(Reader, pPathSave); Reader.Close(); return true; } int main(int argc, const char *argv[]) { CCmdlineFix CmdlineFix(&argc, &argv); log_set_global_logger_default(); std::unique_ptr<IStorage> pStorage = CreateLocalStorage(); if(!pStorage) { log_error("map_extract", "Error creating local storage"); return -1; } const char *pDir; if(argc == 2) { pDir = "."; } else if(argc == 3) { pDir = argv[2]; } else { log_error("map_extract", "usage: %s <map> [directory]", argv[0]); return -1; } if(!fs_is_dir(pDir)) { log_error("map_extract", "directory '%s' does not exist", pDir); return -1; } return ExtractMap(pStorage.get(), argv[1], pDir) ? 0 : 1; }