aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Collision/BoundingIntervalHierarchy.cpp1
-rw-r--r--src/common/Collision/BoundingIntervalHierarchy.h2
-rw-r--r--src/common/Collision/DynamicTree.cpp5
-rw-r--r--src/common/Collision/DynamicTree.h3
-rw-r--r--src/common/Collision/Management/MMapManager.cpp1
-rw-r--r--src/common/Collision/Management/VMapManager2.cpp7
-rw-r--r--src/common/Collision/Management/VMapManager2.h1
-rw-r--r--src/common/Collision/RegularGrid.h60
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp20
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h9
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.cpp10
-rw-r--r--src/server/scripts/Spells/spell_priest.cpp71
-rw-r--r--src/tools/mmaps_generator/IntermediateValues.cpp15
-rw-r--r--src/tools/mmaps_generator/MapBuilder.cpp543
-rw-r--r--src/tools/mmaps_generator/MapBuilder.h86
-rw-r--r--src/tools/mmaps_generator/PathCommon.h2
-rw-r--r--src/tools/mmaps_generator/PathGenerator.cpp88
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.cpp64
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.h28
-rw-r--r--src/tools/mmaps_generator/TileBuilder.cpp554
-rw-r--r--src/tools/mmaps_generator/TileBuilder.h84
22 files changed, 881 insertions, 775 deletions
diff --git a/src/common/Collision/BoundingIntervalHierarchy.cpp b/src/common/Collision/BoundingIntervalHierarchy.cpp
index e37d00b802a..7e58d6c9003 100644
--- a/src/common/Collision/BoundingIntervalHierarchy.cpp
+++ b/src/common/Collision/BoundingIntervalHierarchy.cpp
@@ -16,6 +16,7 @@
*/
#include "BoundingIntervalHierarchy.h"
+#include <stdexcept>
void BIH::buildHierarchy(std::vector<uint32>& tempTree, buildData& dat, BuildStats& stats) const
{
diff --git a/src/common/Collision/BoundingIntervalHierarchy.h b/src/common/Collision/BoundingIntervalHierarchy.h
index 5c9c69ed1b6..5674ee2057d 100644
--- a/src/common/Collision/BoundingIntervalHierarchy.h
+++ b/src/common/Collision/BoundingIntervalHierarchy.h
@@ -24,8 +24,6 @@
#include <G3D/Ray.h>
#include <G3D/Vector3.h>
#include <algorithm>
-#include <limits>
-#include <stdexcept>
#include <vector>
#define MAX_STACK_SIZE 64
diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp
index 073e317e4ae..7566edb473d 100644
--- a/src/common/Collision/DynamicTree.cpp
+++ b/src/common/Collision/DynamicTree.cpp
@@ -101,10 +101,7 @@ struct DynTreeImpl : public ParentTree/*, public Intersectable*/
DynamicMapTree::DynamicMapTree() : impl(new DynTreeImpl()) { }
-DynamicMapTree::~DynamicMapTree()
-{
- delete impl;
-}
+DynamicMapTree::~DynamicMapTree() = default;
void DynamicMapTree::insert(GameObjectModel const& mdl)
{
diff --git a/src/common/Collision/DynamicTree.h b/src/common/Collision/DynamicTree.h
index 50dc3d92993..11d701ebd7c 100644
--- a/src/common/Collision/DynamicTree.h
+++ b/src/common/Collision/DynamicTree.h
@@ -20,6 +20,7 @@
#include "Define.h"
#include "Optional.h"
+#include <memory>
namespace G3D
{
@@ -38,7 +39,7 @@ namespace VMAP
class TC_COMMON_API DynamicMapTree
{
- DynTreeImpl *impl;
+ std::unique_ptr<DynTreeImpl> impl;
public:
diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp
index 8c926d79a6e..c10d64bfd36 100644
--- a/src/common/Collision/Management/MMapManager.cpp
+++ b/src/common/Collision/Management/MMapManager.cpp
@@ -21,6 +21,7 @@
#include "Log.h"
#include "MMapDefines.h"
#include "Memory.h"
+#include <algorithm>
namespace MMAP
{
diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp
index 93a1f7e4995..481b1cdb0ea 100644
--- a/src/common/Collision/Management/VMapManager2.cpp
+++ b/src/common/Collision/Management/VMapManager2.cpp
@@ -88,6 +88,13 @@ namespace VMAP
thread_safe_environment = false;
}
+ void VMapManager2::InitializeThreadUnsafe(uint32 mapId, int32 parentMapId)
+ {
+ iInstanceMapTrees[mapId] = nullptr;
+ if (parentMapId >= 0)
+ iParentMapData[mapId] = parentMapId;
+ }
+
Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const
{
Vector3 pos;
diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h
index 5abe003056c..8fbc9b05ed1 100644
--- a/src/common/Collision/Management/VMapManager2.h
+++ b/src/common/Collision/Management/VMapManager2.h
@@ -84,6 +84,7 @@ namespace VMAP
~VMapManager2();
void InitializeThreadUnsafe(std::unordered_map<uint32, std::vector<uint32>> const& mapData);
+ void InitializeThreadUnsafe(uint32 mapId, int32 parentMapId);
LoadResult loadMap(char const* pBasePath, unsigned int mapId, int x, int y) override;
diff --git a/src/common/Collision/RegularGrid.h b/src/common/Collision/RegularGrid.h
index 0110a17f412..459388d2662 100644
--- a/src/common/Collision/RegularGrid.h
+++ b/src/common/Collision/RegularGrid.h
@@ -22,7 +22,7 @@
#include "IteratorPair.h"
#include <G3D/Ray.h>
#include <G3D/BoundsTrait.h>
-#include <G3D/PositionTrait.h>
+#include <memory>
#include <unordered_map>
template<class Node>
@@ -33,8 +33,7 @@ struct NodeCreator{
template<class T,
class Node,
class NodeCreatorFunc = NodeCreator<Node>,
-class BoundsFunc = BoundsTrait<T>,
-class PositionFunc = PositionTrait<T>
+class BoundsFunc = BoundsTrait<T>
>
class TC_COMMON_API RegularGrid2D
{
@@ -44,27 +43,14 @@ public:
CELL_NUMBER = 64,
};
- #define HGRID_MAP_SIZE (533.33333f * 64.f) // shouldn't be changed
- #define CELL_SIZE float(HGRID_MAP_SIZE/(float)CELL_NUMBER)
+ #define CELL_SIZE 533.33333f
- typedef std::unordered_multimap<const T*, Node*> MemberTable;
+ typedef std::unordered_multimap<T const*, Node*> MemberTable;
MemberTable memberTable;
- Node* nodes[CELL_NUMBER][CELL_NUMBER];
+ std::unique_ptr<Node> nodes[CELL_NUMBER][CELL_NUMBER] = { };
- RegularGrid2D()
- {
- memset(nodes, 0, sizeof(nodes));
- }
-
- ~RegularGrid2D()
- {
- for (int x = 0; x < CELL_NUMBER; ++x)
- for (int y = 0; y < CELL_NUMBER; ++y)
- delete nodes[x][y];
- }
-
- void insert(const T& value)
+ void insert(T const& value)
{
G3D::AABox bounds = G3D::AABox::empty();
BoundsFunc::getBounds(value, bounds);
@@ -81,7 +67,7 @@ public:
}
}
- void remove(const T& value)
+ void remove(T const& value)
{
for (auto& p : Trinity::Containers::MapEqualRange(memberTable, &value))
p.second->remove(value);
@@ -93,25 +79,22 @@ public:
{
for (int x = 0; x < CELL_NUMBER; ++x)
for (int y = 0; y < CELL_NUMBER; ++y)
- if (Node* n = nodes[x][y])
+ if (Node* n = nodes[x][y].get())
n->balance();
}
- bool contains(const T& value) const { return memberTable.count(&value) > 0; }
+ bool contains(T const& value) const { return memberTable.contains(&value); }
bool empty() const { return memberTable.empty(); }
struct Cell
{
int x, y;
- bool operator==(Cell const& c2) const
- {
- return x == c2.x && y == c2.y;
- }
+
+ friend bool operator==(Cell const&, Cell const&) = default;
static Cell ComputeCell(float fx, float fy)
{
- Cell c = { int(fx * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)), int(fy * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)) };
- return c;
+ return { .x = int(fx * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)), .y = int(fy * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)) };
}
bool isValid() const { return x >= 0 && x < CELL_NUMBER && y >= 0 && y < CELL_NUMBER; }
@@ -121,18 +104,18 @@ public:
{
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
if (!nodes[x][y])
- nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
+ nodes[x][y].reset(NodeCreatorFunc::makeNode(x, y));
return *nodes[x][y];
}
template<typename RayCallback>
- void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float max_dist)
+ void intersectRay(G3D::Ray const& ray, RayCallback& intersectCallback, float max_dist)
{
intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist);
}
template<typename RayCallback>
- void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist, const G3D::Vector3& end)
+ void intersectRay(G3D::Ray const& ray, RayCallback& intersectCallback, float& max_dist, G3D::Vector3 const& end)
{
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
if (!cell.isValid())
@@ -142,7 +125,7 @@ public:
if (cell == last_cell)
{
- if (Node* node = nodes[cell.x][cell.y])
+ if (Node* node = nodes[cell.x][cell.y].get())
node->intersectRay(ray, intersectCallback, max_dist);
return;
}
@@ -186,7 +169,7 @@ public:
float tDeltaY = voxel * std::fabs(ky_inv);
do
{
- if (Node* node = nodes[cell.x][cell.y])
+ if (Node* node = nodes[cell.x][cell.y].get())
{
//float enterdist = max_dist;
node->intersectRay(ray, intersectCallback, max_dist);
@@ -208,28 +191,27 @@ public:
}
template<typename IsectCallback>
- void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback)
+ void intersectPoint(G3D::Vector3 const& point, IsectCallback& intersectCallback)
{
Cell cell = Cell::ComputeCell(point.x, point.y);
if (!cell.isValid())
return;
- if (Node* node = nodes[cell.x][cell.y])
+ if (Node* node = nodes[cell.x][cell.y].get())
node->intersectPoint(point, intersectCallback);
}
// Optimized verson of intersectRay function for rays with vertical directions
template<typename RayCallback>
- void intersectZAllignedRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist)
+ void intersectZAllignedRay(G3D::Ray const& ray, RayCallback& intersectCallback, float& max_dist)
{
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
if (!cell.isValid())
return;
- if (Node* node = nodes[cell.x][cell.y])
+ if (Node* node = nodes[cell.x][cell.y].get())
node->intersectRay(ray, intersectCallback, max_dist);
}
};
#undef CELL_SIZE
-#undef HGRID_MAP_SIZE
#endif
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 42a3e09d1d9..ef87db7a692 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2678,6 +2678,26 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
+ case SMART_ACTION_FALL:
+ {
+ std::shared_ptr<MultiActionResult<MovementStopReason>> waitEvent = CreateTimedActionListWaitEventFor<void, MultiActionResult<MovementStopReason>>(e, targets.size());
+
+ for (WorldObject* target : targets)
+ {
+ if (Unit* unitTarget = target->ToUnit())
+ {
+ Optional<Scripting::v2::ActionResultSetter<MovementStopReason>> actionResultSetter;
+ if (waitEvent)
+ actionResultSetter = Scripting::v2::ActionResult<MovementStopReason>::GetResultSetter({ waitEvent, &waitEvent->Results.emplace_back() });
+
+ unitTarget->GetMotionMaster()->MoveFall(e.action.fall.pointId, std::move(actionResultSetter));
+ }
+ }
+
+ if (waitEvent && !waitEvent->Results.empty())
+ mTimedActionWaitEvent = std::move(waitEvent);
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 7fceb43a614..65a13078bc9 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1035,6 +1035,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ENTER_VEHICLE: return sizeof(SmartAction::enterVehicle);
case SMART_ACTION_BOARD_PASSENGER: return sizeof(SmartAction::enterVehicle);
case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
+ case SMART_ACTION_FALL: return sizeof(SmartAction::fall);
default:
TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -2452,6 +2453,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_ADD_TO_STORED_TARGET_LIST:
case SMART_ACTION_DO_ACTION:
case SMART_ACTION_EXIT_VEHICLE:
+ case SMART_ACTION_FALL:
break;
case SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER:
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index ea7459ac26f..a9127a33f8a 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -613,7 +613,9 @@ enum SMART_ACTION
SMART_ACTION_ENTER_VEHICLE = 155, // seat id
SMART_ACTION_BOARD_PASSENGER = 156, // seat id
SMART_ACTION_EXIT_VEHICLE = 157,
- SMART_ACTION_END = 158
+ SMART_ACTION_RESUME_MOVEMENT = 158, // UNUSED NEEDS CHERRYPICK
+ SMART_ACTION_FALL = 159, // pointId
+ SMART_ACTION_END = 160
};
enum class SmartActionSummonCreatureFlags
@@ -876,6 +878,11 @@ struct SmartAction
struct
{
+ uint32 pointId;
+ } fall;
+
+ struct
+ {
SAIBool run; // unused defined by waypoint_path
uint32 pathID;
SAIBool repeat;
diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp
index e5d9fb3d60b..39118263388 100644
--- a/src/server/game/Movement/Spline/MoveSpline.cpp
+++ b/src/server/game/Movement/Spline/MoveSpline.cpp
@@ -269,22 +269,18 @@ bool MoveSplineInitArgs::Validate(Unit const* unit)
// check path lengths - why are we even starting such short movement?
bool MoveSplineInitArgs::_checkPathLengths()
{
- constexpr float MIN_XY_OFFSET = -(1 << 11) / 4.0f;
- constexpr float MIN_Z_OFFSET = -(1 << 10) / 4.0f;
-
- // positive values have 1 less bit limit (if the highest bit was set, value would be sign extended into negative when decompressing)
constexpr float MAX_XY_OFFSET = (1 << 10) / 4.0f;
constexpr float MAX_Z_OFFSET = (1 << 9) / 4.0f;
- auto isValidPackedXYOffset = [](float coord) -> bool { return coord > MIN_XY_OFFSET && coord < MAX_XY_OFFSET; };
- auto isValidPackedZOffset = [](float coord) -> bool { return coord > MIN_Z_OFFSET && coord < MAX_Z_OFFSET; };
+ auto isValidPackedXYOffset = [](float coord) -> bool { return coord > -MAX_XY_OFFSET && coord < MAX_XY_OFFSET; };
+ auto isValidPackedZOffset = [](float coord) -> bool { return coord > -MAX_Z_OFFSET && coord < MAX_Z_OFFSET; };
if (path.size() > 2)
{
Vector3 middle = (path.front() + path.back()) / 2;
for (uint32 i = 1; i < path.size() - 1; ++i)
{
- if ((path[i + 1] - path[i]).length() < 0.1f)
+ if ((path[i + 1] - path[i]).squaredLength() < 0.01f)
return false;
// when compression is enabled, each point coord is packed into 11 bits (10 for Z)
diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp
index 622c6d65142..ab79773e642 100644
--- a/src/server/scripts/Spells/spell_priest.cpp
+++ b/src/server/scripts/Spells/spell_priest.cpp
@@ -52,7 +52,6 @@ enum PriestSpells
SPELL_PRIEST_ATONEMENT_EFFECT = 194384,
SPELL_PRIEST_ATONEMENT_HEAL = 81751,
SPELL_PRIEST_BENEDICTION = 193157,
- SPELL_PRIEST_BENEVOLENCE = 415416,
SPELL_PRIEST_BLAZE_OF_LIGHT = 215768,
SPELL_PRIEST_BLAZE_OF_LIGHT_INCREASE = 355851,
SPELL_PRIEST_BLAZE_OF_LIGHT_DECREASE = 356084,
@@ -160,7 +159,6 @@ enum PriestSpells
SPELL_PRIEST_PURGE_THE_WICKED = 204197,
SPELL_PRIEST_PURGE_THE_WICKED_DUMMY = 204215,
SPELL_PRIEST_PURGE_THE_WICKED_PERIODIC = 204213,
- SPELL_PRIEST_RAPTURE = 47536,
SPELL_PRIEST_RENEW = 139,
SPELL_PRIEST_RENEWED_HOPE = 197469,
SPELL_PRIEST_RENEWED_HOPE_EFFECT = 197470,
@@ -194,7 +192,7 @@ enum PriestSpells
SPELL_PRIEST_THE_PENITENT_AURA = 200347,
SPELL_PRIEST_TRAIL_OF_LIGHT_HEAL = 234946,
SPELL_PRIEST_TRINITY = 214205,
- SPELL_PRIEST_TRINITY_EFFECT = 214206,
+ SPELL_PRIEST_TRINITY_EFFECT = 290793,
SPELL_PRIEST_ULTIMATE_PENITENCE = 421453,
SPELL_PRIEST_ULTIMATE_PENITENCE_DAMAGE = 421543,
SPELL_PRIEST_ULTIMATE_PENITENCE_HEAL = 421544,
@@ -391,8 +389,8 @@ class spell_pri_atonement : public AuraScript
{
bool Validate(SpellInfo const* spellInfo) override
{
- return ValidateSpellInfo({ SPELL_PRIEST_ATONEMENT_HEAL, SPELL_PRIEST_SINS_OF_THE_MANY })
- && ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 }, { SPELL_PRIEST_SINS_OF_THE_MANY, EFFECT_2 } });
+ return ValidateSpellInfo({ SPELL_PRIEST_ATONEMENT_HEAL, SPELL_PRIEST_SINS_OF_THE_MANY, SPELL_PRIEST_TRINITY_EFFECT })
+ && ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 }, { SPELL_PRIEST_SINS_OF_THE_MANY, EFFECT_2 }, { SPELL_PRIEST_TRINITY, EFFECT_0 } });
}
static bool CheckProc(AuraScript const&, ProcEventInfo const& eventInfo)
@@ -419,6 +417,7 @@ public:
_appliedAtonements.push_back(target);
UpdateSinsOfTheManyValue();
+ UpdateTrinityEffect();
}
void RemoveAtonementTarget(ObjectGuid const& target)
@@ -426,6 +425,7 @@ public:
std::erase(_appliedAtonements, target);
UpdateSinsOfTheManyValue();
+ UpdateTrinityEffect();
}
std::vector<ObjectGuid> const& GetAtonementTargets() const
@@ -477,6 +477,15 @@ public:
if (AuraEffect* sinOfTheMany = GetUnitOwner()->GetAuraEffect(SPELL_PRIEST_SINS_OF_THE_MANY, effectIndex))
sinOfTheMany->ChangeAmount(damageByStack[std::min(_appliedAtonements.size(), damageByStack.size() - 1)]);
}
+
+ void UpdateTrinityEffect() const
+ {
+ Unit* priest = GetUnitOwner();
+ if (AuraEffect const* trinity = priest->GetAuraEffect(SPELL_PRIEST_TRINITY, EFFECT_0); trinity && std::ssize(_appliedAtonements) >= trinity->GetAmount())
+ priest->CastSpell(priest, SPELL_PRIEST_TRINITY_EFFECT, CastSpellExtraArgsInit{ .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR });
+ else
+ priest->RemoveAurasDueToSpell(SPELL_PRIEST_TRINITY_EFFECT);
+ }
};
// 81751 - Atonement (Heal)
@@ -515,8 +524,6 @@ class spell_pri_atonement_effect : public SpellScript
({
SPELL_PRIEST_ATONEMENT,
SPELL_PRIEST_ATONEMENT_EFFECT,
- SPELL_PRIEST_TRINITY,
- SPELL_PRIEST_TRINITY_EFFECT,
SPELL_PRIEST_POWER_WORD_RADIANCE,
SPELL_PRIEST_POWER_WORD_SHIELD
}) && ValidateSpellEffect({
@@ -531,15 +538,6 @@ class spell_pri_atonement_effect : public SpellScript
if (!caster->HasAura(SPELL_PRIEST_ATONEMENT))
return false;
- // only apply Trinity if the Priest has both Trinity and Atonement and the triggering spell is Power Word: Shield.
- if (caster->HasAura(SPELL_PRIEST_TRINITY))
- {
- if (GetSpellInfo()->Id != SPELL_PRIEST_POWER_WORD_SHIELD)
- return false;
-
- _effectSpellId = SPELL_PRIEST_TRINITY_EFFECT;
- }
-
return true;
}
@@ -579,7 +577,7 @@ class spell_pri_atonement_effect : public SpellScript
uint32 _effectSpellId = SPELL_PRIEST_ATONEMENT_EFFECT;
};
-// 194384 - Atonement (Buff), 214206 - Atonement [Trinity] (Buff)
+// 194384 - Atonement (Buff)
class spell_pri_atonement_effect_aura : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
@@ -1225,12 +1223,7 @@ class spell_pri_evangelism : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- return ValidateSpellInfo
- ({
- SPELL_PRIEST_TRINITY,
- SPELL_PRIEST_ATONEMENT_EFFECT,
- SPELL_PRIEST_TRINITY_EFFECT
- });
+ return ValidateSpellInfo({ SPELL_PRIEST_ATONEMENT_EFFECT });
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/) const
@@ -1238,9 +1231,7 @@ class spell_pri_evangelism : public SpellScript
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
- Aura* atonementAura = caster->HasAura(SPELL_PRIEST_TRINITY)
- ? target->GetAura(SPELL_PRIEST_TRINITY_EFFECT, caster->GetGUID())
- : target->GetAura(SPELL_PRIEST_ATONEMENT_EFFECT, caster->GetGUID());
+ Aura* atonementAura = target->GetAura(SPELL_PRIEST_ATONEMENT_EFFECT, caster->GetGUID());
if (!atonementAura)
return;
@@ -1841,7 +1832,6 @@ class spell_pri_pain_transformation : public SpellScript
return ValidateSpellInfo
({
SPELL_PRIEST_ATONEMENT_EFFECT,
- SPELL_PRIEST_TRINITY,
SPELL_PRIEST_PAIN_TRANSFORMATION,
SPELL_PRIEST_PAIN_TRANSFORMATION_HEAL
});
@@ -1849,7 +1839,7 @@ class spell_pri_pain_transformation : public SpellScript
bool Load() override
{
- return GetCaster()->HasAura(SPELL_PRIEST_PAIN_TRANSFORMATION) && !GetCaster()->HasAura(SPELL_PRIEST_TRINITY);
+ return GetCaster()->HasAura(SPELL_PRIEST_PAIN_TRANSFORMATION);
}
void HandleHit(SpellEffIndex /*effIndex*/) const
@@ -2170,15 +2160,11 @@ class spell_pri_power_word_shield : public AuraScript
SPELL_PRIEST_STRENGTH_OF_SOUL,
SPELL_PRIEST_STRENGTH_OF_SOUL_EFFECT,
SPELL_PRIEST_ATONEMENT_EFFECT,
- SPELL_PRIEST_TRINITY_EFFECT,
SPELL_PRIEST_SHIELD_DISCIPLINE,
SPELL_PRIEST_SHIELD_DISCIPLINE_EFFECT,
SPELL_PVP_RULES_ENABLED_HARDCODED
}) && ValidateSpellEffect({
- { SPELL_PRIEST_MASTERY_GRACE, EFFECT_0 },
- { SPELL_PRIEST_RAPTURE, EFFECT_1 },
- { SPELL_PRIEST_BENEVOLENCE, EFFECT_0 },
- { SPELL_PRIEST_DIVINE_AEGIS, EFFECT_1 }
+ { SPELL_PRIEST_MASTERY_GRACE, EFFECT_0 }
});
}
@@ -2188,7 +2174,7 @@ class spell_pri_power_word_shield : public AuraScript
if (Unit* caster = GetCaster())
{
- float modifiedAmount = caster->SpellBaseDamageBonusDone(GetSpellInfo()->GetSchoolMask()) * 3.36f;
+ float modifiedAmount = caster->SpellBaseDamageBonusDone(GetSpellInfo()->GetSchoolMask()) * 4.638f;
if (Player* player = caster->ToPlayer())
{
@@ -2196,7 +2182,7 @@ class spell_pri_power_word_shield : public AuraScript
// Mastery: Grace (TBD: move into DoEffectCalcDamageAndHealing hook with a new SpellScript and AuraScript).
if (AuraEffect const* masteryGraceEffect = caster->GetAuraEffect(SPELL_PRIEST_MASTERY_GRACE, EFFECT_0))
- if (GetUnitOwner()->HasAura(SPELL_PRIEST_ATONEMENT_EFFECT) || GetUnitOwner()->HasAura(SPELL_PRIEST_TRINITY_EFFECT))
+ if (GetUnitOwner()->HasAura(SPELL_PRIEST_ATONEMENT_EFFECT))
AddPct(modifiedAmount, masteryGraceEffect->GetAmount());
switch (player->GetPrimarySpecialization())
@@ -2218,22 +2204,8 @@ class spell_pri_power_word_shield : public AuraScript
float critChanceTaken = GetUnitOwner()->SpellCritChanceTaken(caster, nullptr, auraEffect, GetSpellInfo()->GetSchoolMask(), critChanceDone, GetSpellInfo()->GetAttackType());
if (roll_chance_f(critChanceTaken))
- {
modifiedAmount *= 2;
- // Divine Aegis
- if (AuraEffect const* divineEff = caster->GetAuraEffect(SPELL_PRIEST_DIVINE_AEGIS, EFFECT_1))
- AddPct(modifiedAmount, divineEff->GetAmount());
- }
-
- // Rapture talent (TBD: move into DoEffectCalcDamageAndHealing hook).
- if (AuraEffect const* raptureEffect = caster->GetAuraEffect(SPELL_PRIEST_RAPTURE, EFFECT_1))
- AddPct(modifiedAmount, raptureEffect->GetAmount());
-
- // Benevolence talent
- if (AuraEffect const* benevolenceEffect = caster->GetAuraEffect(SPELL_PRIEST_BENEVOLENCE, EFFECT_0))
- AddPct(modifiedAmount, benevolenceEffect->GetAmount());
-
amount = modifiedAmount;
}
}
@@ -3007,7 +2979,6 @@ class spell_pri_shadow_mend : public SpellScript
({
SPELL_PRIEST_ATONEMENT,
SPELL_PRIEST_ATONEMENT_EFFECT,
- SPELL_PRIEST_TRINITY,
SPELL_PRIEST_MASOCHISM_TALENT,
SPELL_PRIEST_MASOCHISM_PERIODIC_HEAL,
SPELL_PRIEST_SHADOW_MEND_PERIODIC_DUMMY
diff --git a/src/tools/mmaps_generator/IntermediateValues.cpp b/src/tools/mmaps_generator/IntermediateValues.cpp
index 068ae951c46..8d0af05c319 100644
--- a/src/tools/mmaps_generator/IntermediateValues.cpp
+++ b/src/tools/mmaps_generator/IntermediateValues.cpp
@@ -16,6 +16,7 @@
*/
#include "IntermediateValues.h"
+#include "Log.h"
#include "StringFormat.h"
namespace MMAP
@@ -31,9 +32,7 @@ namespace MMAP
void IntermediateValues::writeIV(uint32 mapID, uint32 tileX, uint32 tileY)
{
- std::string tileString = Trinity::StringFormat("[{:02},{:02}]: ", tileX, tileY);
-
- printf("%sWriting debug output... \r", tileString.c_str());
+ TC_LOG_INFO("maps.mmapgen.debug", "[Map {:04}] [{:02},{:02}]: Writing debug output intermediate values...", mapID, tileX, tileY);
auto debugWrite = [&](char const* extension, auto const* data)
{
@@ -44,7 +43,7 @@ namespace MMAP
fclose(file);
}
else
- perror(Trinity::StringFormat("{}Failed to open {} for writing!\n", tileString, fileName).c_str());
+ TC_LOG_ERROR("maps.mmapgen.debug", "{}: [{:04}-{:02},{:02}] Failed to open {} for writing!", strerror(errno), mapID, tileX, tileY, fileName);
};
if (heightfield)
@@ -197,7 +196,7 @@ namespace MMAP
FILE* objFile = fopen(objFileName.c_str(), "wb");
if (!objFile)
{
- perror(Trinity::StringFormat("Failed to open {} for writing!\n", objFileName).c_str());
+ TC_LOG_ERROR("maps.mmapgen.debug", "{}: Failed to open {} for writing!", strerror(errno), objFileName);
return;
}
@@ -222,14 +221,14 @@ namespace MMAP
fclose(objFile);
- printf("[%02u,%02u]: Writing debug output... \r", tileY, tileX);
+ TC_LOG_INFO("maps.mmapgen.debug", "[Map {:04}] [{:02},{:02}]: Writing debug output object file...", mapID, tileY, tileX);
objFileName = Trinity::StringFormat("meshes/map{:04}.map", mapID);
objFile = fopen(objFileName.c_str(), "wb");
if (!objFile)
{
- perror(Trinity::StringFormat("Failed to open {} for writing!\n", objFileName).c_str());
+ TC_LOG_ERROR("maps.mmapgen.debug", "{}: Failed to open {} for writing!", strerror(errno), objFileName);
return;
}
@@ -241,7 +240,7 @@ namespace MMAP
objFile = fopen(objFileName.c_str(), "wb");
if (!objFile)
{
- perror(Trinity::StringFormat("Failed to open {} for writing!\n", objFileName).c_str());
+ TC_LOG_ERROR("maps.mmapgen.debug", "{}: Failed to open {} for writing!", strerror(errno), objFileName);
return;
}
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp
index 32d273c6cbd..354cdce9e2e 100644
--- a/src/tools/mmaps_generator/MapBuilder.cpp
+++ b/src/tools/mmaps_generator/MapBuilder.cpp
@@ -16,20 +16,16 @@
*/
#include "MapBuilder.h"
-#include "IntermediateValues.h"
+#include "Log.h"
#include "MapDefines.h"
#include "MapTree.h"
#include "MapUtils.h"
#include "Memory.h"
#include "MMapDefines.h"
-#include "ModelInstance.h"
#include "PathCommon.h"
#include "StringConvert.h"
#include "StringFormat.h"
-#include <DetourNavMesh.h>
-#include <DetourNavMeshBuilder.h>
#include <boost/filesystem/directory.hpp>
-#include <climits>
namespace FileExtensions
{
@@ -39,36 +35,33 @@ static boost::filesystem::path vmtile = ".vmtile";
namespace MMAP
{
- TileBuilder::TileBuilder(MapBuilder* mapBuilder, bool skipLiquid, bool bigBaseUnit, bool debugOutput) :
- m_bigBaseUnit(bigBaseUnit),
- m_debugOutput(debugOutput),
+ MapTileBuilder::MapTileBuilder(MapBuilder* mapBuilder, Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
+ bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector<OffMeshData> const* offMeshConnections) :
+ TileBuilder(maxWalkableAngle, maxWalkableAngleNotSteep, skipLiquid, bigBaseUnit, debugOutput, offMeshConnections),
m_mapBuilder(mapBuilder),
- m_terrainBuilder(nullptr),
- m_workerThread(&TileBuilder::WorkerThread, this),
- m_rcContext(nullptr)
+ m_workerThread(&MapTileBuilder::WorkerThread, this)
{
- m_terrainBuilder = new TerrainBuilder(skipLiquid);
- m_rcContext = new rcContext(false);
}
- TileBuilder::~TileBuilder()
+ MapTileBuilder::~MapTileBuilder()
{
WaitCompletion();
-
- delete m_terrainBuilder;
- delete m_rcContext;
}
- void TileBuilder::WaitCompletion()
+ void MapTileBuilder::WaitCompletion()
{
if (m_workerThread.joinable())
m_workerThread.join();
}
+ void MapTileBuilder::OnTileDone()
+ {
+ ++m_mapBuilder->m_totalTilesProcessed;
+ }
+
MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath, unsigned int threads) :
- m_terrainBuilder (nullptr),
m_debugOutput (debugOutput),
m_threads (threads),
m_skipContinents (skipContinents),
@@ -81,12 +74,8 @@ namespace MMAP
m_mapid (mapid),
m_totalTiles (0u),
m_totalTilesProcessed(0u),
- m_rcContext (nullptr),
_cancelationToken (false)
{
- m_terrainBuilder = new TerrainBuilder(skipLiquid);
-
- m_rcContext = new rcContext(false);
// At least 1 thread is needed
m_threads = std::max(1u, m_threads);
@@ -108,9 +97,6 @@ namespace MMAP
m_tileBuilders.clear();
m_tiles.clear();
-
- delete m_terrainBuilder;
- delete m_rcContext;
}
/**************************************************************************/
@@ -187,8 +173,8 @@ namespace MMAP
}
}
- printf("Discovering maps... found %u.\n", uint32(m_tiles.size()));
- printf("Discovering tiles... found %u.\n\n", m_totalTiles);
+ TC_LOG_INFO("maps.mmapgen", "Discovering maps... found {}.", m_tiles.size());
+ TC_LOG_INFO("maps.mmapgen", "Discovering tiles... found {}.\n", m_totalTiles);
}
/**************************************************************************/
@@ -201,7 +187,7 @@ namespace MMAP
auto fp = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(offMeshFilePath, "rb"));
if (!fp)
{
- printf(" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
+ TC_LOG_ERROR("maps.mmapgen", "MapBuilder::loadOffMeshConnections:: input file {} not found!", offMeshFilePath);
return;
}
@@ -237,7 +223,7 @@ namespace MMAP
/**************************************************************************/
- void TileBuilder::WorkerThread()
+ void MapTileBuilder::WorkerThread()
{
while (true)
{
@@ -251,7 +237,7 @@ namespace MMAP
dtNavMesh* navMesh = dtAllocNavMesh();
if (!navMesh->init(&tileInfo.m_navMeshParams))
{
- printf("[Map %04i] Failed creating navmesh for tile %i,%i !\n", tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY);
+ TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh for tile {},{} !", tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY);
dtFreeNavMesh(navMesh);
return;
}
@@ -264,11 +250,12 @@ namespace MMAP
void MapBuilder::buildMaps(Optional<uint32> mapID)
{
- printf("Using %u threads to generate mmaps\n", m_threads);
+ TC_LOG_INFO("maps.mmapgen", "Using {} threads to generate mmaps", m_threads);
for (unsigned int i = 0; i < m_threads; ++i)
{
- m_tileBuilders.push_back(new TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput));
+ m_tileBuilders.push_back(new MapTileBuilder(this, m_maxWalkableAngle, m_maxWalkableAngleNotSteep,
+ m_skipLiquid, m_bigBaseUnit, m_debugOutput, &m_offMeshConnections));
}
if (mapID)
@@ -304,7 +291,7 @@ namespace MMAP
if (!file)
return;
- printf("Building mesh from file\n");
+ TC_LOG_INFO("maps.mmapgen", "Building mesh from file");
int tileX, tileY, mapId;
if (fread(&mapId, sizeof(int), 1, file) != 1)
{
@@ -326,7 +313,7 @@ namespace MMAP
buildNavMesh(mapId, navMesh);
if (!navMesh)
{
- printf("Failed creating navmesh! \n");
+ TC_LOG_ERROR("maps.mmapgen", "Failed creating navmesh!");
fclose(file);
return;
}
@@ -375,10 +362,11 @@ namespace MMAP
TerrainBuilder::cleanVertices(data.solidVerts, data.solidTris);
// get bounds of current tile
float bmin[3], bmax[3];
- getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
+ TileBuilder::getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
// build navmesh tile
- TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
+ MapTileBuilder tileBuilder(this, m_maxWalkableAngle, m_maxWalkableAngleNotSteep,
+ m_skipLiquid, m_bigBaseUnit, m_debugOutput, &m_offMeshConnections);
tileBuilder.buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
fclose(file);
}
@@ -390,13 +378,14 @@ namespace MMAP
buildNavMesh(mapID, navMesh);
if (!navMesh)
{
- printf("Failed creating navmesh! \n");
+ TC_LOG_ERROR("maps.mmapgen", "Failed creating navmesh!");
return;
}
// ToDo: delete the old tile as the user clearly wants to rebuild it
- TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
+ MapTileBuilder tileBuilder(this, m_maxWalkableAngle, m_maxWalkableAngleNotSteep,
+ m_skipLiquid, m_bigBaseUnit, m_debugOutput, &m_offMeshConnections);
tileBuilder.buildTile(mapID, tileX, tileY, navMesh);
dtFreeNavMesh(navMesh);
@@ -417,13 +406,13 @@ namespace MMAP
buildNavMesh(mapID, navMesh);
if (!navMesh)
{
- printf("[Map %04u] Failed creating navmesh!\n", mapID);
+ TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh!", mapID);
m_totalTilesProcessed += tiles.size();
return;
}
// now start building mmtiles for each tile
- printf("[Map %04u] We have %u tiles. \n", mapID, uint32(tiles.size()));
+ TC_LOG_INFO("maps.mmapgen", "[Map {:04}] We have {} tiles.", mapID, tiles.size());
for (uint32 packedTile : tiles)
{
uint32 tileX, tileY;
@@ -444,59 +433,6 @@ namespace MMAP
}
/**************************************************************************/
- void TileBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
- {
- if(shouldSkipTile(mapID, tileX, tileY))
- {
- ++m_mapBuilder->m_totalTilesProcessed;
- return;
- }
-
- printf("%u%% [Map %04i] Building tile [%02u,%02u]\n", m_mapBuilder->currentPercentageDone(), mapID, tileX, tileY);
-
- MeshData meshData;
-
- // get heightmap data
- m_terrainBuilder->loadMap(mapID, tileX, tileY, meshData);
-
- // get model data
- m_terrainBuilder->loadVMap(mapID, tileY, tileX, meshData);
-
- // if there is no data, give up now
- if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
- {
- ++m_mapBuilder->m_totalTilesProcessed;
- return;
- }
-
- // remove unused vertices
- TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
- TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);
-
- // gather all mesh data for final data check, and bounds calculation
- G3D::Array<float> allVerts;
- allVerts.append(meshData.liquidVerts);
- allVerts.append(meshData.solidVerts);
-
- if (!allVerts.size())
- {
- ++m_mapBuilder->m_totalTilesProcessed;
- return;
- }
-
- // get bounds of current tile
- float bmin[3], bmax[3];
- m_mapBuilder->getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
-
- m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_mapBuilder->m_offMeshConnections);
-
- // build navmesh tile
- buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
-
- ++m_mapBuilder->m_totalTilesProcessed;
- }
-
- /**************************************************************************/
void MapBuilder::buildNavMesh(uint32 mapID, dtNavMesh* &navMesh)
{
// if map has a parent we use that to generate dtNavMeshParams - worldserver will load all missing tiles from that map
@@ -541,7 +477,7 @@ namespace MMAP
// use Max because '32 - tileX' is negative for values over 32
float bmin[3], bmax[3];
- getTileBounds(tileXMax, tileYMax, nullptr, 0, bmin, bmax);
+ TileBuilder::getTileBounds(tileXMax, tileYMax, nullptr, 0, bmin, bmax);
/*** now create the navmesh ***/
@@ -555,10 +491,10 @@ namespace MMAP
navMeshParams.maxPolys = maxPolysPerTile;
navMesh = dtAllocNavMesh();
- printf("[Map %04u] Creating navMesh...\n", mapID);
+ TC_LOG_INFO("maps.mmapgen", "[Map {:04}] Creating navMesh...", mapID);
if (!navMesh->init(&navMeshParams))
{
- printf("[Map %04u] Failed creating navmesh! \n", mapID);
+ TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh!", mapID);
return;
}
@@ -569,7 +505,7 @@ namespace MMAP
{
dtFreeNavMesh(navMesh);
navMesh = nullptr;
- perror(Trinity::StringFormat("[Map {:04}] Failed to open {} for writing!\n", mapID, fileName).c_str());
+ TC_LOG_ERROR("maps.mmapgen", "{}: [Map {:04}] Failed to open {} for writing!\n", strerror(errno), mapID, fileName);
return;
}
@@ -579,366 +515,6 @@ namespace MMAP
}
/**************************************************************************/
- void TileBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
- MeshData &meshData, float bmin[3], float bmax[3],
- dtNavMesh* navMesh)
- {
- // console output
- std::string tileString = Trinity::StringFormat("[Map {:04}] [{:02},{:02}]: ", mapID, tileX, tileY);
- printf("%s Building movemap tiles...\n", tileString.c_str());
-
- IntermediateValues iv;
-
- float* tVerts = meshData.solidVerts.getCArray();
- int tVertCount = meshData.solidVerts.size() / 3;
- int* tTris = meshData.solidTris.getCArray();
- int tTriCount = meshData.solidTris.size() / 3;
-
- float* lVerts = meshData.liquidVerts.getCArray();
- int lVertCount = meshData.liquidVerts.size() / 3;
- int* lTris = meshData.liquidTris.getCArray();
- int lTriCount = meshData.liquidTris.size() / 3;
- uint8* lTriFlags = meshData.liquidType.getCArray();
-
- const TileConfig tileConfig = TileConfig(m_bigBaseUnit);
- int TILES_PER_MAP = tileConfig.TILES_PER_MAP;
- float BASE_UNIT_DIM = tileConfig.BASE_UNIT_DIM;
- rcConfig config = m_mapBuilder->GetMapSpecificConfig(mapID, bmin, bmax, tileConfig);
-
- // this sets the dimensions of the heightfield - should maybe happen before border padding
- rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
-
- // allocate subregions : tiles
- Tile* tiles = new Tile[TILES_PER_MAP * TILES_PER_MAP];
-
- // Initialize per tile config.
- rcConfig tileCfg = config;
- tileCfg.width = config.tileSize + config.borderSize*2;
- tileCfg.height = config.tileSize + config.borderSize*2;
-
- // merge per tile poly and detail meshes
- rcPolyMesh** pmmerge = new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP];
- rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP];
- int nmerge = 0;
- // build all tiles
- for (int y = 0; y < TILES_PER_MAP; ++y)
- {
- for (int x = 0; x < TILES_PER_MAP; ++x)
- {
- Tile& tile = tiles[x + y * TILES_PER_MAP];
-
- // Calculate the per tile bounding box.
- tileCfg.bmin[0] = config.bmin[0] + x * float(config.tileSize * config.cs);
- tileCfg.bmin[2] = config.bmin[2] + y * float(config.tileSize * config.cs);
- tileCfg.bmax[0] = config.bmin[0] + (x + 1) * float(config.tileSize * config.cs);
- tileCfg.bmax[2] = config.bmin[2] + (y + 1) * float(config.tileSize * config.cs);
-
- tileCfg.bmin[0] -= tileCfg.borderSize * tileCfg.cs;
- tileCfg.bmin[2] -= tileCfg.borderSize * tileCfg.cs;
- tileCfg.bmax[0] += tileCfg.borderSize * tileCfg.cs;
- tileCfg.bmax[2] += tileCfg.borderSize * tileCfg.cs;
-
- // build heightfield
- tile.solid = rcAllocHeightfield();
- if (!tile.solid || !rcCreateHeightfield(m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
- {
- printf("%s Failed building heightfield! \n", tileString.c_str());
- continue;
- }
-
- // mark all walkable tiles, both liquids and solids
-
- /* we want to have triangles with slope less than walkableSlopeAngleNotSteep (<= 55) to have NAV_AREA_GROUND
- * and with slope between walkableSlopeAngleNotSteep and walkableSlopeAngle (55 < .. <= 70) to have NAV_AREA_GROUND_STEEP.
- * we achieve this using recast API: memset everything to NAV_AREA_GROUND_STEEP, call rcClearUnwalkableTriangles with 70 so
- * any area above that will get RC_NULL_AREA (unwalkable), then call rcMarkWalkableTriangles with 55 to set NAV_AREA_GROUND
- * on anything below 55 . Players and idle Creatures can use NAV_AREA_GROUND, while Creatures in combat can use NAV_AREA_GROUND_STEEP.
- */
- unsigned char* triFlags = new unsigned char[tTriCount];
- memset(triFlags, NAV_AREA_GROUND_STEEP, tTriCount*sizeof(unsigned char));
- rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
- rcMarkWalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngleNotSteep, tVerts, tVertCount, tTris, tTriCount, triFlags, NAV_AREA_GROUND);
- rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
- delete[] triFlags;
-
- rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid);
- rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
- rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid);
-
- // add liquid triangles
- rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
-
- // compact heightfield spans
- tile.chf = rcAllocCompactHeightfield();
- if (!tile.chf || !rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf))
- {
- printf("%s Failed compacting heightfield! \n", tileString.c_str());
- continue;
- }
-
- // build polymesh intermediates
- if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *tile.chf))
- {
- printf("%s Failed eroding area! \n", tileString.c_str());
- continue;
- }
-
- if (!rcMedianFilterWalkableArea(m_rcContext, *tile.chf))
- {
- printf("%s Failed filtering area! \n", tileString.c_str());
- continue;
- }
-
- if (!rcBuildDistanceField(m_rcContext, *tile.chf))
- {
- printf("%s Failed building distance field! \n", tileString.c_str());
- continue;
- }
-
- if (!rcBuildRegions(m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
- {
- printf("%s Failed building regions! \n", tileString.c_str());
- continue;
- }
-
- tile.cset = rcAllocContourSet();
- if (!tile.cset || !rcBuildContours(m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset))
- {
- printf("%s Failed building contours! \n", tileString.c_str());
- continue;
- }
-
- // build polymesh
- tile.pmesh = rcAllocPolyMesh();
- if (!tile.pmesh || !rcBuildPolyMesh(m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh))
- {
- printf("%s Failed building polymesh! \n", tileString.c_str());
- continue;
- }
-
- tile.dmesh = rcAllocPolyMeshDetail();
- if (!tile.dmesh || !rcBuildPolyMeshDetail(m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh))
- {
- printf("%s Failed building polymesh detail! \n", tileString.c_str());
- continue;
- }
-
- // free those up
- // we may want to keep them in the future for debug
- // but right now, we don't have the code to merge them
- rcFreeHeightField(tile.solid);
- tile.solid = nullptr;
- rcFreeCompactHeightfield(tile.chf);
- tile.chf = nullptr;
- rcFreeContourSet(tile.cset);
- tile.cset = nullptr;
-
- pmmerge[nmerge] = tile.pmesh;
- dmmerge[nmerge] = tile.dmesh;
- nmerge++;
- }
- }
-
- iv.polyMesh = rcAllocPolyMesh();
- if (!iv.polyMesh)
- {
- printf("%s alloc iv.polyMesh FAILED!\n", tileString.c_str());
- delete[] pmmerge;
- delete[] dmmerge;
- delete[] tiles;
- return;
- }
- rcMergePolyMeshes(m_rcContext, pmmerge, nmerge, *iv.polyMesh);
-
- iv.polyMeshDetail = rcAllocPolyMeshDetail();
- if (!iv.polyMeshDetail)
- {
- printf("%s alloc m_dmesh FAILED!\n", tileString.c_str());
- delete[] pmmerge;
- delete[] dmmerge;
- delete[] tiles;
- return;
- }
- rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail);
-
- // free things up
- delete[] pmmerge;
- delete[] dmmerge;
- delete[] tiles;
-
- // set polygons as walkable
- // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
- for (int i = 0; i < iv.polyMesh->npolys; ++i)
- {
- if (uint8 area = iv.polyMesh->areas[i] & NAV_AREA_ALL_MASK)
- {
- if (area >= NAV_AREA_MIN_VALUE)
- iv.polyMesh->flags[i] = 1 << (NAV_AREA_MAX_VALUE - area);
- else
- iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future
- }
- }
-
- // setup mesh parameters
- dtNavMeshCreateParams params;
- memset(&params, 0, sizeof(params));
- params.verts = iv.polyMesh->verts;
- params.vertCount = iv.polyMesh->nverts;
- params.polys = iv.polyMesh->polys;
- params.polyAreas = iv.polyMesh->areas;
- params.polyFlags = iv.polyMesh->flags;
- params.polyCount = iv.polyMesh->npolys;
- params.nvp = iv.polyMesh->nvp;
- params.detailMeshes = iv.polyMeshDetail->meshes;
- params.detailVerts = iv.polyMeshDetail->verts;
- params.detailVertsCount = iv.polyMeshDetail->nverts;
- params.detailTris = iv.polyMeshDetail->tris;
- params.detailTriCount = iv.polyMeshDetail->ntris;
-
- params.offMeshConVerts = meshData.offMeshConnections.getCArray();
- params.offMeshConCount = meshData.offMeshConnections.size()/6;
- params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
- params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
- params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
- params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
-
- params.walkableHeight = BASE_UNIT_DIM*config.walkableHeight; // agent height
- params.walkableRadius = BASE_UNIT_DIM*config.walkableRadius; // agent radius
- params.walkableClimb = BASE_UNIT_DIM*config.walkableClimb; // keep less that walkableHeight (aka agent height)!
- params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) / GRID_SIZE;
- params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) / GRID_SIZE;
- rcVcopy(params.bmin, bmin);
- rcVcopy(params.bmax, bmax);
- params.cs = config.cs;
- params.ch = config.ch;
- params.tileLayer = 0;
- params.buildBvTree = true;
-
- // will hold final navmesh
- unsigned char* navData = nullptr;
- int navDataSize = 0;
-
- do
- {
- // these values are checked within dtCreateNavMeshData - handle them here
- // so we have a clear error message
- if (params.nvp > DT_VERTS_PER_POLYGON)
- {
- printf("%s Invalid verts-per-polygon value! \n", tileString.c_str());
- break;
- }
- if (params.vertCount >= 0xffff)
- {
- printf("%s Too many vertices! \n", tileString.c_str());
- break;
- }
- if (!params.vertCount || !params.verts)
- {
- // occurs mostly when adjacent tiles have models
- // loaded but those models don't span into this tile
-
- // message is an annoyance
- //printf("%sNo vertices to build tile! \n", tileString.c_str());
- break;
- }
- if (!params.polyCount || !params.polys)
- {
- // we have flat tiles with no actual geometry - don't build those, its useless
- // keep in mind that we do output those into debug info
- printf("%s No polygons to build on tile! \n", tileString.c_str());
- break;
- }
- if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
- {
- printf("%s No detail mesh to build tile! \n", tileString.c_str());
- break;
- }
-
- printf("%s Building navmesh tile...\n", tileString.c_str());
- if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
- {
- printf("%s Failed building navmesh tile! \n", tileString.c_str());
- break;
- }
-
- dtTileRef tileRef = 0;
- printf("%s Adding tile to navmesh...\n", tileString.c_str());
- // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
- // is removed via removeTile()
- dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
- if (!tileRef || !dtStatusSucceed(dtResult))
- {
- printf("%s Failed adding tile to navmesh! \n", tileString.c_str());
- break;
- }
-
- // file output
- std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileY, tileX);
- FILE* file = fopen(fileName.c_str(), "wb");
- if (!file)
- {
- perror(Trinity::StringFormat("[Map {:04}] Failed to open {} for writing!\n", mapID, fileName).c_str());
- navMesh->removeTile(tileRef, nullptr, nullptr);
- break;
- }
-
- printf("%s Writing to file...\n", tileString.c_str());
-
- // write header
- MmapTileHeader header;
- header.usesLiquids = m_terrainBuilder->usesLiquids();
- header.size = uint32(navDataSize);
- fwrite(&header, sizeof(MmapTileHeader), 1, file);
-
- /*
- dtMeshHeader* navDataHeader = (dtMeshHeader*)navData;
- printf("Poly count: %d\n", navDataHeader->polyCount);
- */
-
- // write data
- fwrite(navData, sizeof(unsigned char), navDataSize, file);
- fclose(file);
-
- // now that tile is written to disk, we can unload it
- navMesh->removeTile(tileRef, nullptr, nullptr);
- }
- while (false);
-
- if (m_debugOutput)
- {
- // restore padding so that the debug visualization is correct
- for (int i = 0; i < iv.polyMesh->nverts; ++i)
- {
- unsigned short* v = &iv.polyMesh->verts[i*3];
- v[0] += (unsigned short)config.borderSize;
- v[2] += (unsigned short)config.borderSize;
- }
-
- iv.generateObjFile(mapID, tileX, tileY, meshData);
- iv.writeIV(mapID, tileX, tileY);
- }
- }
-
- /**************************************************************************/
- void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const
- {
- // this is for elevation
- if (verts && vertCount)
- rcCalcBounds(verts, vertCount, bmin, bmax);
- else
- {
- bmin[1] = FLT_MIN;
- bmax[1] = FLT_MAX;
- }
-
- // this is for width and depth
- bmax[0] = (32 - int(tileX)) * GRID_SIZE;
- bmax[2] = (32 - int(tileY)) * GRID_SIZE;
- bmin[0] = bmax[0] - GRID_SIZE;
- bmin[2] = bmax[2] - GRID_SIZE;
- }
-
- /**************************************************************************/
bool MapBuilder::shouldSkipMap(uint32 mapID) const
{
if (m_mapid >= 0)
@@ -1024,7 +600,7 @@ namespace MMAP
}
/**************************************************************************/
- bool TileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
+ bool MapTileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
{
std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileY, tileX);
FILE* file = fopen(fileName.c_str(), "rb");
@@ -1043,55 +619,12 @@ namespace MMAP
if (header.mmapVersion != MMAP_VERSION)
return false;
- return true;
+ return TileBuilder::shouldSkipTile(mapID, tileX, tileY);
}
- rcConfig MapBuilder::GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const
+ std::string MapTileBuilder::GetProgressText() const
{
- rcConfig config;
- memset(&config, 0, sizeof(rcConfig));
-
- rcVcopy(config.bmin, bmin);
- rcVcopy(config.bmax, bmax);
-
- config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
- config.cs = tileConfig.BASE_UNIT_DIM;
- config.ch = tileConfig.BASE_UNIT_DIM;
- // Keeping these 2 slope angles the same reduces a lot the number of polys.
- // 55 should be the minimum, maybe 70 is ok (keep in mind blink uses mmaps), 85 is too much for players
- config.walkableSlopeAngle = m_maxWalkableAngle ? *m_maxWalkableAngle : 55;
- config.walkableSlopeAngleNotSteep = m_maxWalkableAngleNotSteep ? *m_maxWalkableAngleNotSteep : 55;
- config.tileSize = tileConfig.VERTEX_PER_TILE;
- config.walkableRadius = m_bigBaseUnit ? 1 : 2;
- config.borderSize = config.walkableRadius + 3;
- config.maxEdgeLen = tileConfig.VERTEX_PER_TILE + 1; // anything bigger than tileSize
- config.walkableHeight = m_bigBaseUnit ? 3 : 6;
- // a value >= 3|6 allows npcs to walk over some fences
- // a value >= 4|8 allows npcs to walk over all fences
- config.walkableClimb = m_bigBaseUnit ? 3 : 6;
- config.minRegionArea = rcSqr(60);
- config.mergeRegionArea = rcSqr(50);
- config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
- config.detailSampleDist = config.cs * 16;
- config.detailSampleMaxError = config.ch * 1;
-
- switch (mapID)
- {
- // Blade's Edge Arena
- case 562:
- // This allows to walk on the ropes to the pillars
- config.walkableRadius = 0;
- break;
- // Blackfathom Deeps
- case 48:
- // Reduce the chance to have underground levels
- config.ch *= 2;
- break;
- default:
- break;
- }
-
- return config;
+ return Trinity::StringFormat("{}%", m_mapBuilder->currentPercentageDone());
}
/**************************************************************************/
diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h
index 388dc53a072..34c3a113274 100644
--- a/src/tools/mmaps_generator/MapBuilder.h
+++ b/src/tools/mmaps_generator/MapBuilder.h
@@ -22,8 +22,8 @@
#include "Optional.h"
#include "ProducerConsumerQueue.h"
#include "TerrainBuilder.h"
+#include "TileBuilder.h"
#include <DetourNavMesh.h>
-#include <Recast.h>
#include <atomic>
#include <span>
#include <thread>
@@ -33,45 +33,6 @@ namespace MMAP
{
typedef std::unordered_map<uint32, Trinity::Containers::FlatSet<uint32>> TileList;
- struct Tile
- {
- Tile() : chf(nullptr), solid(nullptr), cset(nullptr), pmesh(nullptr), dmesh(nullptr) {}
- ~Tile()
- {
- rcFreeCompactHeightfield(chf);
- rcFreeContourSet(cset);
- rcFreeHeightField(solid);
- rcFreePolyMesh(pmesh);
- rcFreePolyMeshDetail(dmesh);
- }
- rcCompactHeightfield* chf;
- rcHeightfield* solid;
- rcContourSet* cset;
- rcPolyMesh* pmesh;
- rcPolyMeshDetail* dmesh;
- };
-
- struct TileConfig
- {
- TileConfig(bool bigBaseUnit)
- {
- // these are WORLD UNIT based metrics
- // this are basic unit dimentions
- // value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc )
- BASE_UNIT_DIM = bigBaseUnit ? 0.5333333f : 0.2666666f;
-
- // All are in UNIT metrics!
- VERTEX_PER_MAP = int(GRID_SIZE / BASE_UNIT_DIM + 0.5f);
- VERTEX_PER_TILE = bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP
- TILES_PER_MAP = VERTEX_PER_MAP / VERTEX_PER_TILE;
- }
-
- float BASE_UNIT_DIM;
- int VERTEX_PER_MAP;
- int VERTEX_PER_TILE;
- int TILES_PER_MAP;
- };
-
struct TileInfo
{
TileInfo() : m_mapId(uint32(-1)), m_tileX(), m_tileY(), m_navMeshParams() {}
@@ -84,46 +45,37 @@ namespace MMAP
// ToDo: move this to its own file. For now it will stay here to keep the changes to a minimum, especially in the cpp file
class MapBuilder;
- class TileBuilder
+
+ class MapTileBuilder : public TileBuilder
{
public:
- TileBuilder(MapBuilder* mapBuilder,
+ MapTileBuilder(MapBuilder* mapBuilder,
+ Optional<float> maxWalkableAngle,
+ Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid,
bool bigBaseUnit,
- bool debugOutput);
-
- TileBuilder(TileBuilder&&) = default;
- ~TileBuilder();
+ bool debugOutput,
+ std::vector<OffMeshData> const* offMeshConnections);
+ ~MapTileBuilder();
void WorkerThread();
void WaitCompletion();
- void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh);
- // move map building
- void buildMoveMapTile(uint32 mapID,
- uint32 tileX,
- uint32 tileY,
- MeshData& meshData,
- float bmin[3],
- float bmax[3],
- dtNavMesh* navMesh);
+ bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const override;
- bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const;
+ std::string GetProgressText() const override;
- private:
- bool m_bigBaseUnit;
- bool m_debugOutput;
+ void OnTileDone() override;
+ private:
MapBuilder* m_mapBuilder;
- TerrainBuilder* m_terrainBuilder;
std::thread m_workerThread;
- // build performance - not really used for now
- rcContext* m_rcContext;
};
class MapBuilder
{
friend class TileBuilder;
+ friend class MapTileBuilder;
public:
MapBuilder(Optional<float> maxWalkableAngle,
@@ -157,24 +109,17 @@ namespace MMAP
void buildNavMesh(uint32 mapID, dtNavMesh* &navMesh);
- void getTileBounds(uint32 tileX, uint32 tileY,
- float* verts, int vertCount,
- float* bmin, float* bmax) const;
-
bool shouldSkipMap(uint32 mapID) const;
bool isTransportMap(uint32 mapID) const;
bool isDevMap(uint32 mapID) const;
bool isBattlegroundMap(uint32 mapID) const;
bool isContinentMap(uint32 mapID) const;
- rcConfig GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const;
-
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const;
uint32 currentPercentageDone() const;
void ParseOffMeshConnectionsFile(char const* offMeshFilePath);
- TerrainBuilder* m_terrainBuilder;
TileList m_tiles;
bool m_debugOutput;
@@ -195,9 +140,6 @@ namespace MMAP
uint32 m_totalTiles;
std::atomic<uint32> m_totalTilesProcessed;
- // build performance - not really used for now
- rcContext* m_rcContext;
-
std::vector<TileBuilder*> m_tileBuilders;
ProducerConsumerQueue<TileInfo> _queue;
std::atomic<bool> _cancelationToken;
diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h
index 17d354a0997..b7c05fe1541 100644
--- a/src/tools/mmaps_generator/PathCommon.h
+++ b/src/tools/mmaps_generator/PathCommon.h
@@ -141,7 +141,7 @@ namespace MMAP
namespace VMapFactory
{
- std::unique_ptr<VMAP::VMapManager2> CreateVMapManager();
+ std::unique_ptr<VMAP::VMapManager2> CreateVMapManager(uint32 mapId);
}
}
diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp
index 88f56a2e425..1e98b19a852 100644
--- a/src/tools/mmaps_generator/PathGenerator.cpp
+++ b/src/tools/mmaps_generator/PathGenerator.cpp
@@ -20,6 +20,7 @@
#include "DB2FileSystemSource.h"
#include "ExtractorDB2LoadInfo.h"
#include "Locales.h"
+#include "Log.h"
#include "MapBuilder.h"
#include "PathCommon.h"
#include "Timer.h"
@@ -37,7 +38,6 @@ constexpr char Readme[] =
namespace
{
std::unordered_map<uint32, uint8> _liquidTypes;
- std::unordered_map<uint32, std::vector<uint32>> _mapDataForVmapInitialization;
}
namespace MMAP
@@ -46,10 +46,21 @@ namespace MMAP
namespace VMapFactory
{
- std::unique_ptr<VMAP::VMapManager2> CreateVMapManager()
+ std::unique_ptr<VMAP::VMapManager2> CreateVMapManager(uint32 mapId)
{
std::unique_ptr<VMAP::VMapManager2> vmgr = std::make_unique<VMAP::VMapManager2>();
- vmgr->InitializeThreadUnsafe(_mapDataForVmapInitialization);
+
+ do
+ {
+ int32 parentMapId = sMapStore[mapId].ParentMapID;
+
+ vmgr->InitializeThreadUnsafe(mapId, parentMapId);
+ if (parentMapId < 0)
+ break;
+
+ mapId = parentMapId;
+ } while (true);
+
vmgr->GetLiquidFlagsPtr = [](uint32 liquidId) -> uint32
{
auto itr = _liquidTypes.find(liquidId);
@@ -60,11 +71,22 @@ namespace MMAP
}
}
+void SetupLogging()
+{
+ Log* log = sLog;
+
+ log->CreateAppenderFromConfigLine("Appender.Console", "1,2,0"); // APPENDER_CONSOLE | LOG_LEVEL_DEBUG | APPENDER_FLAGS_NONE
+ log->CreateLoggerFromConfigLine("Logger.root", "2,Console"); // LOG_LEVEL_DEBUG | Console appender
+ log->CreateLoggerFromConfigLine("Logger.tool.mmapgen", "2,Console"); // LOG_LEVEL_DEBUG | Console appender
+ log->CreateLoggerFromConfigLine("Logger.maps", "3,Console"); // LOG_LEVEL_DEBUG | Console appender
+ log->CreateLoggerFromConfigLine("Logger.maps.mmapgen", "2,Console"); // LOG_LEVEL_DEBUG | Console appender
+}
+
bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
{
if (MMAP::getDirContents(dbcLocales, "dbc") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dbcLocales.empty())
{
- printf("'dbc' directory is empty or does not exist\n");
+ TC_LOG_ERROR("tool.mmapgen", "'dbc' directory is empty or does not exist");
return false;
}
@@ -72,14 +94,14 @@ bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
if (MMAP::getDirContents(dirFiles, "maps") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
- printf("'maps' directory is empty or does not exist\n");
+ TC_LOG_ERROR("tool.mmapgen", "'maps' directory is empty or does not exist");
return false;
}
dirFiles.clear();
if (MMAP::getDirContents(dirFiles, "vmaps/0000", "*.vmtree") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
- printf("'vmaps' directory is empty or does not exist\n");
+ TC_LOG_ERROR("tool.mmapgen", "'vmaps' directory is empty or does not exist");
return false;
}
@@ -88,7 +110,7 @@ bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
{
if (!boost::filesystem::create_directory("mmaps"))
{
- printf("'mmaps' directory does not exist and failed to create it\n");
+ TC_LOG_ERROR("tool.mmapgen", "'mmaps' directory does not exist and failed to create it");
return false;
}
}
@@ -100,7 +122,7 @@ bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
{
if (!boost::filesystem::create_directory("meshes"))
{
- printf("'meshes' directory does not exist and failed to create it (no place to put debugOutput files)\n");
+ TC_LOG_ERROR("tool.mmapgen", "'meshes' directory does not exist and failed to create it (no place to put debugOutput files)");
return false;
}
}
@@ -111,7 +133,7 @@ bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
int finish(char const* message, int returnValue)
{
- printf("%s", message);
+ TC_LOG_FATAL("tool.mmapgen.commandline", "{}", message);
getchar(); // Wait for user input
return returnValue;
}
@@ -147,7 +169,7 @@ bool handleArgs(int argc, char** argv,
if (maxangle <= 90.f && maxangle >= 0.f)
maxAngle = maxangle;
else
- printf("invalid option for '--maxAngle', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--maxAngle', using default");
}
else if (strcmp(argv[i], "--maxAngleNotSteep") == 0)
{
@@ -159,7 +181,7 @@ bool handleArgs(int argc, char** argv,
if (maxangle <= 90.f && maxangle >= 0.f)
maxAngleNotSteep = maxangle;
else
- printf("invalid option for '--maxAngleNotSteep', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--maxAngleNotSteep', using default");
}
else if (strcmp(argv[i], "--threads") == 0)
{
@@ -193,7 +215,7 @@ bool handleArgs(int argc, char** argv,
if (tileX < 0 || tileY < 0)
{
- printf("invalid tile coords.\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid tile coords.");
return false;
}
}
@@ -208,7 +230,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
skipLiquid = false;
else
- printf("invalid option for '--skipLiquid', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--skipLiquid', using default");
}
else if (strcmp(argv[i], "--skipContinents") == 0)
{
@@ -221,7 +243,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
skipContinents = false;
else
- printf("invalid option for '--skipContinents', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--skipContinents', using default");
}
else if (strcmp(argv[i], "--skipJunkMaps") == 0)
{
@@ -234,7 +256,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
skipJunkMaps = false;
else
- printf("invalid option for '--skipJunkMaps', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--skipJunkMaps', using default");
}
else if (strcmp(argv[i], "--skipBattlegrounds") == 0)
{
@@ -247,7 +269,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
skipBattlegrounds = false;
else
- printf("invalid option for '--skipBattlegrounds', using default\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--skipBattlegrounds', using default");
}
else if (strcmp(argv[i], "--debugOutput") == 0)
{
@@ -260,7 +282,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
debugOutput = false;
else
- printf("invalid option for '--debugOutput', using default true\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--debugOutput', using default true");
}
else if (strcmp(argv[i], "--silent") == 0)
{
@@ -277,7 +299,7 @@ bool handleArgs(int argc, char** argv,
else if (strcmp(param, "false") == 0)
bigBaseUnit = false;
else
- printf("invalid option for '--bigBaseUnit', using default false\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid option for '--bigBaseUnit', using default false");
}
else if (strcmp(argv[i], "--offMeshInput") == 0)
{
@@ -293,7 +315,7 @@ bool handleArgs(int argc, char** argv,
}
else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-?"))
{
- printf("%s\n", Readme);
+ TC_LOG_INFO("tool.mmapgen", "{}", Readme);
silent = true;
return false;
}
@@ -304,16 +326,16 @@ bool handleArgs(int argc, char** argv,
mapnum = map;
else
{
- printf("invalid map id\n");
+ TC_LOG_ERROR("tool.mmapgen.commandline", "invalid map id {}", map);
return false;
}
}
}
-#ifndef NDEBUG
+#if !defined(NDEBUG)
if (!allowDebug)
{
- finish("Build mmaps_generator in RelWithDebInfo or Release mode or it will take hours to complete!!!\nUse '--allowDebug' argument if you really want to run this tool in Debug.\n", -2);
+ finish("Build mmaps_generator in RelWithDebInfo or Release mode or it will take hours to complete!!!\nUse '--allowDebug' argument if you really want to run this tool in Debug.", -2);
silent = true;
return false;
}
@@ -350,10 +372,9 @@ std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale, bool sil
return liquidData;
}
-std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& locale, bool silent, int32 errorExitCode)
+void LoadMap(std::string const& locale, bool silent, int32 errorExitCode)
{
DB2FileLoader mapDb2;
- std::unordered_map<uint32, std::vector<uint32>> mapData;
DB2FileSystemSource mapSource((boost::filesystem::path("dbc") / locale / "Map.db2").string());
try
{
@@ -364,12 +385,9 @@ std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& local
if (!record)
continue;
- mapData.emplace(std::piecewise_construct, std::forward_as_tuple(record.GetId()), std::forward_as_tuple());
int16 parentMapId = int16(record.GetUInt16("ParentMapID"));
if (parentMapId < 0)
parentMapId = int16(record.GetUInt16("CosmeticParentMapID"));
- if (parentMapId != -1)
- mapData[parentMapId].push_back(record.GetId());
MMAP::MapEntry& map = MMAP::sMapStore[record.GetId()];
map.MapType = record.GetUInt8("MapType");
@@ -385,8 +403,6 @@ std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& local
exit(finish(e.what(), errorExitCode));
}
-
- return mapData;
}
int main(int argc, char** argv)
@@ -395,7 +411,9 @@ int main(int argc, char** argv)
Trinity::Locale::Init();
- Trinity::Banner::Show("MMAP generator", [](char const* text) { printf("%s\n", text); }, nullptr);
+ SetupLogging();
+
+ Trinity::Banner::Show("MMAP generator", [](char const* text) { TC_LOG_INFO("tool.mmapgen", "{}", text); }, nullptr);
unsigned int threads = std::thread::hardware_concurrency();
int mapnum = -1;
@@ -424,9 +442,9 @@ int main(int argc, char** argv)
if (silent)
return -2;
- printf("You have specifed debug output, but didn't specify a map to generate.\n");
- printf("This will generate debug output for ALL maps.\n");
- printf("Are you sure you want to continue? (y/n) ");
+ TC_LOG_INFO("tool.mmapgen", "You have specifed debug output, but didn't specify a map to generate.");
+ TC_LOG_INFO("tool.mmapgen", "This will generate debug output for ALL maps.");
+ TC_LOG_INFO("tool.mmapgen", "Are you sure you want to continue? (y/n)");
if (getchar() != 'y')
return 0;
}
@@ -437,7 +455,7 @@ int main(int argc, char** argv)
_liquidTypes = LoadLiquid(dbcLocales[0], silent, -5);
- _mapDataForVmapInitialization = LoadMap(dbcLocales[0], silent, -4);
+ LoadMap(dbcLocales[0], silent, -4);
MMAP::MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath, threads);
@@ -453,7 +471,7 @@ int main(int argc, char** argv)
builder.buildMaps({});
if (!silent)
- printf("Finished. MMAPS were built in %s\n", secsToTimeString(GetMSTimeDiffToNow(start) / 1000).c_str());
+ TC_LOG_INFO("tool.mmapgen", "Finished. MMAPS were built in {}", secsToTimeString(GetMSTimeDiffToNow(start) / 1000));
return 0;
}
diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp
index 69a9e13adc7..a2a542ed095 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.cpp
+++ b/src/tools/mmaps_generator/TerrainBuilder.cpp
@@ -16,6 +16,7 @@
*/
#include "TerrainBuilder.h"
+#include "Log.h"
#include "MapDefines.h"
#include "MapTree.h"
#include "MMapDefines.h"
@@ -28,10 +29,9 @@
namespace MMAP
{
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
- TerrainBuilder::~TerrainBuilder() { }
/**************************************************************************/
- void TerrainBuilder::getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc)
+ void TerrainBuilder::getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc)
{
switch (portion)
{
@@ -64,31 +64,31 @@ namespace MMAP
}
/**************************************************************************/
- void TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
+ void TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager)
{
- if (loadMap(mapID, tileX, tileY, meshData, ENTIRE))
+ if (loadMap(mapID, tileX, tileY, meshData, vmapManager, ENTIRE))
{
- loadMap(mapID, tileX+1, tileY, meshData, LEFT);
- loadMap(mapID, tileX-1, tileY, meshData, RIGHT);
- loadMap(mapID, tileX, tileY+1, meshData, TOP);
- loadMap(mapID, tileX, tileY-1, meshData, BOTTOM);
+ loadMap(mapID, tileX+1, tileY, meshData, vmapManager, LEFT);
+ loadMap(mapID, tileX-1, tileY, meshData, vmapManager, RIGHT);
+ loadMap(mapID, tileX, tileY+1, meshData, vmapManager, TOP);
+ loadMap(mapID, tileX, tileY-1, meshData, vmapManager, BOTTOM);
}
}
/**************************************************************************/
- bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion)
+ bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager, Spot portion)
{
std::string mapFileName = Trinity::StringFormat("maps/{:04}_{:02}_{:02}.map", mapID, tileY, tileX);
FILE* mapFile = fopen(mapFileName.c_str(), "rb");
if (!mapFile)
{
- int32 parentMapId = sMapStore[mapID].ParentMapID;
+ int32 parentMapId = vmapManager->getParentMapId(mapID);
while (!mapFile && parentMapId != -1)
{
mapFileName = Trinity::StringFormat("maps/{:04}_{:02}_{:02}.map", parentMapId, tileY, tileX);
mapFile = fopen(mapFileName.c_str(), "rb");
- parentMapId = sMapStore[parentMapId].ParentMapID;
+ parentMapId = vmapManager->getParentMapId(mapID);
}
}
@@ -100,7 +100,7 @@ namespace MMAP
fheader.versionMagic != MapVersionMagic)
{
fclose(mapFile);
- printf("%s is the wrong version, please extract new .map files\n", mapFileName.c_str());
+ TC_LOG_ERROR("maps.mmapgen", "{} is the wrong version, please extract new .map files", mapFileName);
return false;
}
@@ -123,12 +123,9 @@ namespace MMAP
}
// data used later
- uint8 holes[16][16][8];
- memset(holes, 0, sizeof(holes));
- uint16 liquid_entry[16][16];
- memset(liquid_entry, 0, sizeof(liquid_entry));
- map_liquidHeaderTypeFlags liquid_flags[16][16];
- memset(liquid_flags, 0, sizeof(liquid_flags));
+ uint8 holes[16][16][8] = { };
+ uint16 liquid_entry[16][16] = { };
+ map_liquidHeaderTypeFlags liquid_flags[16][16] = { };
G3D::Array<int> ltriangles;
G3D::Array<int> ttriangles;
@@ -137,17 +134,17 @@ namespace MMAP
{
float heightMultiplier;
float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
- int expected = V9_SIZE_SQ + V8_SIZE_SQ;
+ size_t expected = V9_SIZE_SQ + V8_SIZE_SQ;
if (hheader.flags.HasFlag(map_heightHeaderFlags::HeightAsInt8))
{
uint8 v9[V9_SIZE_SQ];
uint8 v8[V8_SIZE_SQ];
- int count = 0;
+ size_t count = 0;
count += fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
count += fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
if (count != expected)
- printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} height data expected {}, read {}", mapFileName, expected, count);
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
@@ -161,11 +158,11 @@ namespace MMAP
{
uint16 v9[V9_SIZE_SQ];
uint16 v8[V8_SIZE_SQ];
- int count = 0;
+ size_t count = 0;
count += fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
count += fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
if (count != expected)
- printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} height data expected {}, read {}", mapFileName, expected, count);
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
@@ -177,11 +174,11 @@ namespace MMAP
}
else
{
- int count = 0;
+ size_t count = 0;
count += fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
count += fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
if (count != expected)
- printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} height data expected {}, read {}", mapFileName, expected, count);
}
// hole data
@@ -190,7 +187,7 @@ namespace MMAP
memset(holes, 0, fheader.holesSize);
fseek(mapFile, fheader.holesOffset, SEEK_SET);
if (fread(holes, fheader.holesSize, 1, mapFile) != 1)
- printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} holes data expected {}, read {}", mapFileName, 1, 0);
}
int count = meshData.solidVerts.size() / 3;
@@ -234,16 +231,16 @@ namespace MMAP
map_liquidHeader lheader;
fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1)
- printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} liquid header expected {}, read {}", mapFileName, 1, 0);
float* liquid_map = nullptr;
if (!lheader.flags.HasFlag(map_liquidHeaderFlags::NoType))
{
if (fread(liquid_entry, sizeof(liquid_entry), 1, mapFile) != 1)
- printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} liquid id expected {}, read {}", mapFileName, 1, 0);
if (fread(liquid_flags, sizeof(liquid_flags), 1, mapFile) != 1)
- printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} liquid flags expected {}, read {}", mapFileName, 1, 0);
}
else
{
@@ -257,7 +254,7 @@ namespace MMAP
liquid_map = new float [toRead];
if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead)
{
- printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
+ TC_LOG_ERROR("maps.mmapgen", "TerrainBuilder::loadMap: Failed to read {} liquid header expected {}, read {}", mapFileName, toRead, 0);
delete[] liquid_map;
liquid_map = nullptr;
}
@@ -558,7 +555,7 @@ namespace MMAP
}
/**************************************************************************/
- bool TerrainBuilder::isHole(int square, uint8 const holes[16][16][8])
+ bool TerrainBuilder::isHole(int square, uint8 const (&holes)[16][16][8])
{
int row = square / 128;
int col = square % 128;
@@ -582,9 +579,8 @@ namespace MMAP
}
/**************************************************************************/
- bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
+ bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager)
{
- std::unique_ptr<VMAP::VMapManager2> vmapManager = VMapFactory::CreateVMapManager();
VMAP::LoadResult result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
bool retval = false;
@@ -791,7 +787,7 @@ namespace MMAP
}
/**************************************************************************/
- void TerrainBuilder::cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris)
+ void TerrainBuilder::cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris)
{
std::map<int, int> vertMap;
diff --git a/src/tools/mmaps_generator/TerrainBuilder.h b/src/tools/mmaps_generator/TerrainBuilder.h
index 98c59bbb572..fff061d4618 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.h
+++ b/src/tools/mmaps_generator/TerrainBuilder.h
@@ -18,12 +18,16 @@
#ifndef _MMAP_TERRAIN_BUILDER_H
#define _MMAP_TERRAIN_BUILDER_H
-#include "PathCommon.h"
#include "WorldModel.h"
#include <G3D/Array.h>
#include <G3D/Vector3.h>
+namespace VMAP
+{
+class VMapManager2;
+}
+
enum class map_liquidHeaderTypeFlags : uint8;
namespace MMAP
@@ -91,11 +95,10 @@ namespace MMAP
class TerrainBuilder
{
public:
- TerrainBuilder(bool skipLiquid);
- ~TerrainBuilder();
+ explicit TerrainBuilder(bool skipLiquid);
- void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
- bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
+ void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager);
+ bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager);
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, std::vector<OffMeshData> const& offMeshConnections);
bool usesLiquids() const { return !m_skipLiquid; }
@@ -106,20 +109,17 @@ namespace MMAP
static void copyVertices(std::vector<G3D::Vector3> const& source, G3D::Array<float>& dest);
static void copyIndices(std::vector<VMAP::MeshTriangle> const& source, G3D::Array<int>& dest, int offset, bool flip);
static void copyIndices(G3D::Array<int> const& source, G3D::Array<int>& dest, int offset);
- static void cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris);
+ static void cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris);
private:
/// Loads a portion of a map's terrain
- bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion);
+ bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager2* vmapManager, Spot portion);
/// Sets loop variables for selecting only certain parts of a map's terrain
- void getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc);
+ void getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc);
/// Controls whether liquids are loaded
bool m_skipLiquid;
- /// Load the map terrain from file
- bool loadHeightMap(uint32 mapID, uint32 tileX, uint32 tileY, G3D::Array<float> &vertices, G3D::Array<int> &triangles, Spot portion);
-
/// Get the vector coordinate for a specific position
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
@@ -127,17 +127,13 @@ namespace MMAP
void getHeightTriangle(int square, Spot triangle, int* indices, bool liquid = false);
/// Determines if the specific position's triangles should be rendered
- bool isHole(int square, uint8 const holes[16][16][8]);
+ bool isHole(int square, uint8 const (&holes)[16][16][8]);
/// Get the liquid vector coordinate for a specific position
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
/// Get the liquid type for a specific position
map_liquidHeaderTypeFlags getLiquidType(int square, map_liquidHeaderTypeFlags const (&liquid_type)[16][16]);
-
- // hide parameterless and copy constructor
- TerrainBuilder() = delete;
- TerrainBuilder(TerrainBuilder const& tb) = delete;
};
}
diff --git a/src/tools/mmaps_generator/TileBuilder.cpp b/src/tools/mmaps_generator/TileBuilder.cpp
new file mode 100644
index 00000000000..7b0a7bef00f
--- /dev/null
+++ b/src/tools/mmaps_generator/TileBuilder.cpp
@@ -0,0 +1,554 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TileBuilder.h"
+#include "IntermediateValues.h"
+#include "Log.h"
+#include "MMapDefines.h"
+#include "PathCommon.h"
+#include "StringFormat.h"
+#include "VMapManager2.h"
+#include <DetourNavMeshBuilder.h>
+
+namespace
+{
+ struct Tile
+ {
+ Tile() : chf(nullptr), solid(nullptr), cset(nullptr), pmesh(nullptr), dmesh(nullptr) {}
+ ~Tile()
+ {
+ rcFreeCompactHeightfield(chf);
+ rcFreeContourSet(cset);
+ rcFreeHeightField(solid);
+ rcFreePolyMesh(pmesh);
+ rcFreePolyMeshDetail(dmesh);
+ }
+ rcCompactHeightfield* chf;
+ rcHeightfield* solid;
+ rcContourSet* cset;
+ rcPolyMesh* pmesh;
+ rcPolyMeshDetail* dmesh;
+ };
+}
+
+namespace MMAP
+{
+ struct TileConfig
+ {
+ TileConfig(bool bigBaseUnit)
+ {
+ // these are WORLD UNIT based metrics
+ // this are basic unit dimentions
+ // value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc )
+ BASE_UNIT_DIM = bigBaseUnit ? 0.5333333f : 0.2666666f;
+
+ // All are in UNIT metrics!
+ VERTEX_PER_MAP = int(GRID_SIZE / BASE_UNIT_DIM + 0.5f);
+ VERTEX_PER_TILE = bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP
+ TILES_PER_MAP = VERTEX_PER_MAP / VERTEX_PER_TILE;
+ }
+
+ float BASE_UNIT_DIM;
+ int VERTEX_PER_MAP;
+ int VERTEX_PER_TILE;
+ int TILES_PER_MAP;
+ };
+
+ TileBuilder::TileBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
+ bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector<OffMeshData> const* offMeshConnections) :
+ m_maxWalkableAngle(maxWalkableAngle),
+ m_maxWalkableAngleNotSteep(maxWalkableAngleNotSteep),
+ m_bigBaseUnit(bigBaseUnit),
+ m_debugOutput(debugOutput),
+ m_terrainBuilder(skipLiquid),
+ m_rcContext(false),
+ m_offMeshConnections(offMeshConnections)
+ {
+ }
+
+ TileBuilder::~TileBuilder() = default;
+
+ /**************************************************************************/
+ void TileBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
+ {
+ if (shouldSkipTile(mapID, tileX, tileY))
+ {
+ OnTileDone();
+ return;
+ }
+
+ TC_LOG_INFO("maps.mmapgen", "{} [Map {:04}] Building tile [{:02},{:02}]", GetProgressText(), mapID, tileX, tileY);
+
+ MeshData meshData;
+
+ std::unique_ptr<VMAP::VMapManager2> vmapManager = VMapFactory::CreateVMapManager(mapID);
+
+ // get heightmap data
+ m_terrainBuilder.loadMap(mapID, tileX, tileY, meshData, vmapManager.get());
+
+ // get model data
+ m_terrainBuilder.loadVMap(mapID, tileY, tileX, meshData, vmapManager.get());
+
+ // if there is no data, give up now
+ if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
+ {
+ OnTileDone();
+ return;
+ }
+
+ // remove unused vertices
+ TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
+ TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);
+
+ // gather all mesh data for final data check, and bounds calculation
+ G3D::Array<float> allVerts;
+ allVerts.append(meshData.liquidVerts);
+ allVerts.append(meshData.solidVerts);
+
+ if (!allVerts.size())
+ {
+ OnTileDone();
+ return;
+ }
+
+ // get bounds of current tile
+ float bmin[3], bmax[3];
+ getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
+
+ if (m_offMeshConnections)
+ m_terrainBuilder.loadOffMeshConnections(mapID, tileX, tileY, meshData, *m_offMeshConnections);
+
+ // build navmesh tile
+ buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
+
+ OnTileDone();
+ }
+
+ /**************************************************************************/
+ void TileBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
+ MeshData& meshData, float (&bmin)[3], float (&bmax)[3],
+ dtNavMesh* navMesh)
+ {
+ // console output
+ std::string tileString = Trinity::StringFormat("[Map {:04}] [{:02},{:02}]:", mapID, tileX, tileY);
+ TC_LOG_INFO("maps.mmapgen", "{} Building movemap tile...", tileString);
+
+ IntermediateValues iv;
+
+ float* tVerts = meshData.solidVerts.getCArray();
+ int tVertCount = meshData.solidVerts.size() / 3;
+ int* tTris = meshData.solidTris.getCArray();
+ int tTriCount = meshData.solidTris.size() / 3;
+
+ float* lVerts = meshData.liquidVerts.getCArray();
+ int lVertCount = meshData.liquidVerts.size() / 3;
+ int* lTris = meshData.liquidTris.getCArray();
+ int lTriCount = meshData.liquidTris.size() / 3;
+ uint8* lTriFlags = meshData.liquidType.getCArray();
+
+ const TileConfig tileConfig = TileConfig(m_bigBaseUnit);
+ int TILES_PER_MAP = tileConfig.TILES_PER_MAP;
+ float BASE_UNIT_DIM = tileConfig.BASE_UNIT_DIM;
+ rcConfig config = GetMapSpecificConfig(mapID, bmin, bmax, tileConfig);
+
+ // this sets the dimensions of the heightfield - should maybe happen before border padding
+ rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
+
+ // allocate subregions : tiles
+ Tile* tiles = new Tile[TILES_PER_MAP * TILES_PER_MAP];
+
+ // Initialize per tile config.
+ rcConfig tileCfg = config;
+ tileCfg.width = config.tileSize + config.borderSize * 2;
+ tileCfg.height = config.tileSize + config.borderSize * 2;
+
+ // merge per tile poly and detail meshes
+ rcPolyMesh** pmmerge = new rcPolyMesh * [TILES_PER_MAP * TILES_PER_MAP];
+ rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail * [TILES_PER_MAP * TILES_PER_MAP];
+ int nmerge = 0;
+ // build all tiles
+ for (int y = 0; y < TILES_PER_MAP; ++y)
+ {
+ for (int x = 0; x < TILES_PER_MAP; ++x)
+ {
+ Tile& tile = tiles[x + y * TILES_PER_MAP];
+
+ // Calculate the per tile bounding box.
+ tileCfg.bmin[0] = config.bmin[0] + x * float(config.tileSize * config.cs);
+ tileCfg.bmin[2] = config.bmin[2] + y * float(config.tileSize * config.cs);
+ tileCfg.bmax[0] = config.bmin[0] + (x + 1) * float(config.tileSize * config.cs);
+ tileCfg.bmax[2] = config.bmin[2] + (y + 1) * float(config.tileSize * config.cs);
+
+ tileCfg.bmin[0] -= tileCfg.borderSize * tileCfg.cs;
+ tileCfg.bmin[2] -= tileCfg.borderSize * tileCfg.cs;
+ tileCfg.bmax[0] += tileCfg.borderSize * tileCfg.cs;
+ tileCfg.bmax[2] += tileCfg.borderSize * tileCfg.cs;
+
+ // build heightfield
+ tile.solid = rcAllocHeightfield();
+ if (!tile.solid || !rcCreateHeightfield(&m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building heightfield!", tileString);
+ continue;
+ }
+
+ // mark all walkable tiles, both liquids and solids
+
+ /* we want to have triangles with slope less than walkableSlopeAngleNotSteep (<= 55) to have NAV_AREA_GROUND
+ * and with slope between walkableSlopeAngleNotSteep and walkableSlopeAngle (55 < .. <= 70) to have NAV_AREA_GROUND_STEEP.
+ * we achieve this using recast API: memset everything to NAV_AREA_GROUND_STEEP, call rcClearUnwalkableTriangles with 70 so
+ * any area above that will get RC_NULL_AREA (unwalkable), then call rcMarkWalkableTriangles with 55 to set NAV_AREA_GROUND
+ * on anything below 55 . Players and idle Creatures can use NAV_AREA_GROUND, while Creatures in combat can use NAV_AREA_GROUND_STEEP.
+ */
+ unsigned char* triFlags = new unsigned char[tTriCount];
+ memset(triFlags, NAV_AREA_GROUND_STEEP, tTriCount * sizeof(unsigned char));
+ rcClearUnwalkableTriangles(&m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
+ rcMarkWalkableTriangles(&m_rcContext, tileCfg.walkableSlopeAngleNotSteep, tVerts, tVertCount, tTris, tTriCount, triFlags, NAV_AREA_GROUND);
+ rcRasterizeTriangles(&m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
+ delete[] triFlags;
+
+ rcFilterLowHangingWalkableObstacles(&m_rcContext, config.walkableClimb, *tile.solid);
+ rcFilterLedgeSpans(&m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
+ rcFilterWalkableLowHeightSpans(&m_rcContext, tileCfg.walkableHeight, *tile.solid);
+
+ // add liquid triangles
+ rcRasterizeTriangles(&m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
+
+ // compact heightfield spans
+ tile.chf = rcAllocCompactHeightfield();
+ if (!tile.chf || !rcBuildCompactHeightfield(&m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed compacting heightfield!", tileString);
+ continue;
+ }
+
+ // build polymesh intermediates
+ if (!rcErodeWalkableArea(&m_rcContext, config.walkableRadius, *tile.chf))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed eroding area!", tileString);
+ continue;
+ }
+
+ if (!rcMedianFilterWalkableArea(&m_rcContext, *tile.chf))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed filtering area!", tileString);
+ continue;
+ }
+
+ if (!rcBuildDistanceField(&m_rcContext, *tile.chf))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building distance field!", tileString);
+ continue;
+ }
+
+ if (!rcBuildRegions(&m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building regions!", tileString);
+ continue;
+ }
+
+ tile.cset = rcAllocContourSet();
+ if (!tile.cset || !rcBuildContours(&m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building contours!", tileString);
+ continue;
+ }
+
+ // build polymesh
+ tile.pmesh = rcAllocPolyMesh();
+ if (!tile.pmesh || !rcBuildPolyMesh(&m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building polymesh!", tileString);
+ continue;
+ }
+
+ tile.dmesh = rcAllocPolyMeshDetail();
+ if (!tile.dmesh || !rcBuildPolyMeshDetail(&m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building polymesh detail!", tileString);
+ continue;
+ }
+
+ // free those up
+ // we may want to keep them in the future for debug
+ // but right now, we don't have the code to merge them
+ rcFreeHeightField(tile.solid);
+ tile.solid = nullptr;
+ rcFreeCompactHeightfield(tile.chf);
+ tile.chf = nullptr;
+ rcFreeContourSet(tile.cset);
+ tile.cset = nullptr;
+
+ pmmerge[nmerge] = tile.pmesh;
+ dmmerge[nmerge] = tile.dmesh;
+ nmerge++;
+ }
+ }
+
+ iv.polyMesh = rcAllocPolyMesh();
+ if (!iv.polyMesh)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} alloc iv.polyMesh FAILED!", tileString);
+ delete[] pmmerge;
+ delete[] dmmerge;
+ delete[] tiles;
+ return;
+ }
+ rcMergePolyMeshes(&m_rcContext, pmmerge, nmerge, *iv.polyMesh);
+
+ iv.polyMeshDetail = rcAllocPolyMeshDetail();
+ if (!iv.polyMeshDetail)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} alloc m_dmesh FAILED!", tileString);
+ delete[] pmmerge;
+ delete[] dmmerge;
+ delete[] tiles;
+ return;
+ }
+ rcMergePolyMeshDetails(&m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail);
+
+ // free things up
+ delete[] pmmerge;
+ delete[] dmmerge;
+ delete[] tiles;
+
+ // set polygons as walkable
+ // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
+ for (int i = 0; i < iv.polyMesh->npolys; ++i)
+ {
+ if (uint8 area = iv.polyMesh->areas[i] & NAV_AREA_ALL_MASK)
+ {
+ if (area >= NAV_AREA_MIN_VALUE)
+ iv.polyMesh->flags[i] = 1 << (NAV_AREA_MAX_VALUE - area);
+ else
+ iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future
+ }
+ }
+
+ // setup mesh parameters
+ dtNavMeshCreateParams params = {};
+ params.verts = iv.polyMesh->verts;
+ params.vertCount = iv.polyMesh->nverts;
+ params.polys = iv.polyMesh->polys;
+ params.polyAreas = iv.polyMesh->areas;
+ params.polyFlags = iv.polyMesh->flags;
+ params.polyCount = iv.polyMesh->npolys;
+ params.nvp = iv.polyMesh->nvp;
+ params.detailMeshes = iv.polyMeshDetail->meshes;
+ params.detailVerts = iv.polyMeshDetail->verts;
+ params.detailVertsCount = iv.polyMeshDetail->nverts;
+ params.detailTris = iv.polyMeshDetail->tris;
+ params.detailTriCount = iv.polyMeshDetail->ntris;
+
+ params.offMeshConVerts = meshData.offMeshConnections.getCArray();
+ params.offMeshConCount = meshData.offMeshConnections.size() / 6;
+ params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
+ params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
+ params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
+ params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
+
+ params.walkableHeight = BASE_UNIT_DIM * config.walkableHeight; // agent height
+ params.walkableRadius = BASE_UNIT_DIM * config.walkableRadius; // agent radius
+ params.walkableClimb = BASE_UNIT_DIM * config.walkableClimb; // keep less that walkableHeight (aka agent height)!
+ params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) / GRID_SIZE;
+ params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) / GRID_SIZE;
+ rcVcopy(params.bmin, bmin);
+ rcVcopy(params.bmax, bmax);
+ params.cs = config.cs;
+ params.ch = config.ch;
+ params.tileLayer = 0;
+ params.buildBvTree = true;
+
+ // will hold final navmesh
+ unsigned char* navData = nullptr;
+ int navDataSize = 0;
+
+ do
+ {
+ // these values are checked within dtCreateNavMeshData - handle them here
+ // so we have a clear error message
+ if (params.nvp > DT_VERTS_PER_POLYGON)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Invalid verts-per-polygon value!", tileString);
+ break;
+ }
+ if (params.vertCount >= 0xffff)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Too many vertices!", tileString);
+ break;
+ }
+ if (!params.vertCount || !params.verts)
+ {
+ // occurs mostly when adjacent tiles have models
+ // loaded but those models don't span into this tile
+
+ // message is an annoyance
+ //TC_LOG_ERROR("maps.mmapgen", "{} No vertices to build tile!", tileString);
+ break;
+ }
+ if (!params.polyCount || !params.polys)
+ {
+ // we have flat tiles with no actual geometry - don't build those, its useless
+ // keep in mind that we do output those into debug info
+ TC_LOG_ERROR("maps.mmapgen", "{} No polygons to build on tile!", tileString);
+ break;
+ }
+ if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} No detail mesh to build tile!", tileString);
+ break;
+ }
+
+ TC_LOG_DEBUG("maps.mmapgen", "{} Building navmesh tile...", tileString);
+ if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed building navmesh tile!", tileString);
+ break;
+ }
+
+ dtTileRef tileRef = 0;
+ TC_LOG_DEBUG("maps.mmapgen", "{} Adding tile to navmesh...", tileString);
+ // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
+ // is removed via removeTile()
+ dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
+ if (!tileRef || !dtStatusSucceed(dtResult))
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{} Failed adding tile to navmesh!", tileString);
+ break;
+ }
+
+ // file output
+ std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileY, tileX);
+ FILE* file = fopen(fileName.c_str(), "wb");
+ if (!file)
+ {
+ TC_LOG_ERROR("maps.mmapgen", "{}: [Map {:04}] Failed to open {} for writing!", strerror(errno), mapID, fileName);
+ navMesh->removeTile(tileRef, nullptr, nullptr);
+ break;
+ }
+
+ TC_LOG_DEBUG("maps.mmapgen", "{} Writing to file...", tileString);
+
+ // write header
+ MmapTileHeader header;
+ header.usesLiquids = m_terrainBuilder.usesLiquids();
+ header.size = uint32(navDataSize);
+ fwrite(&header, sizeof(MmapTileHeader), 1, file);
+
+ // write data
+ fwrite(navData, sizeof(unsigned char), navDataSize, file);
+ fclose(file);
+
+ // now that tile is written to disk, we can unload it
+ navMesh->removeTile(tileRef, nullptr, nullptr);
+ } while (false);
+
+ if (m_debugOutput)
+ {
+ // restore padding so that the debug visualization is correct
+ for (int i = 0; i < iv.polyMesh->nverts; ++i)
+ {
+ unsigned short* v = &iv.polyMesh->verts[i * 3];
+ v[0] += (unsigned short)config.borderSize;
+ v[2] += (unsigned short)config.borderSize;
+ }
+
+ iv.generateObjFile(mapID, tileX, tileY, meshData);
+ iv.writeIV(mapID, tileX, tileY);
+ }
+ }
+
+ /**************************************************************************/
+ void TileBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
+ {
+ // this is for elevation
+ if (verts && vertCount)
+ rcCalcBounds(verts, vertCount, bmin, bmax);
+ else
+ {
+ bmin[1] = FLT_MIN;
+ bmax[1] = FLT_MAX;
+ }
+
+ // this is for width and depth
+ bmax[0] = (32 - int(tileX)) * GRID_SIZE;
+ bmax[2] = (32 - int(tileY)) * GRID_SIZE;
+ bmin[0] = bmax[0] - GRID_SIZE;
+ bmin[2] = bmax[2] - GRID_SIZE;
+ }
+
+ /**************************************************************************/
+ bool TileBuilder::shouldSkipTile(uint32 /*mapID*/, uint32 /*tileX*/, uint32 /*tileY*/) const
+ {
+ if (m_debugOutput)
+ return false;
+
+ return true;
+ }
+
+ rcConfig TileBuilder::GetMapSpecificConfig(uint32 mapID, float const (&bmin)[3], float const (&bmax)[3], TileConfig const& tileConfig) const
+ {
+ rcConfig config { };
+
+ rcVcopy(config.bmin, bmin);
+ rcVcopy(config.bmax, bmax);
+
+ config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
+ config.cs = tileConfig.BASE_UNIT_DIM;
+ config.ch = tileConfig.BASE_UNIT_DIM;
+ // Keeping these 2 slope angles the same reduces a lot the number of polys.
+ // 55 should be the minimum, maybe 70 is ok (keep in mind blink uses mmaps), 85 is too much for players
+ config.walkableSlopeAngle = m_maxWalkableAngle.value_or(55.0f);
+ config.walkableSlopeAngleNotSteep = m_maxWalkableAngleNotSteep.value_or(55.0f);
+ config.tileSize = tileConfig.VERTEX_PER_TILE;
+ config.walkableRadius = m_bigBaseUnit ? 1 : 2;
+ config.borderSize = config.walkableRadius + 3;
+ config.maxEdgeLen = tileConfig.VERTEX_PER_TILE + 1; // anything bigger than tileSize
+ config.walkableHeight = m_bigBaseUnit ? 3 : 6;
+ // a value >= 3|6 allows npcs to walk over some fences
+ // a value >= 4|8 allows npcs to walk over all fences
+ config.walkableClimb = m_bigBaseUnit ? 3 : 6;
+ config.minRegionArea = rcSqr(60);
+ config.mergeRegionArea = rcSqr(50);
+ config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
+ config.detailSampleDist = config.cs * 16;
+ config.detailSampleMaxError = config.ch * 1;
+
+ switch (mapID)
+ {
+ // Blade's Edge Arena
+ case 562:
+ // This allows to walk on the ropes to the pillars
+ config.walkableRadius = 0;
+ break;
+ // Blackfathom Deeps
+ case 48:
+ // Reduce the chance to have underground levels
+ config.ch *= 2;
+ break;
+ default:
+ break;
+ }
+
+ return config;
+ }
+
+ std::string TileBuilder::GetProgressText() const
+ {
+ return "";
+ }
+}
diff --git a/src/tools/mmaps_generator/TileBuilder.h b/src/tools/mmaps_generator/TileBuilder.h
new file mode 100644
index 00000000000..4ebbe38a037
--- /dev/null
+++ b/src/tools/mmaps_generator/TileBuilder.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_TILE_BUILDER_H
+#define TRINITYCORE_TILE_BUILDER_H
+
+#include "Define.h"
+#include "StringFormat.h"
+#include "TerrainBuilder.h"
+#include <DetourNavMesh.h>
+#include <Recast.h>
+
+namespace MMAP
+{
+struct TileConfig;
+
+class TileBuilder
+{
+public:
+ TileBuilder(Optional<float> maxWalkableAngle,
+ Optional<float> maxWalkableAngleNotSteep,
+ bool skipLiquid,
+ bool bigBaseUnit,
+ bool debugOutput,
+ std::vector<OffMeshData> const* offMeshConnections);
+
+ TileBuilder(TileBuilder const&) = delete;
+ TileBuilder(TileBuilder&&) = delete;
+
+ TileBuilder& operator=(TileBuilder const&) = delete;
+ TileBuilder& operator=(TileBuilder&&) = delete;
+
+ virtual ~TileBuilder();
+
+ void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh);
+ // move map building
+ void buildMoveMapTile(uint32 mapID,
+ uint32 tileX,
+ uint32 tileY,
+ MeshData& meshData,
+ float (&bmin)[3],
+ float (&bmax)[3],
+ dtNavMesh* navMesh);
+
+ virtual bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const;
+
+ static void getTileBounds(uint32 tileX, uint32 tileY,
+ float* verts, int vertCount,
+ float* bmin, float* bmax);
+
+ rcConfig GetMapSpecificConfig(uint32 mapID, float const (&bmin)[3], float const (&bmax)[3], TileConfig const& tileConfig) const;
+
+ virtual std::string GetProgressText() const;
+
+ virtual void OnTileDone() { }
+
+private:
+ Optional<float> m_maxWalkableAngle;
+ Optional<float> m_maxWalkableAngleNotSteep;
+ bool m_bigBaseUnit;
+ bool m_debugOutput;
+
+ TerrainBuilder m_terrainBuilder;
+ // build performance - not really used for now
+ rcContext m_rcContext;
+ std::vector<OffMeshData> const* m_offMeshConnections;
+};
+}
+
+#endif // TRINITYCORE_TILE_BUILDER_H