2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "VMapFactory.h"
20 #include "VMapManager2.h"
21 #include "VMapDefinitions.h"
22 #include "WorldModel.h"
23 #include "GameObjectModel.h"
32 struct GameobjectModelData
34 GameobjectModelData(char const* name_
, uint32 nameLength
, Vector3
const& lowBound
, Vector3
const& highBound
, bool isWmo_
) :
35 bound(lowBound
, highBound
), name(name_
, nameLength
), isWmo(isWmo_
) { }
42 typedef std::unordered_map
<uint32
, GameobjectModelData
> ModelList
;
45 void LoadGameObjectModelList(std::string
const& dataPath
)
47 uint32 oldMSTime
= getMSTime();
49 FILE* model_list_file
= fopen((dataPath
+ "vmaps/" + VMAP::GAMEOBJECT_MODELS
).c_str(), "rb");
52 TC_LOG_ERROR("misc", "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS
);
57 if (fread(magic
, 1, 8, model_list_file
) != 8
58 || memcmp(magic
, VMAP::VMAP_MAGIC
, 8) != 0)
60 TC_LOG_ERROR("misc", "File '%s' has wrong header, expected %s.", VMAP::GAMEOBJECT_MODELS
, VMAP::VMAP_MAGIC
);
61 fclose(model_list_file
);
65 uint32 name_length
, displayId
;
71 if (fread(&displayId
, sizeof(uint32
), 1, model_list_file
) != 1)
72 if (feof(model_list_file
)) // EOF flag is only set after failed reading attempt
75 if (fread(&isWmo
, sizeof(uint8
), 1, model_list_file
) != 1
76 || fread(&name_length
, sizeof(uint32
), 1, model_list_file
) != 1
77 || name_length
>= sizeof(buff
)
78 || fread(&buff
, sizeof(char), name_length
, model_list_file
) != name_length
79 || fread(&v1
, sizeof(Vector3
), 1, model_list_file
) != 1
80 || fread(&v2
, sizeof(Vector3
), 1, model_list_file
) != 1)
82 TC_LOG_ERROR("misc", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS
);
86 if (v1
.isNaN() || v2
.isNaN())
88 TC_LOG_ERROR("misc", "File '%s' Model '%s' has invalid v1%s v2%s values!", VMAP::GAMEOBJECT_MODELS
, std::string(buff
, name_length
).c_str(), v1
.toString().c_str(), v2
.toString().c_str());
92 model_list
.emplace(std::piecewise_construct
, std::forward_as_tuple(displayId
), std::forward_as_tuple(&buff
[0], name_length
, v1
, v2
, isWmo
!= 0));
95 fclose(model_list_file
);
96 TC_LOG_INFO("server.loading", ">> Loaded %u GameObject models in %u ms", uint32(model_list
.size()), GetMSTimeDiffToNow(oldMSTime
));
99 GameObjectModel::~GameObjectModel()
102 ((VMAP::VMapManager2
*)VMAP::VMapFactory::createOrGetVMapManager())->releaseModelInstance(name
);
105 bool GameObjectModel::initialize(std::unique_ptr
<GameObjectModelOwnerBase
> modelOwner
, std::string
const& dataPath
)
107 ModelList::const_iterator it
= model_list
.find(modelOwner
->GetDisplayId());
108 if (it
== model_list
.end())
111 G3D::AABox
mdl_box(it
->second
.bound
);
112 // ignore models with no bounds
113 if (mdl_box
== G3D::AABox::zero())
115 TC_LOG_ERROR("misc", "GameObject model %s has zero bounds, loading skipped", it
->second
.name
.c_str());
119 iModel
= ((VMAP::VMapManager2
*)VMAP::VMapFactory::createOrGetVMapManager())->acquireModelInstance(dataPath
+ "vmaps/", it
->second
.name
);
124 name
= it
->second
.name
;
125 iPos
= modelOwner
->GetPosition();
126 iScale
= modelOwner
->GetScale();
127 iInvScale
= 1.f
/ iScale
;
129 G3D::Matrix3 iRotation
= G3D::Matrix3::fromEulerAnglesZYX(modelOwner
->GetOrientation(), 0, 0);
130 iInvRot
= iRotation
.inverse();
131 // transform bounding box:
132 mdl_box
= AABox(mdl_box
.low() * iScale
, mdl_box
.high() * iScale
);
133 AABox rotated_bounds
;
134 for (int i
= 0; i
< 8; ++i
)
135 rotated_bounds
.merge(iRotation
* mdl_box
.corner(i
));
137 iBound
= rotated_bounds
+ iPos
;
140 for (int i
= 0; i
< 8; ++i
)
142 Vector3
pos(iBound
.corner(i
));
143 modelOwner
->DebugVisualizeCorner(pos
);
147 owner
= std::move(modelOwner
);
148 isWmo
= it
->second
.isWmo
;
152 GameObjectModel
* GameObjectModel::Create(std::unique_ptr
<GameObjectModelOwnerBase
> modelOwner
, std::string
const& dataPath
)
154 GameObjectModel
* mdl
= new GameObjectModel();
155 if (!mdl
->initialize(std::move(modelOwner
), dataPath
))
164 bool GameObjectModel::intersectRay(G3D::Ray
const& ray
, float& maxDist
, bool stopAtFirstHit
, PhaseShift
const& phaseShift
) const
166 if (!isCollisionEnabled() || !owner
->IsSpawned())
169 if (!owner
->IsInPhase(phaseShift
))
172 float time
= ray
.intersectionTime(iBound
);
173 if (time
== G3D::finf())
176 // child bounds are defined in object space:
177 Vector3 p
= iInvRot
* (ray
.origin() - iPos
) * iInvScale
;
178 Ray
modRay(p
, iInvRot
* ray
.direction());
179 float distance
= maxDist
* iInvScale
;
180 bool hit
= iModel
->IntersectRay(modRay
, distance
, stopAtFirstHit
);
189 void GameObjectModel::intersectPoint(G3D::Vector3
const& point
, VMAP::AreaInfo
& info
, PhaseShift
const& phaseShift
) const
191 if (!isCollisionEnabled() || !owner
->IsSpawned() || !isMapObject())
194 if (!owner
->IsInPhase(phaseShift
))
197 if (!iBound
.contains(point
))
200 // child bounds are defined in object space:
201 Vector3 pModel
= iInvRot
* (point
- iPos
) * iInvScale
;
202 Vector3 zDirModel
= iInvRot
* Vector3(0.f
, 0.f
, -1.f
);
204 if (iModel
->IntersectPoint(pModel
, zDirModel
, zDist
, info
))
206 Vector3 modelGround
= pModel
+ zDist
* zDirModel
;
207 float world_Z
= ((modelGround
* iInvRot
) * iScale
+ iPos
).z
;
208 if (info
.ground_Z
< world_Z
)
210 info
.ground_Z
= world_Z
;
211 info
.adtId
= owner
->GetNameSetId();
216 bool GameObjectModel::UpdatePosition()
221 ModelList::const_iterator it
= model_list
.find(owner
->GetDisplayId());
222 if (it
== model_list
.end())
225 G3D::AABox
mdl_box(it
->second
.bound
);
226 // ignore models with no bounds
227 if (mdl_box
== G3D::AABox::zero())
229 TC_LOG_ERROR("misc", "GameObject model %s has zero bounds, loading skipped", it
->second
.name
.c_str());
233 iPos
= owner
->GetPosition();
235 G3D::Matrix3 iRotation
= G3D::Matrix3::fromEulerAnglesZYX(owner
->GetOrientation(), 0, 0);
236 iInvRot
= iRotation
.inverse();
237 // transform bounding box:
238 mdl_box
= AABox(mdl_box
.low() * iScale
, mdl_box
.high() * iScale
);
239 AABox rotated_bounds
;
240 for (int i
= 0; i
< 8; ++i
)
241 rotated_bounds
.merge(iRotation
* mdl_box
.corner(i
));
243 iBound
= rotated_bounds
+ iPos
;
246 for (int i
= 0; i
< 8; ++i
)
248 Vector3
pos(iBound
.corner(i
));
249 owner
->DebugVisualizeCorner(pos
);