mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-22 18:15:31 +01:00
Core/VMAPS: Fixed vmaps in single WMO instances like ragefire chasm (ported commit: 24d30dab84)
* Fixed some models not always being spawned because they only appear in one tile file but are large enough to cross tile boundaries (lava in Firelands at Ragnaros place)
This commit is contained in:
@@ -132,7 +132,7 @@ namespace VMAP
|
||||
{
|
||||
std::string mapFileName = getMapFileName(mapId);
|
||||
StaticMapTree* newTree = new StaticMapTree(mapId, basePath);
|
||||
if (!newTree->InitMap(mapFileName, this))
|
||||
if (!newTree->InitMap(mapFileName))
|
||||
{
|
||||
delete newTree;
|
||||
return false;
|
||||
|
||||
@@ -120,9 +120,8 @@ namespace VMAP
|
||||
return intersectionCallBack.result;
|
||||
}
|
||||
|
||||
StaticMapTree::StaticMapTree(uint32 mapID, const std::string &basePath) :
|
||||
iMapID(mapID), iIsTiled(false), iTreeValues(nullptr),
|
||||
iNTreeValues(0), iBasePath(basePath)
|
||||
StaticMapTree::StaticMapTree(uint32 mapID, const std::string &basePath)
|
||||
: iMapID(mapID), iTreeValues(NULL), iNTreeValues(0), iBasePath(basePath)
|
||||
{
|
||||
if (iBasePath.length() > 0 && iBasePath[iBasePath.length()-1] != '/' && iBasePath[iBasePath.length()-1] != '\\')
|
||||
{
|
||||
@@ -268,24 +267,20 @@ namespace VMAP
|
||||
if (!rf)
|
||||
return LoadResult::FileNotFound;
|
||||
|
||||
char tiled;
|
||||
char chunk[8];
|
||||
if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1)
|
||||
if (!readChunk(rf, chunk, VMAP_MAGIC, 8))
|
||||
{
|
||||
fclose(rf);
|
||||
return LoadResult::VersionMismatch;
|
||||
}
|
||||
if (tiled)
|
||||
FILE* tf = OpenMapTileFile(basePath, mapID, tileX, tileY, vm).File;
|
||||
if (!tf)
|
||||
result = LoadResult::FileNotFound;
|
||||
else
|
||||
{
|
||||
FILE* tf = OpenMapTileFile(basePath, mapID, tileX, tileY, vm).File;
|
||||
if (!tf)
|
||||
result = LoadResult::FileNotFound;
|
||||
else
|
||||
{
|
||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||
result = LoadResult::VersionMismatch;
|
||||
fclose(tf);
|
||||
}
|
||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||
result = LoadResult::VersionMismatch;
|
||||
fclose(tf);
|
||||
}
|
||||
fclose(rf);
|
||||
return result;
|
||||
@@ -293,7 +288,7 @@ namespace VMAP
|
||||
|
||||
//=========================================================
|
||||
|
||||
bool StaticMapTree::InitMap(const std::string &fname, VMapManager2* vm)
|
||||
bool StaticMapTree::InitMap(std::string const& fname)
|
||||
{
|
||||
VMAP_DEBUG_LOG("maps", "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str());
|
||||
bool success = false;
|
||||
@@ -303,39 +298,14 @@ namespace VMAP
|
||||
return false;
|
||||
|
||||
char chunk[8];
|
||||
char tiled = '\0';
|
||||
|
||||
if (readChunk(rf, chunk, VMAP_MAGIC, 8) && fread(&tiled, sizeof(char), 1, rf) == 1 &&
|
||||
readChunk(rf, chunk, "NODE", 4) && iTree.readFromFile(rf))
|
||||
if (readChunk(rf, chunk, VMAP_MAGIC, 8) &&
|
||||
readChunk(rf, chunk, "NODE", 4) &&
|
||||
iTree.readFromFile(rf))
|
||||
{
|
||||
iNTreeValues = iTree.primCount();
|
||||
iTreeValues = new ModelInstance[iNTreeValues];
|
||||
success = readChunk(rf, chunk, "GOBJ", 4);
|
||||
}
|
||||
|
||||
iIsTiled = tiled != '\0';
|
||||
|
||||
// global model spawns
|
||||
// only non-tiled maps have them, and if so exactly one (so far at least...)
|
||||
ModelSpawn spawn;
|
||||
#ifdef VMAP_DEBUG
|
||||
TC_LOG_DEBUG("maps", "StaticMapTree::InitMap() : map isTiled: %u", static_cast<uint32>(iIsTiled));
|
||||
#endif
|
||||
if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn))
|
||||
{
|
||||
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name, spawn.flags);
|
||||
VMAP_DEBUG_LOG("maps", "StaticMapTree::InitMap() : loading %s", spawn.name.c_str());
|
||||
if (model)
|
||||
{
|
||||
// assume that global model always is the first and only tree value (could be improved...)
|
||||
iTreeValues[0] = ModelInstance(spawn, model);
|
||||
iLoadedSpawns[0] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
VMAP_ERROR_LOG("misc", "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str());
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
@@ -376,15 +346,6 @@ namespace VMAP
|
||||
|
||||
bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm)
|
||||
{
|
||||
if (!iIsTiled)
|
||||
{
|
||||
// currently, core creates grids for all maps, whether it has terrain tiles or not
|
||||
// so we need "fake" tile loads to know when we can unload map geometry
|
||||
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||
TC_METRIC_EVENT("map_events", "LoadMapTile",
|
||||
"Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY));
|
||||
return true;
|
||||
}
|
||||
if (!iTreeValues)
|
||||
{
|
||||
VMAP_ERROR_LOG("misc", "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
|
||||
|
||||
@@ -46,7 +46,6 @@ namespace VMAP
|
||||
typedef std::unordered_map<uint32, uint32> loadedSpawnMap;
|
||||
private:
|
||||
uint32 iMapID;
|
||||
bool iIsTiled;
|
||||
BIH iTree;
|
||||
ModelInstance* iTreeValues; // the tree entries
|
||||
uint32 iNTreeValues;
|
||||
@@ -86,11 +85,10 @@ namespace VMAP
|
||||
bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
||||
bool GetLocationInfo(const G3D::Vector3 &pos, LocationInfo &info) const;
|
||||
|
||||
bool InitMap(const std::string &fname, VMapManager2* vm);
|
||||
bool InitMap(std::string const& fname);
|
||||
void UnloadMap(VMapManager2* vm);
|
||||
bool LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm);
|
||||
void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm);
|
||||
bool isTiled() const { return iIsTiled; }
|
||||
uint32 numLoadedTiles() const { return uint32(iLoadedTiles.size()); }
|
||||
void getModelInstances(ModelInstance* &models, uint32 &count);
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
*/
|
||||
|
||||
#include "TileAssembler.h"
|
||||
#include "MapTree.h"
|
||||
#include "BoundingIntervalHierarchy.h"
|
||||
#include "MapTree.h"
|
||||
#include "StringFormat.h"
|
||||
#include "VMapDefinitions.h"
|
||||
|
||||
#include <set>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
using G3D::Vector3;
|
||||
using G3D::AABox;
|
||||
@@ -48,7 +48,7 @@ namespace VMAP
|
||||
{
|
||||
Vector3 out = pIn * iScale;
|
||||
out = iRotation * out;
|
||||
return(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
@@ -57,12 +57,10 @@ namespace VMAP
|
||||
: iDestDir(pDestDirName), iSrcDir(pSrcDirName)
|
||||
{
|
||||
boost::filesystem::create_directory(iDestDir);
|
||||
//init();
|
||||
}
|
||||
|
||||
TileAssembler::~TileAssembler()
|
||||
{
|
||||
//delete iCoordModelMapping;
|
||||
}
|
||||
|
||||
bool TileAssembler::convertWorld2()
|
||||
@@ -71,32 +69,39 @@ namespace VMAP
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
float constexpr invTileSize = 1.0f / 533.33333f;
|
||||
|
||||
// export Map data
|
||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
|
||||
while (!mapData.empty())
|
||||
{
|
||||
MapSpawns data = std::move(mapData.front());
|
||||
mapData.pop_front();
|
||||
|
||||
// build global map tree
|
||||
std::vector<ModelSpawn*> mapSpawns;
|
||||
UniqueEntryMap::iterator entry;
|
||||
printf("Calculating model bounds for map %u...\n", map_iter->first);
|
||||
for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry)
|
||||
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)
|
||||
{
|
||||
// M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail
|
||||
if (entry->second.flags & MOD_M2)
|
||||
{
|
||||
if (!calculateTransformedBound(entry->second))
|
||||
continue;
|
||||
}
|
||||
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
|
||||
{
|
||||
/// @todo remove extractor hack and uncomment below line:
|
||||
//entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f);
|
||||
}
|
||||
|
||||
mapSpawns.push_back(&entry->second);
|
||||
spawnedModelFiles.insert(entry->second.name);
|
||||
|
||||
std::map<uint32, std::set<TileSpawn>>& 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)].emplace(entry->second.ID, entry->second.flags);
|
||||
}
|
||||
|
||||
printf("Creating map tree for map %u...\n", map_iter->first);
|
||||
printf("Creating map tree for map %u...\n", data.MapId);
|
||||
BIH pTree;
|
||||
|
||||
try
|
||||
@@ -112,7 +117,7 @@ namespace VMAP
|
||||
// ===> possibly move this code to StaticMapTree class
|
||||
// write map tree file
|
||||
std::stringstream mapfilename;
|
||||
mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree";
|
||||
mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(3) << data.MapId << ".vmtree";
|
||||
FILE* mapfile = fopen(mapfilename.str().c_str(), "wb");
|
||||
if (!mapfile)
|
||||
{
|
||||
@@ -123,24 +128,12 @@ namespace VMAP
|
||||
|
||||
//general info
|
||||
if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) success = false;
|
||||
uint32 globalTileID = StaticMapTree::packTileID(65, 65);
|
||||
pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
|
||||
char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO
|
||||
if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) success = false;
|
||||
// Nodes
|
||||
if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false;
|
||||
if (success) success = pTree.writeToFile(mapfile);
|
||||
// global map spawns (WDT), if any (most instances)
|
||||
if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) success = false;
|
||||
|
||||
for (TileMap::iterator glob=globalRange.first; glob != globalRange.second && success; ++glob)
|
||||
{
|
||||
success = ModelSpawn::writeToFile(mapfile, map_iter->second->UniqueEntries[glob->second.Id]);
|
||||
}
|
||||
|
||||
// spawn id to index map
|
||||
if (success && fwrite("SIDX", 4, 1, mapfile) != 1) success = false;
|
||||
uint32 mapSpawnsSize = mapSpawns.size();
|
||||
if (success && fwrite("SIDX", 4, 1, mapfile) != 1) success = false;
|
||||
if (success && fwrite(&mapSpawnsSize, sizeof(uint32), 1, mapfile) != 1) success = false;
|
||||
for (uint32 i = 0; i < mapSpawnsSize; ++i)
|
||||
{
|
||||
@@ -152,37 +145,30 @@ namespace VMAP
|
||||
|
||||
// <====
|
||||
|
||||
// write map tile files, similar to ADT files, only with extra BSP tree node info
|
||||
TileMap &tileEntries = map_iter->second->TileEntries;
|
||||
TileMap::iterator tile;
|
||||
for (tile = tileEntries.begin(); tile != tileEntries.end(); ++tile)
|
||||
// write map tile files, similar to ADT files, only with extra BIH tree node info
|
||||
for (auto tileItr = data.TileEntries.begin(); tileItr != data.TileEntries.end(); ++tileItr)
|
||||
{
|
||||
if (tile->second.Flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
|
||||
continue;
|
||||
if (tile->second.Flags & MOD_PARENT_SPAWN) // tile belongs to parent map
|
||||
continue;
|
||||
uint32 nSpawns = tileEntries.count(tile->first);
|
||||
std::stringstream tilefilename;
|
||||
tilefilename.fill('0');
|
||||
tilefilename << iDestDir << '/' << std::setw(3) << map_iter->first << '_';
|
||||
uint32 x, y;
|
||||
StaticMapTree::unpackTileID(tile->first, x, y);
|
||||
tilefilename << std::setw(2) << x << '_' << std::setw(2) << y << ".vmtile";
|
||||
if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
|
||||
StaticMapTree::unpackTileID(tileItr->first, x, y);
|
||||
std::string tileFileName = Trinity::StringFormat("%s/%03u_%02u_%02u.vmtile", iDestDir.c_str(), data.MapId, y, x);
|
||||
if (FILE* tileFile = fopen(tileFileName.c_str(), "wb"))
|
||||
{
|
||||
std::set<TileSpawn> const& parentTileEntries = data.ParentTileEntries[tileItr->first];
|
||||
|
||||
uint32 nSpawns = tileItr->second.size() + parentTileEntries.size();
|
||||
|
||||
// file header
|
||||
if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) success = false;
|
||||
if (success && fwrite(VMAP_MAGIC, 1, 8, tileFile) != 8) success = false;
|
||||
// write number of tile spawns
|
||||
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) success = false;
|
||||
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tileFile) != 1) success = false;
|
||||
// write tile spawns
|
||||
for (uint32 s=0; s<nSpawns; ++s)
|
||||
{
|
||||
if (s)
|
||||
++tile;
|
||||
const ModelSpawn &spawn2 = map_iter->second->UniqueEntries[tile->second.Id];
|
||||
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
|
||||
}
|
||||
fclose(tilefile);
|
||||
for (auto spawnItr = tileItr->second.begin(); spawnItr != tileItr->second.end() && success; ++spawnItr)
|
||||
success = ModelSpawn::writeToFile(tileFile, data.UniqueEntries[spawnItr->Id]);
|
||||
|
||||
for (auto spawnItr = parentTileEntries.begin(); spawnItr != parentTileEntries.end() && success; ++spawnItr)
|
||||
success = ModelSpawn::writeToFile(tileFile, data.UniqueEntries[spawnItr->Id]);
|
||||
|
||||
fclose(tileFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,12 +187,6 @@ namespace VMAP
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//cleanup:
|
||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end(); ++map_iter)
|
||||
{
|
||||
delete map_iter->second;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -220,33 +200,34 @@ namespace VMAP
|
||||
return false;
|
||||
}
|
||||
printf("Read coordinate mapping...\n");
|
||||
uint32 mapID, tileX, tileY, check;
|
||||
G3D::Vector3 v1, v2;
|
||||
ModelSpawn spawn;
|
||||
uint32 mapID, check = 0;
|
||||
std::map<uint32, MapSpawns> data;
|
||||
while (!feof(dirf))
|
||||
{
|
||||
// read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
// read mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
check = fread(&mapID, sizeof(uint32), 1, dirf);
|
||||
if (check == 0) // EoF...
|
||||
break;
|
||||
fread(&tileX, sizeof(uint32), 1, dirf);
|
||||
fread(&tileY, sizeof(uint32), 1, dirf);
|
||||
|
||||
ModelSpawn spawn;
|
||||
if (!ModelSpawn::readFromFile(dirf, spawn))
|
||||
break;
|
||||
|
||||
MapSpawns *current;
|
||||
MapData::iterator map_iter = mapData.find(mapID);
|
||||
if (map_iter == mapData.end())
|
||||
auto map_iter = data.emplace(std::piecewise_construct, std::forward_as_tuple(mapID), std::forward_as_tuple());
|
||||
if (map_iter.second)
|
||||
{
|
||||
map_iter.first->second.MapId = mapID;
|
||||
printf("spawning Map %u\n", mapID);
|
||||
mapData[mapID] = current = new MapSpawns();
|
||||
}
|
||||
else
|
||||
current = map_iter->second;
|
||||
|
||||
current->UniqueEntries.emplace(spawn.ID, spawn);
|
||||
current->TileEntries.insert(pair<uint32, TileSpawn>(StaticMapTree::packTileID(tileX, tileY), TileSpawn{ spawn.ID, spawn.flags }));
|
||||
map_iter.first->second.UniqueEntries.emplace(spawn.ID, spawn);
|
||||
}
|
||||
|
||||
mapData.resize(data.size());
|
||||
auto dst = mapData.begin();
|
||||
for (auto src = data.begin(); src != data.end(); ++src, ++dst)
|
||||
*dst = std::move(src->second);
|
||||
|
||||
bool success = (ferror(dirf) == 0);
|
||||
fclose(dirf);
|
||||
return success;
|
||||
@@ -272,29 +253,10 @@ namespace VMAP
|
||||
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
|
||||
|
||||
AABox modelBound;
|
||||
bool boundEmpty=true;
|
||||
|
||||
for (uint32 g=0; g<groups; ++g) // should be only one for M2 files...
|
||||
{
|
||||
std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;
|
||||
modelBound.merge(modelPosition.transform(raw_model.groupsArray[0].bounds.low()));
|
||||
modelBound.merge(modelPosition.transform(raw_model.groupsArray[0].bounds.high()));
|
||||
|
||||
if (vertices.empty())
|
||||
{
|
||||
std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 nvectors = vertices.size();
|
||||
for (uint32 i = 0; i < nvectors; ++i)
|
||||
{
|
||||
Vector3 v = modelPosition.transform(vertices[i]);
|
||||
|
||||
if (boundEmpty)
|
||||
modelBound = AABox(v, v), boundEmpty=false;
|
||||
else
|
||||
modelBound.merge(v);
|
||||
}
|
||||
}
|
||||
spawn.iBound = modelBound + spawn.iPos;
|
||||
spawn.flags |= MOD_HAS_BOUND;
|
||||
return true;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <G3D/Vector3.h>
|
||||
#include <G3D/Matrix3.h>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
@@ -54,20 +55,26 @@ namespace VMAP
|
||||
|
||||
struct TileSpawn
|
||||
{
|
||||
TileSpawn() : Id(0), Flags(0) { }
|
||||
TileSpawn(uint32 id, uint32 flags) : Id(id), Flags(flags) { }
|
||||
|
||||
uint32 Id;
|
||||
uint32 Flags;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, ModelSpawn> UniqueEntryMap;
|
||||
typedef std::multimap<uint32, TileSpawn> TileMap;
|
||||
bool operator<(TileSpawn const& right) const { return Id < right.Id; }
|
||||
};
|
||||
|
||||
struct TC_COMMON_API MapSpawns
|
||||
{
|
||||
UniqueEntryMap UniqueEntries;
|
||||
TileMap TileEntries;
|
||||
MapSpawns() { }
|
||||
|
||||
uint32 MapId;
|
||||
std::map<uint32, ModelSpawn> UniqueEntries;
|
||||
std::map<uint32 /*packedTileId*/, std::set<TileSpawn>> TileEntries;
|
||||
std::map<uint32 /*packedTileId*/, std::set<TileSpawn>> ParentTileEntries;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, MapSpawns*> MapData;
|
||||
typedef std::deque<MapSpawns> MapData;
|
||||
//===============================================
|
||||
|
||||
struct TC_COMMON_API GroupModel_Raw
|
||||
@@ -101,7 +108,6 @@ namespace VMAP
|
||||
private:
|
||||
std::string iDestDir;
|
||||
std::string iSrcDir;
|
||||
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
||||
MapData mapData;
|
||||
std::set<std::string> spawnedModelFiles;
|
||||
|
||||
|
||||
@@ -36,9 +36,8 @@ namespace VMAP
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1 << 1,
|
||||
MOD_HAS_BOUND = 1 << 2,
|
||||
MOD_PARENT_SPAWN = 1 << 3
|
||||
MOD_HAS_BOUND = 1 << 1,
|
||||
MOD_PARENT_SPAWN = 1 << 2
|
||||
};
|
||||
|
||||
class TC_COMMON_API ModelSpawn
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
const char VMAP_MAGIC[] = "VMAP_4.6";
|
||||
const char RAW_VMAP_MAGIC[] = "VMAP046"; // used in extracted vmap files with raw data
|
||||
const char VMAP_MAGIC[] = "VMAP_4.7";
|
||||
const char RAW_VMAP_MAGIC[] = "VMAP047"; // used in extracted vmap files with raw data
|
||||
const char GAMEOBJECT_MODELS[] = "GameObjectModels.dtree";
|
||||
|
||||
// defined in TileAssembler.cpp currently...
|
||||
|
||||
@@ -83,10 +83,10 @@ ADTFile::ADTFile(char* filename, bool cache) : _file(WorldMpq, filename, false)
|
||||
dirfileCache = nullptr;
|
||||
}
|
||||
|
||||
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMapId)
|
||||
bool ADTFile::init(uint32 map_num, uint32 originalMapId)
|
||||
{
|
||||
if (dirfileCache)
|
||||
return initFromCache(map_num, tileX, tileY, originalMapId);
|
||||
return initFromCache(map_num, originalMapId);
|
||||
|
||||
if (_file.isEof ())
|
||||
return false;
|
||||
@@ -191,7 +191,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa
|
||||
{
|
||||
ADT::MDDF doodadDef;
|
||||
_file.read(&doodadDef, sizeof(ADT::MDDF));
|
||||
Doodad::Extract(doodadDef, ModelInstanceNames[doodadDef.Id].c_str(), map_num, tileX, tileY, originalMapId, dirfile, dirfileCache);
|
||||
Doodad::Extract(doodadDef, ModelInstanceNames[doodadDef.Id].c_str(), map_num, originalMapId, dirfile, dirfileCache);
|
||||
}
|
||||
|
||||
ModelInstanceNames.clear();
|
||||
@@ -206,8 +206,8 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa
|
||||
{
|
||||
ADT::MODF mapObjDef;
|
||||
_file.read(&mapObjDef, sizeof(ADT::MODF));
|
||||
MapObject::Extract(mapObjDef, WmoInstanceNames[mapObjDef.Id].c_str(), map_num, tileX, tileY, originalMapId, dirfile, dirfileCache);
|
||||
Doodad::ExtractSet(WmoDoodads[WmoInstanceNames[mapObjDef.Id]], mapObjDef, map_num, tileX, tileY, originalMapId, dirfile, dirfileCache);
|
||||
MapObject::Extract(mapObjDef, WmoInstanceNames[mapObjDef.Id].c_str(), false, map_num, originalMapId, dirfile, dirfileCache);
|
||||
Doodad::ExtractSet(WmoDoodads[WmoInstanceNames[mapObjDef.Id]], mapObjDef, false, map_num, originalMapId, dirfile, dirfileCache);
|
||||
}
|
||||
|
||||
WmoInstanceNames.clear();
|
||||
@@ -223,7 +223,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADTFile::initFromCache(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMapId)
|
||||
bool ADTFile::initFromCache(uint32 map_num, uint32 originalMapId)
|
||||
{
|
||||
if (dirfileCache->empty())
|
||||
return true;
|
||||
@@ -239,8 +239,6 @@ bool ADTFile::initFromCache(uint32 map_num, uint32 tileX, uint32 tileY, uint32 o
|
||||
for (ADTOutputCache const& cached : *dirfileCache)
|
||||
{
|
||||
fwrite(&map_num, sizeof(uint32), 1, dirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, dirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, dirfile);
|
||||
uint32 flags = cached.Flags;
|
||||
if (map_num != originalMapId)
|
||||
flags |= MOD_PARENT_SPAWN;
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
~ADTFile();
|
||||
std::vector<std::string> WmoInstanceNames;
|
||||
std::vector<std::string> ModelInstanceNames;
|
||||
bool init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMapId);
|
||||
bool initFromCache(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMapId);
|
||||
bool init(uint32 map_num, uint32 originalMapId);
|
||||
bool initFromCache(uint32 map_num, uint32 originalMapId);
|
||||
};
|
||||
|
||||
char const* GetPlainName(char const* FileName);
|
||||
|
||||
@@ -50,6 +50,7 @@ bool Model::open()
|
||||
_unload();
|
||||
|
||||
memcpy(&header, f.getBuffer(), sizeof(ModelHeader));
|
||||
bounds = header.collisionBox;
|
||||
if (header.nBoundingTriangles > 0)
|
||||
{
|
||||
f.seek(0);
|
||||
@@ -86,18 +87,18 @@ bool Model::ConvertToVMAPModel(const char * outfilename)
|
||||
uint32 nVertices = header.nBoundingVertices;
|
||||
fwrite(&nVertices, sizeof(int), 1, output);
|
||||
uint32 nofgroups = 1;
|
||||
fwrite(&nofgroups,sizeof(uint32), 1, output);
|
||||
fwrite(N,4*3,1,output);// rootwmoid, flags, groupid
|
||||
fwrite(N,sizeof(float),3*2,output);//bbox, only needed for WMO currently
|
||||
fwrite(N,4,1,output);// liquidflags
|
||||
fwrite("GRP ",4,1,output);
|
||||
fwrite(&nofgroups, sizeof(uint32), 1, output);
|
||||
fwrite(N, 4 * 3, 1, output);// rootwmoid, flags, groupid
|
||||
fwrite(&bounds, sizeof(AaBox3D), 1, output);//bbox, only needed for WMO currently
|
||||
fwrite(N, 4, 1, output);// liquidflags
|
||||
fwrite("GRP ", 4, 1, output);
|
||||
uint32 branches = 1;
|
||||
int wsize;
|
||||
wsize = sizeof(branches) + sizeof(uint32) * branches;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&branches,sizeof(branches), 1, output);
|
||||
fwrite(&branches, sizeof(branches), 1, output);
|
||||
uint32 nIndexes = header.nBoundingTriangles;
|
||||
fwrite(&nIndexes,sizeof(uint32), 1, output);
|
||||
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
||||
fwrite("INDX",4, 1, output);
|
||||
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
@@ -137,14 +138,12 @@ bool Model::ConvertToVMAPModel(const char * outfilename)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D const& v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, -v.y);
|
||||
}
|
||||
|
||||
void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId,
|
||||
FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
|
||||
void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
|
||||
{
|
||||
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
|
||||
float sc = doodadDef.Scale / 1024.0f;
|
||||
@@ -169,15 +168,11 @@ void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint
|
||||
uint16 nameSet = 0;// not used for models
|
||||
uint32 uniqueId = GenerateUniqueObjectId(doodadDef.UniqueId, 0);
|
||||
uint32 flags = MOD_M2;
|
||||
if (tileX == 65 && tileY == 65)
|
||||
flags |= MOD_WORLDSPAWN;
|
||||
if (mapID != originalMapId)
|
||||
flags |= MOD_PARENT_SPAWN;
|
||||
|
||||
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
|
||||
//write mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&nameSet, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
|
||||
@@ -215,7 +210,7 @@ void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint
|
||||
}
|
||||
}
|
||||
|
||||
void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId,
|
||||
void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, bool isGlobalWmo, uint32 mapID, uint32 originalMapId,
|
||||
FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
|
||||
{
|
||||
if (wmo.DoodadSet >= doodadData.Sets.size())
|
||||
@@ -224,6 +219,9 @@ void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, u
|
||||
G3D::Vector3 wmoPosition(wmo.Position.z, wmo.Position.x, wmo.Position.y);
|
||||
G3D::Matrix3 wmoRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::toRadians(wmo.Rotation.y), G3D::toRadians(wmo.Rotation.x), G3D::toRadians(wmo.Rotation.z));
|
||||
|
||||
if (isGlobalWmo)
|
||||
wmoPosition += G3D::Vector3(533.33333f * 32, 533.33333f * 32, 0.0f);
|
||||
|
||||
uint16 doodadId = 0;
|
||||
WMO::MODS const& doodadSetData = doodadData.Sets[wmo.DoodadSet];
|
||||
for (uint16 doodadIndex : doodadData.References)
|
||||
@@ -280,15 +278,11 @@ void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, u
|
||||
uint16 nameSet = 0; // not used for models
|
||||
uint32 uniqueId = GenerateUniqueObjectId(wmo.UniqueId, doodadId);
|
||||
uint32 tcflags = MOD_M2;
|
||||
if (tileX == 65 && tileY == 65)
|
||||
tcflags |= MOD_WORLDSPAWN;
|
||||
if (mapID != originalMapId)
|
||||
tcflags |= MOD_PARENT_SPAWN;
|
||||
|
||||
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
|
||||
//write mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tcflags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&nameSet, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
ModelHeader header;
|
||||
Vec3D* vertices;
|
||||
uint16* indices;
|
||||
AaBox3D bounds;
|
||||
|
||||
bool open();
|
||||
bool ConvertToVMAPModel(char const* outfilename);
|
||||
@@ -55,10 +56,10 @@ public:
|
||||
|
||||
namespace Doodad
|
||||
{
|
||||
void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId,
|
||||
void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 originalMapId,
|
||||
FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache);
|
||||
|
||||
void ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId,
|
||||
void ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, bool isGlobalWmo, uint32 mapID, uint32 originalMapId,
|
||||
FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#ifndef MODELHEADERS_H
|
||||
#define MODELHEADERS_H
|
||||
|
||||
#include "mpqfile.h" // integer typedefs
|
||||
#include "Define.h"
|
||||
#include "vec3d.h"
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
@@ -65,7 +66,10 @@ struct ModelHeader
|
||||
uint32 ofsTransLookup;
|
||||
uint32 nTexAnimLookup;
|
||||
uint32 ofsTexAnimLookup;
|
||||
float floats[14];
|
||||
AaBox3D boundingBox;
|
||||
float boundingSphereRadius;
|
||||
AaBox3D collisionBox;
|
||||
float collisionSphereRadius;
|
||||
uint32 nBoundingTriangles;
|
||||
uint32 ofsBoundingTriangles;
|
||||
uint32 nBoundingVertices;
|
||||
|
||||
@@ -142,6 +142,13 @@ class AaBox3D
|
||||
public:
|
||||
Vec3D min;
|
||||
Vec3D max;
|
||||
|
||||
AaBox3D& operator+=(Vec3D const& offset)
|
||||
{
|
||||
min += offset;
|
||||
max += offset;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class Vec2D
|
||||
|
||||
@@ -483,14 +483,14 @@ void ParsMapFiles()
|
||||
bool success = false;
|
||||
if (ADTFile* ADT = WDT->GetMap(x, y))
|
||||
{
|
||||
success = ADT->init(itr->first, x, y, itr->first);
|
||||
success = ADT->init(itr->first, itr->first);
|
||||
WDT->FreeADT(ADT);
|
||||
}
|
||||
if (!success && parentWDT)
|
||||
{
|
||||
if (ADTFile* ADT = parentWDT->GetMap(x, y))
|
||||
{
|
||||
ADT->init(itr->first, x, y, itr->second.parent_id);
|
||||
ADT->init(itr->first, itr->second.parent_id);
|
||||
parentWDT->FreeADT(ADT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,8 @@ struct WMODoodadData;
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1 << 1,
|
||||
MOD_HAS_BOUND = 1 << 2,
|
||||
MOD_PARENT_SPAWN = 1 << 3
|
||||
MOD_HAS_BOUND = 1 << 1,
|
||||
MOD_PARENT_SPAWN = 1 << 2
|
||||
};
|
||||
|
||||
extern const char * szWorkDirWmo;
|
||||
|
||||
@@ -108,8 +108,8 @@ bool WDTFile::init(uint32 mapId)
|
||||
{
|
||||
ADT::MODF mapObjDef;
|
||||
_file.read(&mapObjDef, sizeof(ADT::MODF));
|
||||
MapObject::Extract(mapObjDef, _wmoNames[mapObjDef.Id].c_str(), mapId, 65, 65, mapId, dirfile, nullptr);
|
||||
Doodad::ExtractSet(WmoDoodads[_wmoNames[mapObjDef.Id]], mapObjDef, mapId, 65, 65, mapId, dirfile, nullptr);
|
||||
MapObject::Extract(mapObjDef, _wmoNames[mapObjDef.Id].c_str(), true, mapId, mapId, dirfile, nullptr);
|
||||
Doodad::ExtractSet(WmoDoodads[_wmoNames[mapObjDef.Id]], mapObjDef, true, mapId, mapId, dirfile, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,7 +509,7 @@ WMOGroup::~WMOGroup()
|
||||
delete [] LiquBytes;
|
||||
}
|
||||
|
||||
void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
|
||||
void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, bool isGlobalWmo, uint32 mapID, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
|
||||
{
|
||||
// destructible wmo, do not dump. we can handle the vmap for these
|
||||
// in dynamic tree (gameobject vmaps)
|
||||
@@ -520,8 +520,7 @@ void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uin
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName);
|
||||
FILE *input;
|
||||
input = fopen(tempname, "r+b");
|
||||
FILE* input = fopen(tempname, "r+b");
|
||||
|
||||
if (!input)
|
||||
{
|
||||
@@ -537,33 +536,25 @@ void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uin
|
||||
if (count != 1 || nVertices == 0)
|
||||
return;
|
||||
|
||||
Vec3D position = mapObjDef.Position;
|
||||
|
||||
float x, z;
|
||||
x = position.x;
|
||||
z = position.z;
|
||||
if (x == 0 && z == 0)
|
||||
{
|
||||
position.x = 533.33333f * 32;
|
||||
position.z = 533.33333f * 32;
|
||||
}
|
||||
position = fixCoords(position);
|
||||
Vec3D position = fixCoords(mapObjDef.Position);
|
||||
AaBox3D bounds;
|
||||
bounds.min = fixCoords(mapObjDef.Bounds.min);
|
||||
bounds.max = fixCoords(mapObjDef.Bounds.max);
|
||||
|
||||
if (isGlobalWmo)
|
||||
{
|
||||
position += Vec3D(533.33333f * 32, 533.33333f * 32, 0.0f);
|
||||
bounds += Vec3D(533.33333f * 32, 533.33333f * 32, 0.0f);
|
||||
}
|
||||
|
||||
float scale = 1.0f;
|
||||
uint32 uniqueId = GenerateUniqueObjectId(mapObjDef.UniqueId, 0);
|
||||
uint32 flags = MOD_HAS_BOUND;
|
||||
if (tileX == 65 && tileY == 65)
|
||||
flags |= MOD_WORLDSPAWN;
|
||||
if (mapID != originalMapId)
|
||||
flags |= MOD_PARENT_SPAWN;
|
||||
|
||||
//write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
//write mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&mapObjDef.NameSet, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
|
||||
|
||||
@@ -158,7 +158,8 @@ public:
|
||||
|
||||
namespace MapObject
|
||||
{
|
||||
void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache);
|
||||
void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, bool isGlobalWmo, uint32 mapID, uint32 originalMapId,
|
||||
FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user