aboutsummaryrefslogtreecommitdiff
path: root/src/tools/vmap4_assembler
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/vmap4_assembler')
-rw-r--r--src/tools/vmap4_assembler/TileAssembler.cpp340
-rw-r--r--src/tools/vmap4_assembler/TileAssembler.h4
-rw-r--r--src/tools/vmap4_assembler/VMapAssembler.cpp87
3 files changed, 263 insertions, 168 deletions
diff --git a/src/tools/vmap4_assembler/TileAssembler.cpp b/src/tools/vmap4_assembler/TileAssembler.cpp
index dfd905ff6df..e0a3962cf2b 100644
--- a/src/tools/vmap4_assembler/TileAssembler.cpp
+++ b/src/tools/vmap4_assembler/TileAssembler.cpp
@@ -17,10 +17,13 @@
#include "TileAssembler.h"
#include "BoundingIntervalHierarchy.h"
+#include "IteratorPair.h"
#include "MapTree.h"
#include "Memory.h"
+#include "StringConvert.h"
#include "StringFormat.h"
#include "VMapDefinitions.h"
+#include <boost/filesystem/directory.hpp>
#include <boost/filesystem/operations.hpp>
#include <set>
@@ -43,143 +46,67 @@ namespace VMAP
TileAssembler::TileAssembler(std::string pSrcDirName, std::string pDestDirName)
: iDestDir(std::move(pDestDirName)), iSrcDir(std::move(pSrcDirName))
{
- boost::filesystem::create_directories(iDestDir);
}
bool TileAssembler::convertWorld2()
{
- bool success = readMapSpawns();
- if (!success)
+ boost::system::error_code ec;
+ Trinity::IteratorPair dirBin(boost::filesystem::directory_iterator(iSrcDir + "/dir_bin", ec), {});
+ if (ec)
+ {
+ printf("Failed to open input %s/dir_bin: %s\n", iSrcDir.c_str(), ec.message().c_str());
return false;
+ }
- float constexpr invTileSize = 1.0f / 533.33333f;
-
- // export Map data
- while (!mapData.empty())
+ if (!boost::filesystem::create_directories(iDestDir, ec))
{
- MapSpawns data = std::move(mapData.front());
- mapData.pop_front();
-
- // build global map tree
- std::vector<ModelSpawn*> mapSpawns;
- mapSpawns.reserve(data.UniqueEntries.size());
- printf("Calculating model bounds for map %u...\n", data.MapId);
- for (auto entry = data.UniqueEntries.begin(); entry != data.UniqueEntries.end(); ++entry)
+ boost::system::error_code existsErr;
+ if (!boost::filesystem::exists(iDestDir, existsErr))
{
- // M2 models don't have a bound set in WDT/ADT placement data, they're not used for LoS but are needed for pathfinding
- if (!(entry->second.flags & MOD_HAS_BOUND))
- if (!calculateTransformedBound(entry->second))
- continue;
-
- mapSpawns.push_back(&entry->second);
- spawnedModelFiles.insert(entry->second.name);
-
- std::map<uint32, std::set<uint32>>& tileEntries = (entry->second.flags & MOD_PARENT_SPAWN) ? data.ParentTileEntries : data.TileEntries;
-
- G3D::AABox const& bounds = entry->second.iBound;
- G3D::Vector2int16 low(int16(bounds.low().x * invTileSize), int16(bounds.low().y * invTileSize));
- G3D::Vector2int16 high(int16(bounds.high().x * invTileSize), int16(bounds.high().y * invTileSize));
- for (int x = low.x; x <= high.x; ++x)
- for (int y = low.y; y <= high.y; ++y)
- tileEntries[StaticMapTree::packTileID(x, y)].insert(entry->second.ID);
+ printf("Failed to create output directory %s: %s\n", iDestDir.c_str(), ec.message().c_str());
+ return false;
}
+ // else already exists - this is fine, continue
+ }
- printf("Creating map tree for map %u...\n", data.MapId);
- BIH pTree;
+ std::deque<boost::filesystem::path> mapSpawnFiles;
+ for (boost::filesystem::directory_entry const& directoryEntry : dirBin)
+ {
+ if (!boost::filesystem::is_regular_file(directoryEntry))
+ continue;
- try
- {
- pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds);
- }
- catch (std::exception& e)
- {
- printf(R"(Exception "%s" when calling pTree.build)", e.what());
- return false;
- }
+ mapSpawnFiles.push_back(directoryEntry.path());
+ }
- std::unordered_map<uint32, uint32> modelNodeIdx;
- for (uint32 i = 0; i < mapSpawns.size(); ++i)
- modelNodeIdx.try_emplace(mapSpawns[i]->ID, i);
+ // export Map data
+ while (!mapSpawnFiles.empty())
+ {
+ boost::filesystem::path file = std::move(mapSpawnFiles.front());
+ mapSpawnFiles.pop_front();
- // write map tree file
- std::string mapfilename = Trinity::StringFormat("{}/{:04}.vmtree", iDestDir, data.MapId);
- auto mapfile = Trinity::make_unique_ptr_with_deleter(fopen(mapfilename.c_str(), "wb"), &::fclose);
- if (!mapfile)
+ auto dirf = Trinity::make_unique_ptr_with_deleter(fopen(file.string().c_str(), "rb"), &::fclose);
+ if (!dirf)
{
- success = false;
- printf("Cannot open %s\n", mapfilename.c_str());
- break;
+ printf("Could not read dir_bin file!\n");
+ return false;
}
- //general info
- if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile.get()) != 8) success = false;
- // Nodes
- if (success && fwrite("NODE", 4, 1, mapfile.get()) != 1) success = false;
- if (success) success = pTree.writeToFile(mapfile.get());
-
- mapfile = nullptr;
-
- // <====
-
- // write map tile files, similar to ADT files, only with extra BIH tree node info
- for (auto const& [tileId, spawns] : data.TileEntries)
+ Optional<uint32> mapId = Trinity::StringTo<uint32>(file.filename().string());
+ if (!mapId)
{
- uint32 x, y;
- StaticMapTree::unpackTileID(tileId, x, y);
- std::string tileFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtile", iDestDir, data.MapId, y, x);
- auto tileFile = Trinity::make_unique_ptr_with_deleter(fopen(tileFileName.c_str(), "wb"), &::fclose);
- std::string tileSpawnIndicesFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtileidx", iDestDir, data.MapId, y, x);
- auto tileSpawnIndicesFile = Trinity::make_unique_ptr_with_deleter(fopen(tileSpawnIndicesFileName.c_str(), "wb"), &::fclose);
- if (tileFile && tileSpawnIndicesFile)
- {
- std::set<uint32> const& parentTileEntries = data.ParentTileEntries[tileId];
-
- uint32 nSpawns = spawns.size() + parentTileEntries.size();
-
- // file header
- if (success && fwrite(VMAP_MAGIC, 1, 8, tileFile.get()) != 8) success = false;
- if (success && fwrite(VMAP_MAGIC, 1, 8, tileSpawnIndicesFile.get()) != 8) success = false;
- // write number of tile spawns
- if (success && fwrite(&nSpawns, sizeof(uint32), 1, tileFile.get()) != 1) success = false;
- if (success && fwrite(&nSpawns, sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1) success = false;
- // write tile spawns
- for (auto spawnItr = spawns.begin(); spawnItr != spawns.end() && success; ++spawnItr)
- {
- success = ModelSpawn::writeToFile(tileFile.get(), data.UniqueEntries[*spawnItr]);
- if (success && fwrite(&modelNodeIdx[*spawnItr], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1) success = false;
- }
-
- for (auto spawnItr = parentTileEntries.begin(); spawnItr != parentTileEntries.end() && success; ++spawnItr)
- {
- success = ModelSpawn::writeToFile(tileFile.get(), data.UniqueEntries[*spawnItr]);
- if (success && fwrite(&modelNodeIdx[*spawnItr], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1) success = false;
- }
- }
+ printf("Invalid Map ID %s\n", file.filename().string().c_str());
+ return false;
}
- for (auto const& [tileId, spawns] : data.ParentTileEntries)
- {
- if (data.TileEntries.contains(tileId))
- continue;
+ printf("spawning Map %u\n", *mapId);
- uint32 x, y;
- StaticMapTree::unpackTileID(tileId, x, y);
- std::string tileSpawnIndicesFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtileidx", iDestDir, data.MapId, y, x);
- auto tileSpawnIndicesFile = Trinity::make_unique_ptr_with_deleter(fopen(tileSpawnIndicesFileName.c_str(), "wb"), &::fclose);
- if (tileSpawnIndicesFile)
- {
- uint32 nSpawns = spawns.size();
-
- // file header
- if (success && fwrite(VMAP_MAGIC, 1, 8, tileSpawnIndicesFile.get()) != 8) success = false;
- // write number of tile spawns
- if (success && fwrite(&nSpawns, sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1) success = false;
- // write tile spawns
- for (auto spawnItr = spawns.begin(); spawnItr != spawns.end() && success; ++spawnItr)
- if (fwrite(&modelNodeIdx[*spawnItr], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
- success = false;
- }
- }
+ MapSpawns data;
+ data.MapId = *mapId;
+ if (!readMapSpawns(dirf.get(), &data))
+ return false;
+
+ if (!convertMap(data))
+ return false;
}
// add an object models, listed in temp_gameobject_models file
@@ -192,54 +119,175 @@ namespace VMAP
if (!convertRawFile(spawnedModelFile))
{
printf("error converting %s\n", spawnedModelFile.c_str());
- success = false;
break;
}
}
- return success;
+ return true;
}
- bool TileAssembler::readMapSpawns()
+ bool TileAssembler::convertMap(MapSpawns& data)
{
- std::string fname = iSrcDir + "/dir_bin";
- auto dirf = Trinity::make_unique_ptr_with_deleter(fopen(fname.c_str(), "rb"), &::fclose);
- if (!dirf)
+ float constexpr invTileSize = 1.0f / 533.33333f;
+
+ // build global map tree
+ std::vector<ModelSpawn*> mapSpawns;
+ mapSpawns.reserve(data.UniqueEntries.size());
+ printf("Calculating model bounds for map %u...\n", data.MapId);
+ for (auto& [spawnId, spawn] : data.UniqueEntries)
+ {
+ // M2 models don't have a bound set in WDT/ADT placement data, they're not used for LoS but are needed for pathfinding
+ if (!(spawn.flags & MOD_HAS_BOUND))
+ if (!calculateTransformedBound(spawn))
+ continue;
+
+ mapSpawns.push_back(&spawn);
+ spawnedModelFiles.insert(spawn.name);
+
+ std::map<uint32, std::set<uint32>>& tileEntries = (spawn.flags & MOD_PARENT_SPAWN) ? data.ParentTileEntries : data.TileEntries;
+
+ G3D::AABox const& bounds = spawn.iBound;
+ G3D::Vector2int16 low(int16(bounds.low().x * invTileSize), int16(bounds.low().y * invTileSize));
+ G3D::Vector2int16 high(int16(bounds.high().x * invTileSize), int16(bounds.high().y * invTileSize));
+ for (int x = low.x; x <= high.x; ++x)
+ for (int y = low.y; y <= high.y; ++y)
+ tileEntries[StaticMapTree::packTileID(x, y)].insert(spawnId);
+ }
+
+ printf("Creating map tree for map %u...\n", data.MapId);
+ BIH pTree;
+
+ try
+ {
+ pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds);
+ }
+ catch (std::exception& e)
{
- printf("Could not read dir_bin file!\n");
+ printf(R"(Exception "%s" when calling pTree.build)", e.what());
return false;
}
- printf("Read coordinate mapping...\n");
- uint32 mapID, check;
- std::map<uint32, MapSpawns> data;
- while (!feof(dirf.get()))
+
+ std::unordered_map<uint32, uint32> modelNodeIdx;
+ for (uint32 i = 0; i < mapSpawns.size(); ++i)
+ modelNodeIdx.try_emplace(mapSpawns[i]->ID, i);
+
+ // write map tree file
+ std::string mapfilename = Trinity::StringFormat("{}/{:04}.vmtree", iDestDir, data.MapId);
+ auto mapfile = Trinity::make_unique_ptr_with_deleter(fopen(mapfilename.c_str(), "wb"), &::fclose);
+ if (!mapfile)
{
- // read mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
- check = fread(&mapID, sizeof(uint32), 1, dirf.get());
- if (check == 0) // EoF...
- break;
+ printf("Cannot open %s\n", mapfilename.c_str());
+ return false;
+ }
- ModelSpawn spawn;
- if (!ModelSpawn::readFromFile(dirf.get(), spawn))
- break;
+ //general info
+ if (fwrite(VMAP_MAGIC, 1, 8, mapfile.get()) != 8)
+ return false;
+ // Nodes
+ if (fwrite("NODE", 4, 1, mapfile.get()) != 1)
+ return false;
+ if (!pTree.writeToFile(mapfile.get()))
+ return false;
+
+ mapfile = nullptr;
+
+ // <====
- auto [itr, isNew] = data.try_emplace(mapID);
- if (isNew)
+ // write map tile files, similar to ADT files, only with extra BIH tree node info
+ for (auto const& [tileId, spawns] : data.TileEntries)
+ {
+ uint32 x, y;
+ StaticMapTree::unpackTileID(tileId, x, y);
+ std::string tileFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtile", iDestDir, data.MapId, y, x);
+ auto tileFile = Trinity::make_unique_ptr_with_deleter(fopen(tileFileName.c_str(), "wb"), &::fclose);
+ std::string tileSpawnIndicesFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtileidx", iDestDir, data.MapId, y, x);
+ auto tileSpawnIndicesFile = Trinity::make_unique_ptr_with_deleter(fopen(tileSpawnIndicesFileName.c_str(), "wb"), &::fclose);
+ if (tileFile && tileSpawnIndicesFile)
{
- itr->second.MapId = mapID;
- printf("spawning Map %u\n", mapID);
+ std::set<uint32> const& parentTileEntries = data.ParentTileEntries[tileId];
+
+ uint32 nSpawns = spawns.size() + parentTileEntries.size();
+
+ // file header
+ if (fwrite(VMAP_MAGIC, 1, 8, tileFile.get()) != 8)
+ return false;
+ if (fwrite(VMAP_MAGIC, 1, 8, tileSpawnIndicesFile.get()) != 8)
+ return false;
+
+ // write number of tile spawns
+ if (fwrite(&nSpawns, sizeof(uint32), 1, tileFile.get()) != 1)
+ return false;
+ if (fwrite(&nSpawns, sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
+ return false;
+
+ // write tile spawns
+ for (uint32 spawnId : spawns)
+ {
+ if (!ModelSpawn::writeToFile(tileFile.get(), data.UniqueEntries[spawnId]))
+ return false;
+ if (fwrite(&modelNodeIdx[spawnId], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
+ return false;
+ }
+
+ for (uint32 spawnId : parentTileEntries)
+ {
+ if (!ModelSpawn::writeToFile(tileFile.get(), data.UniqueEntries[spawnId]))
+ return false;
+ if (fwrite(&modelNodeIdx[spawnId], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
+ return false;
+ }
}
+ }
- itr->second.UniqueEntries.emplace(spawn.ID, spawn);
+ for (auto const& [tileId, spawns] : data.ParentTileEntries)
+ {
+ if (data.TileEntries.contains(tileId))
+ continue;
+
+ uint32 x, y;
+ StaticMapTree::unpackTileID(tileId, x, y);
+ std::string tileSpawnIndicesFileName = Trinity::StringFormat("{}/{:04}_{:02}_{:02}.vmtileidx", iDestDir, data.MapId, y, x);
+ auto tileSpawnIndicesFile = Trinity::make_unique_ptr_with_deleter(fopen(tileSpawnIndicesFileName.c_str(), "wb"), &::fclose);
+ if (tileSpawnIndicesFile)
+ {
+ uint32 nSpawns = spawns.size();
+
+ // file header
+ if (fwrite(VMAP_MAGIC, 1, 8, tileSpawnIndicesFile.get()) != 8)
+ return false;
+
+ // write number of tile spawns
+ if (fwrite(&nSpawns, sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
+ return false;
+
+ // write tile spawns
+ for (uint32 spawnId : spawns)
+ if (fwrite(&modelNodeIdx[spawnId], sizeof(uint32), 1, tileSpawnIndicesFile.get()) != 1)
+ return false;
+ }
}
- mapData.resize(data.size());
- auto dst = mapData.begin();
- for (auto src = data.begin(); src != data.end(); ++src, ++dst)
- *dst = std::move(src->second);
+ return true;
+ }
- bool success = (ferror(dirf.get()) == 0);
- return success;
+ bool TileAssembler::readMapSpawns(FILE* dirf, MapSpawns* data)
+ {
+ while (!feof(dirf))
+ {
+ // read Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
+ ModelSpawn spawn;
+ if (!ModelSpawn::readFromFile(dirf, spawn))
+ {
+ if (feof(dirf))
+ break;
+
+ return false;
+ }
+
+ data->UniqueEntries.emplace(spawn.ID, spawn);
+ }
+
+ return true;
}
bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn)
diff --git a/src/tools/vmap4_assembler/TileAssembler.h b/src/tools/vmap4_assembler/TileAssembler.h
index 5e9c963a0d7..f803793a5b5 100644
--- a/src/tools/vmap4_assembler/TileAssembler.h
+++ b/src/tools/vmap4_assembler/TileAssembler.h
@@ -94,14 +94,14 @@ namespace VMAP
private:
std::string iDestDir;
std::string iSrcDir;
- MapData mapData;
std::set<std::string> spawnedModelFiles;
public:
TileAssembler(std::string pSrcDirName, std::string pDestDirName);
bool convertWorld2();
- bool readMapSpawns();
+ bool convertMap(MapSpawns& data);
+ static bool readMapSpawns(FILE* dirf, MapSpawns* data);
bool calculateTransformedBound(ModelSpawn &spawn);
void exportGameobjectModels();
diff --git a/src/tools/vmap4_assembler/VMapAssembler.cpp b/src/tools/vmap4_assembler/VMapAssembler.cpp
index 031a5c8dcb7..b492b207879 100644
--- a/src/tools/vmap4_assembler/VMapAssembler.cpp
+++ b/src/tools/vmap4_assembler/VMapAssembler.cpp
@@ -15,13 +15,28 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <string>
-#include <iostream>
-
-#include "TileAssembler.h"
#include "Banner.h"
+#include "GitRevision.h"
#include "Locales.h"
+#include "Optional.h"
+#include "TileAssembler.h"
#include "Util.h"
+#include <boost/program_options.hpp>
+#include <iostream>
+#include <string>
+
+namespace po = boost::program_options;
+
+/**
+ * Parses command line arguments
+ *
+ * @param [in] argc command line argument count
+ * @param [in] argv raw command line arguments
+ * @param [out] src raw data dir
+ * @param [out] dest vmap dest dir
+ * @return Non-empty optional if program should exit immediately (holds exit code in that case)
+ */
+Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest);
int main(int argc, char* argv[])
{
@@ -29,23 +44,11 @@ int main(int argc, char* argv[])
Trinity::Locale::Init();
- Trinity::Banner::Show("VMAP assembler", [](char const* text) { std::cout << text << std::endl; }, nullptr);
-
- std::string src = "Buildings";
- std::string dest = "vmaps";
+ std::string src, dest;
+ if (Optional<int> exitCode = HandleArgs(argc, argv, &src, &dest))
+ return *exitCode;
- if (argc > 3)
- {
- std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl;
- return 1;
- }
- else
- {
- if (argc > 1)
- src = argv[1];
- if (argc > 2)
- dest = argv[2];
- }
+ Trinity::Banner::Show("VMAP assembler", [](char const* text) { std::cout << text << std::endl; }, nullptr);
std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl;
@@ -60,3 +63,47 @@ int main(int argc, char* argv[])
std::cout << "Ok, all done" << std::endl;
return 0;
}
+
+Optional<int> HandleArgs(int argc, char* argv[], std::string* src, std::string* dest)
+{
+ po::options_description visible("Usage: vmap4assembler [OPTION]... [SRC] [DEST]\n\nWhere OPTION can be any of");
+ visible.add_options()
+ ("help,h", "print usage message")
+ ("version,v", "print version build info");
+
+ po::options_description all;
+ all.add(visible);
+ all.add_options()
+ ("src", po::value(src)->default_value("Buildings"), "raw data dir")
+ ("dest", po::value(dest)->default_value("vmaps"), "vmap dest dir");
+
+ po::positional_options_description positional;
+ positional.add("src", 1);
+ positional.add("dest", 1);
+
+ po::variables_map variablesMap;
+ try
+ {
+ store(po::command_line_parser(argc, argv).options(all).positional(positional).run(), variablesMap);
+ notify(variablesMap);
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << '\n';
+ return 1;
+ }
+
+ if (variablesMap.contains("help"))
+ {
+ std::cout << visible << '\n';
+ return 0;
+ }
+
+ if (variablesMap.contains("version"))
+ {
+ std::cout << GitRevision::GetFullVersion() << '\n';
+ return 0;
+ }
+
+ return {};
+}