TrinityCore
Loading...
Searching...
No Matches
VMapManager.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "VMapManager.h"
19#include "Errors.h"
20#include "Log.h"
21#include "MapTree.h"
22#include "ModelInstance.h"
23#include "VMapDefinitions.h"
24#include "WorldModel.h"
25#include <G3D/Vector3.h>
26
27namespace VMAP
28{
30 {
31 public:
32 explicit ManagedModel(VMapManager& mgr, std::string const& name) : _mgr(mgr), _name(name) { }
33
34 ManagedModel(ManagedModel const&) = delete;
36
39
44
46
47 private:
49 std::string const& _name; // valid only while model is held in VMapManager::iLoadedModelFiles
50 };
51
52 bool readChunk(FILE* rf, char* dest, const char* compare, uint32 len)
53 {
54 if (fread(dest, sizeof(char), len, rf) != len) return false;
55 return memcmp(dest, compare, len) == 0;
56 }
57
59 iEnableLineOfSightCalc(true),
60 iEnableHeightCalc(true),
61 thread_safe_environment(true),
62 GetLiquidFlagsPtr([](uint32 /*liquidTypeId*/) { return 0u; }),
63 IsVMAPDisabledForPtr([](uint32 /*mapId*/, uint8 /*disableFlags*/) { return false; }),
64 LoadPathOnlyModels(false)
65 {
66 }
67
68 VMapManager::~VMapManager() = default;
69
70 InstanceTreeMap::const_iterator VMapManager::GetMapTree(uint32 mapId) const
71 {
72 // return the iterator if found or end() if not found/NULL
73 auto itr = iInstanceMapTrees.find(mapId);
74 if (itr != iInstanceMapTrees.cend() && !itr->second)
75 itr = iInstanceMapTrees.cend();
76
77 return itr;
78 }
79
80 void VMapManager::InitializeThreadUnsafe(std::unordered_map<uint32, std::vector<uint32>> const& mapData)
81 {
82 // the caller must pass the list of all mapIds that will be used in the VMapManager lifetime
83 for (auto const& [mapId, childMapIds] : mapData)
84 {
85 iInstanceMapTrees[mapId] = nullptr;
86 for (uint32 childMapId : childMapIds)
87 iParentMapData[childMapId] = mapId;
88 }
89
91 }
92
94 {
95 iInstanceMapTrees[mapId] = nullptr;
96 if (parentMapId >= 0)
97 iParentMapData[mapId] = parentMapId;
98 }
99
100 inline static G3D::Vector3 convertPositionToInternalRep(float x, float y, float z)
101 {
102 G3D::Vector3 pos;
103 constexpr float mid = 0.5f * 64.0f * 533.33333333f;
104 pos.x = mid - x;
105 pos.y = mid - y;
106 pos.z = z;
107
108 return pos;
109 }
110
112 {
113 return Trinity::StringFormat("{:04}/{:04}.vmtree", mapId, mapId);
114 }
115
116 std::string VMapManager::getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY, std::string_view extension)
117 {
118 return Trinity::StringFormat("{:04}/{:04}_{:02}_{:02}.{}", mapID, mapID, tileX, tileY, extension);
119 }
120
121 LoadResult VMapManager::loadMap(std::string const& basePath, uint32 mapId, uint32 x, uint32 y)
122 {
123 if (!isMapLoadingEnabled())
125
126 auto instanceTree = iInstanceMapTrees.find(mapId);
127 if (instanceTree == iInstanceMapTrees.end())
128 {
130 instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first;
131 else
132 ABORT_MSG("Invalid mapId %u tile [%u, %u] passed to VMapManager after startup in thread unsafe environment",
133 mapId, x, y);
134 }
135
136 if (!instanceTree->second)
137 {
138 std::string mapFileName = getMapFileName(mapId);
139 std::unique_ptr<StaticMapTree> newTree = std::make_unique<StaticMapTree>(mapId, basePath);
140 LoadResult treeInitResult = newTree->InitMap(mapFileName);
141 if (treeInitResult != LoadResult::Success)
142 return treeInitResult;
143
144 instanceTree->second = std::move(newTree);
145 }
146
147 return instanceTree->second->LoadMapTile(x, y, this);
148 }
149
151 {
152 auto instanceTree = iInstanceMapTrees.find(mapId);
153 if (instanceTree != iInstanceMapTrees.end() && instanceTree->second)
154 {
155 instanceTree->second->UnloadMapTile(x, y);
156 if (instanceTree->second->numLoadedTiles() == 0)
157 instanceTree->second = nullptr;
158 }
159 }
160
162 {
163 auto instanceTree = iInstanceMapTrees.find(mapId);
164 if (instanceTree != iInstanceMapTrees.end() && instanceTree->second)
165 {
166 instanceTree->second->UnloadMap();
167 if (instanceTree->second->numLoadedTiles() == 0)
168 instanceTree->second = nullptr;
169 }
170 }
171
172 bool VMapManager::isInLineOfSight(uint32 mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
173 {
175 return true;
176
177 auto instanceTree = GetMapTree(mapId);
178 if (instanceTree != iInstanceMapTrees.end())
179 {
180 G3D::Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
181 G3D::Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2);
182 if (pos1 != pos2)
183 return instanceTree->second->isInLineOfSight(pos1, pos2, ignoreFlags);
184 }
185
186 return true;
187 }
188
193 bool VMapManager::getObjectHitPos(uint32 mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist)
194 {
196 {
197 auto instanceTree = GetMapTree(mapId);
198 if (instanceTree != iInstanceMapTrees.end())
199 {
200 G3D::Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
201 G3D::Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2);
202 G3D::Vector3 resultPos;
203 bool result = instanceTree->second->getObjectHitPos(pos1, pos2, resultPos, modifyDist);
204 resultPos = convertPositionToInternalRep(resultPos.x, resultPos.y, resultPos.z);
205 rx = resultPos.x;
206 ry = resultPos.y;
207 rz = resultPos.z;
208 return result;
209 }
210 }
211
212 rx = x2;
213 ry = y2;
214 rz = z2;
215
216 return false;
217 }
218
223 float VMapManager::getHeight(uint32 mapId, float x, float y, float z, float maxSearchDist)
224 {
226 {
227 auto instanceTree = GetMapTree(mapId);
228 if (instanceTree != iInstanceMapTrees.end())
229 {
230 G3D::Vector3 pos = convertPositionToInternalRep(x, y, z);
231 float height = instanceTree->second->getHeight(pos, maxSearchDist);
232 if (!(height < G3D::finf()))
233 return height = VMAP_INVALID_HEIGHT_VALUE; // No height
234
235 return height;
236 }
237 }
238
240 }
241
242 bool VMapManager::getAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional<uint8> reqLiquidType, AreaAndLiquidData& data) const
243 {
244 InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
245 if (instanceTree != iInstanceMapTrees.end())
246 {
247 LocationInfo info;
248 G3D::Vector3 pos = convertPositionToInternalRep(x, y, z);
249 if (instanceTree->second->GetLocationInfo(pos, info))
250 {
251 data.floorZ = info.ground_Z;
253 {
254 uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
255 float liquidLevel;
256 if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & *reqLiquidType))
257 if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel))
258 data.liquidInfo.emplace(liquidType, liquidLevel);
259 }
260
262 data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID);
263
264 return true;
265 }
266 }
267
268 return false;
269 }
270
271 std::shared_ptr<WorldModel> VMapManager::acquireModelInstance(std::string const& basepath, std::string const& filename)
272 {
273 std::shared_ptr<ManagedModel> worldmodel; // this is intentionally declared before lock so that it is destroyed after it to prevent deadlocks in releaseModelInstance
274
276 std::scoped_lock lock(LoadedModelFilesLock);
277
278 auto& [key, model] = *iLoadedModelFiles.try_emplace(filename).first;
279 worldmodel = model.lock();
280 if (worldmodel)
281 return std::shared_ptr<WorldModel>(worldmodel, &worldmodel->Model);
282
283 worldmodel = std::make_shared<ManagedModel>(*this, key);
284 if (!worldmodel->Model.readFile(basepath + filename + ".vmo"))
285 {
286 TC_LOG_ERROR("misc", "VMapManager: could not load '{}{}.vmo'", basepath, filename);
287 return nullptr;
288 }
289 TC_LOG_DEBUG("maps", "VMapManager: loading file '{}{}'", basepath, filename);
290
291 model = worldmodel;
292
293 return std::shared_ptr<WorldModel>(worldmodel, &worldmodel->Model);
294 }
295
296 void VMapManager::releaseModelInstance(std::string const& filename)
297 {
299 std::scoped_lock lock(LoadedModelFilesLock);
300
301 TC_LOG_DEBUG("maps", "VMapManager: unloading file '{}'", filename);
302
303 std::size_t erased = iLoadedModelFiles.erase(filename);
304 if (!erased)
305 TC_LOG_ERROR("misc", "VMapManager: trying to unload non-loaded file '{}'", filename);
306 }
307
308 LoadResult VMapManager::existsMap(std::string const& basePath, uint32 mapId, uint32 x, uint32 y)
309 {
310 return StaticMapTree::CanLoadMap(basePath, mapId, x, y, this);
311 }
312
313 std::span<ModelInstance const> VMapManager::getModelsOnMap(uint32 mapId) const
314 {
315 InstanceTreeMap::const_iterator mapTree = GetMapTree(mapId);
316 if (mapTree != iInstanceMapTrees.end())
317 return mapTree->second->getModelInstances();
318
319 return {};
320 }
321
323 {
324 auto itr = iParentMapData.find(mapId);
325 if (itr != iParentMapData.end())
326 return int32(itr->second);
327
328 return -1;
329 }
330
331} // namespace VMAP
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define ABORT_MSG
Definition Errors.h:88
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
#define VMAP_INVALID_HEIGHT_VALUE
Definition VMapManager.h:71
uint32 GetLiquidType() const
uint32 GetMogpFlags() const
Definition WorldModel.h:101
uint32 GetWmoID() const
Definition WorldModel.h:102
ManagedModel(ManagedModel const &)=delete
ManagedModel(ManagedModel &&)=delete
ManagedModel(VMapManager &mgr, std::string const &name)
VMapManager & _mgr
std::string const & _name
ManagedModel & operator=(ManagedModel const &)=delete
ManagedModel & operator=(ManagedModel &&)=delete
bool GetLiquidLevel(G3D::Vector3 const &p, LocationInfo &info, float &liqHeight) const
static LoadResult CanLoadMap(std::string const &basePath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager *vm)
Definition MapTree.cpp:228
bool getAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional< uint8 > reqLiquidType, AreaAndLiquidData &data) const
bool getObjectHitPos(uint32 mapId, float x1, float y1, float z1, float x2, float y2, float z2, float &rx, float &ry, float &rz, float modifyDist)
bool isLineOfSightCalcEnabled() const
LoadResult existsMap(std::string const &basePath, uint32 mapId, uint32 x, uint32 y)
bool isHeightCalcEnabled() const
LoadResult loadMap(std::string const &basePath, uint32 mapId, uint32 x, uint32 y)
void unloadMap(uint32 mapId, uint32 x, uint32 y)
InstanceTreeMap::const_iterator GetMapTree(uint32 mapId) const
float getHeight(uint32 mapId, float x, float y, float z, float maxSearchDist)
bool isMapLoadingEnabled() const
ModelFileMap iLoadedModelFiles
static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY, std::string_view extension)
std::shared_ptr< WorldModel > acquireModelInstance(std::string const &basepath, std::string const &filename)
std::unordered_map< uint32, uint32 > iParentMapData
std::mutex LoadedModelFilesLock
GetLiquidFlagsFn GetLiquidFlagsPtr
int32 getParentMapId(uint32 mapId) const
InstanceTreeMap iInstanceMapTrees
void InitializeThreadUnsafe(std::unordered_map< uint32, std::vector< uint32 > > const &mapData)
static std::string getMapFileName(uint32 mapId)
std::span< ModelInstance const > getModelsOnMap(uint32 mapId) const
bool isInLineOfSight(uint32 mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
IsVMAPDisabledForFn IsVMAPDisabledForPtr
void releaseModelInstance(std::string const &filename)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len)
static G3D::Vector3 convertPositionToInternalRep(float x, float y, float z)
@ VMAP_DISABLE_LIQUIDSTATUS
Definition VMapManager.h:58
@ VMAP_DISABLE_LOS
Definition VMapManager.h:57
@ VMAP_DISABLE_HEIGHT
Definition VMapManager.h:56
@ VMAP_DISABLE_AREAFLAG
Definition VMapManager.h:55
Optional< AreaInfo > areaInfo
Definition VMapManager.h:95
Optional< LiquidInfo > liquidInfo
Definition VMapManager.h:96
GroupModel const * hitModel
Definition MapTree.h:45
ModelInstance const * hitInstance
Definition MapTree.h:44