diff options
Diffstat (limited to 'src')
42 files changed, 480 insertions, 473 deletions
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 1ab9ae6eb62..4a9d3ce7faf 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -222,12 +222,25 @@ void AuthSocket::OnClose(void) // Read the packet from the client void AuthSocket::OnRead() { + #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3 + uint32 challengesInARow = 0; uint8 _cmd; while (1) { if (!socket().recv_soft((char *)&_cmd, 1)) return; + if (_cmd == AUTH_LOGON_CHALLENGE) + { + ++challengesInARow; + if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) + { + TC_LOG_WARN(LOG_FILTER_AUTHSERVER, "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, socket().getRemoteAddress().c_str()); + socket().shutdown(); + return; + } + } + size_t i; // Circle through known commands and call the correct command handler diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index a56d0f94f2d..57fd7ea2d73 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -206,7 +206,7 @@ void SmartAI::EndPath(bool fail) mLastWP = NULL; if (mCanRepeatPath) - StartPath(mRun, GetScript()->GetPathId(), mCanRepeatPath); + StartPath(mRun, GetScript()->GetPathId(), true); else GetScript()->SetPathId(0); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index ba1e59e0cc9..3823f7ba287 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -942,7 +942,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; instance->SetData64(e.action.setInstanceData64.field, targets->front()->GetGUID()); - TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: "UI64FMTD, + TC_LOG_DEBUG(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: " UI64FMTD, e.action.setInstanceData64.field, targets->front()->GetGUID()); delete targets; @@ -1585,8 +1585,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; } - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (ObjectList* targets = GetTargets(e, unit)) { for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -2551,7 +2550,7 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* case SMART_TARGET_CLOSEST_ENEMY: { if (me) - if (Unit* target = me->SelectNearestTarget(e.target.closestAttackable.maxDist)) + if (Unit* target = me->SelectNearestTarget(e.target.closestAttackable.maxDist, e.target.closestAttackable.playerOnly)) l->push_back(target); break; @@ -2559,7 +2558,7 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* case SMART_TARGET_CLOSEST_FRIENDLY: { if (me) - if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist)) + if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist, e.target.closestFriendly.playerOnly)) l->push_back(target); break; @@ -3443,13 +3442,13 @@ void SmartScript::DoFindFriendlyMissingBuff(std::list<Creature*>& list, float ra cell.Visit(p, grid_creature_searcher, *me->GetMap(), *me, range); } -Unit* SmartScript::DoFindClosestFriendlyInRange(float range) +Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) { if (!me) return NULL; Unit* unit = NULL; - Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range); + Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range, playerOnly); Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(me, unit, u_check); me->VisitNearbyObject(range, searcher); return unit; @@ -3463,16 +3462,15 @@ void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry) return; for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) { - if (i == mTimedActionList.begin()) - { - i->enableTimed = true;//enable processing only for the first action - } - else i->enableTimed = false; + i->enableTimed = i == mTimedActionList.begin();//enable processing only for the first action - if (e.action.timedActionList.timerType == 1) + if (e.action.timedActionList.timerType == 0) + i->event.type = SMART_EVENT_UPDATE_OOC; + else if (e.action.timedActionList.timerType == 1) i->event.type = SMART_EVENT_UPDATE_IC; else if (e.action.timedActionList.timerType > 1) i->event.type = SMART_EVENT_UPDATE; + InitTimer((*i)); } } diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index b22f2d81b26..b1b9f4d6725 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -89,7 +89,7 @@ class SmartScript Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff); void DoFindFriendlyCC(std::list<Creature*>& _list, float range); void DoFindFriendlyMissingBuff(std::list<Creature*>& list, float range, uint32 spellid); - Unit* DoFindClosestFriendlyInRange(float range); + Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly); void StoreTargetList(ObjectList* targets, uint32 id) { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 90819e7a2c3..56fa7ed1275 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1021,8 +1021,8 @@ enum SMARTAI_TARGETS SMART_TARGET_ACTION_INVOKER_VEHICLE = 22, // Unit's vehicle who caused this Event to occur SMART_TARGET_OWNER_OR_SUMMONER = 23, // Unit's owner or summoner SMART_TARGET_THREAT_LIST = 24, // All units on creature's threat list - SMART_TARGET_CLOSEST_ENEMY = 25, // maxDist - SMART_TARGET_CLOSEST_FRIENDLY = 26, // maxDist + SMART_TARGET_CLOSEST_ENEMY = 25, // maxDist, playerOnly + SMART_TARGET_CLOSEST_FRIENDLY = 26, // maxDist, playerOnly SMART_TARGET_END = 27 }; @@ -1109,11 +1109,13 @@ struct SmartTarget struct { uint32 maxDist; + uint32 playerOnly; } closestAttackable; struct { uint32 maxDist; + uint32 playerOnly; } closestFriendly; struct diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index aaa630ce4b8..a5c059b30df 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -344,7 +344,7 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, st Player* player = m_session->GetPlayer(); if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity())) { - uint64 guid = player->GetSelection(); + uint64 guid = player->GetTarget(); uint32 areaId = player->GetAreaId(); std::string areaName = "Unknown"; std::string zoneName = "Unknown"; @@ -713,12 +713,10 @@ Player* ChatHandler::getSelectedPlayer() if (!m_session) return NULL; - uint64 guid = m_session->GetPlayer()->GetSelection(); + if (Player* selected = m_session->GetPlayer()->GetSelectedPlayer()) + return selected; - if (guid == 0) - return m_session->GetPlayer(); - - return ObjectAccessor::FindPlayer(guid); + return m_session->GetPlayer(); } Unit* ChatHandler::getSelectedUnit() @@ -726,12 +724,10 @@ Unit* ChatHandler::getSelectedUnit() if (!m_session) return NULL; - uint64 guid = m_session->GetPlayer()->GetSelection(); + if (Unit* selected = m_session->GetPlayer()->GetSelectedUnit()) + return selected; - if (guid == 0) - return m_session->GetPlayer(); - - return ObjectAccessor::GetUnit(*m_session->GetPlayer(), guid); + return m_session->GetPlayer(); } WorldObject* ChatHandler::getSelectedObject() @@ -739,7 +735,7 @@ WorldObject* ChatHandler::getSelectedObject() if (!m_session) return NULL; - uint64 guid = m_session->GetPlayer()->GetSelection(); + uint64 guid = m_session->GetPlayer()->GetTarget(); if (guid == 0) return GetNearbyGameObject(); @@ -752,7 +748,7 @@ Creature* ChatHandler::getSelectedCreature() if (!m_session) return NULL; - return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(), m_session->GetPlayer()->GetSelection()); + return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(), m_session->GetPlayer()->GetTarget()); } char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 169d5feae03..4efd78d5932 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -165,6 +165,7 @@ m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL) ResetLootMode(); // restore default loot mode TriggerJustRespawned = false; m_isTempWorldObject = false; + _focusSpell = NULL; } Creature::~Creature() @@ -1709,7 +1710,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) } // select nearest hostile unit within the given distance (regardless of threat list). -Unit* Creature::SelectNearestTarget(float dist) const +Unit* Creature::SelectNearestTarget(float dist, bool playerOnly /* = false */) const { CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY())); Cell cell(p); @@ -1721,7 +1722,7 @@ Unit* Creature::SelectNearestTarget(float dist) const if (dist == 0.0f) dist = MAX_VISIBILITY_DISTANCE; - Trinity::NearestHostileUnitCheck u_check(this, dist); + Trinity::NearestHostileUnitCheck u_check(this, dist, playerOnly); Trinity::UnitLastSearcher<Trinity::NearestHostileUnitCheck> searcher(this, target, u_check); TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); @@ -2640,3 +2641,41 @@ void Creature::SetDisplayId(uint32 modelId) SetFloatValue(UNIT_FIELD_COMBATREACH, minfo->combat_reach * GetObjectScale()); } } + +void Creature::SetTarget(uint64 guid) +{ + if (!_focusSpell) + SetUInt64Value(UNIT_FIELD_TARGET, guid); +} + +void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) +{ + // already focused + if (_focusSpell) + return; + + _focusSpell = focusSpell; + SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); + if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST) + AddUnitState(UNIT_STATE_ROTATING); + + // Set serverside orientation if needed (needs to be after attribute check) + SetInFront(target); +} + +void Creature::ReleaseFocus(Spell const* focusSpell) +{ + // focused to something else + if (focusSpell != _focusSpell) + return; + + _focusSpell = NULL; + if (Unit* victim = GetVictim()) + SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); + else + SetUInt64Value(UNIT_FIELD_TARGET, 0); + + if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST) + ClearUnitState(UNIT_STATE_ROTATING); +} + diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index b720a063f2d..3a07d9c101b 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -609,7 +609,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void SendAIReaction(AiReaction reactionType); - Unit* SelectNearestTarget(float dist = 0) const; + Unit* SelectNearestTarget(float dist = 0, bool playerOnly = false) const; Unit* SelectNearestTargetInAttackDistance(float dist = 0) const; Player* SelectNearestPlayer(float distance = 0) const; Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false) const; @@ -703,6 +703,11 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool m_isTempWorldObject; //true when possessed + // Handling caster facing during spellcast + void SetTarget(uint64 guid); + void FocusTarget(Spell const* focusSpell, WorldObject const* target); + void ReleaseFocus(Spell const* focusSpell); + protected: bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData* data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); @@ -762,6 +767,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature //Formation var CreatureGroup* m_formation; bool TriggerJustRespawned; + + Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing }; class AssistDelayEvent : public BasicEvent diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 15e7eb436e1..eef416b339d 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1508,7 +1508,7 @@ void GameObject::Use(Unit* user) Player* player = user->ToPlayer(); - Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetSelection()); + Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetTarget()); // accept only use by player from same raid as caster, except caster itself if (!targetPlayer || targetPlayer == player || !targetPlayer->IsInSameRaidWith(player)) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 5a787f910b8..9d77e144c0b 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -91,7 +91,7 @@ WorldObject::~WorldObject() { if (GetTypeId() == TYPEID_CORPSE) { - TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object Corpse guid="UI64FMTD", type=%d, entry=%u deleted but still in map!!", + TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object Corpse guid=" UI64FMTD ", type=%d, entry=%u deleted but still in map!!", GetGUID(), ((Corpse*)this)->GetType(), GetEntry()); ASSERT(false); } @@ -103,7 +103,7 @@ Object::~Object() { if (IsInWorld()) { - TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry()); + TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object - guid=" UI64FMTD ", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry()); if (isType(TYPEMASK_ITEM)) TC_LOG_FATAL(LOG_FILTER_GENERAL, "Item slot %u", ((Item*)this)->GetSlot()); ASSERT(false); @@ -112,7 +112,7 @@ Object::~Object() if (m_objectUpdated) { - TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in update list!!", GetGUID(), GetTypeId(), GetEntry()); + TC_LOG_FATAL(LOG_FILTER_GENERAL, "Object::~Object - guid=" UI64FMTD ", typeid=%d, entry=%u deleted but still in update list!!", GetGUID(), GetTypeId(), GetEntry()); ASSERT(false); sObjectAccessor->RemoveUpdateObject(this); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8217682f103..9ada25b1c81 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -673,7 +673,6 @@ Player::Player(WorldSession* session): Unit(true) if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) SetAcceptWhispers(true); - m_curSelection = 0; m_lootGuid = 0; m_comboTarget = 0; @@ -20455,7 +20454,7 @@ void Player::PossessSpellInitialize() if (!charmInfo) { - TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player::PossessSpellInitialize(): charm ("UI64FMTD") has no charminfo!", charm->GetGUID()); + TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player::PossessSpellInitialize(): charm (" UI64FMTD ") has no charminfo!", charm->GetGUID()); return; } @@ -20567,7 +20566,7 @@ void Player::CharmSpellInitialize() CharmInfo* charmInfo = charm->GetCharmInfo(); if (!charmInfo) { - TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player::CharmSpellInitialize(): the player's charm ("UI64FMTD") has no charminfo!", charm->GetGUID()); + TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player::CharmSpellInitialize(): the player's charm (" UI64FMTD ") has no charminfo!", charm->GetGUID()); return; } @@ -22397,15 +22396,15 @@ bool Player::IsQuestRewarded(uint32 quest_id) const Unit* Player::GetSelectedUnit() const { - if (m_curSelection) - return ObjectAccessor::GetUnit(*this, m_curSelection); + if (uint64 selectionGUID = GetUInt64Value(UNIT_FIELD_TARGET)) + return ObjectAccessor::GetUnit(*this, selectionGUID); return NULL; } Player* Player::GetSelectedPlayer() const { - if (m_curSelection) - return ObjectAccessor::GetPlayer(*this, m_curSelection); + if (uint64 selectionGUID = GetUInt64Value(UNIT_FIELD_TARGET)) + return ObjectAccessor::GetPlayer(*this, selectionGUID); return NULL; } @@ -25416,7 +25415,7 @@ void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset) if (!found) // something wrong... { - TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player %s tried to save equipment set "UI64FMTD" (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index); + TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player %s tried to save equipment set " UI64FMTD " (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index); return; } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index bac794422be..fee542a752e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1506,10 +1506,11 @@ class Player : public Unit, public GridObject<Player> size_t GetRewardedQuestCount() const { return m_RewardedQuests.size(); } bool IsQuestRewarded(uint32 quest_id) const; - uint64 GetSelection() const { return m_curSelection; } Unit* GetSelectedUnit() const; Player* GetSelectedPlayer() const; - void SetSelection(uint64 guid) { m_curSelection = guid; SetUInt64Value(UNIT_FIELD_TARGET, guid); } + + void SetTarget(uint64 /*guid*/) OVERRIDE { } /// Used for serverside target changes, does not apply to players + void SetSelection(uint64 guid) { SetUInt64Value(UNIT_FIELD_TARGET, guid); } uint8 GetComboPoints() const { return m_comboPoints; } uint64 GetComboTarget() const { return m_comboTarget; } @@ -2424,7 +2425,6 @@ class Player : public Unit, public GridObject<Player> bool m_itemUpdateQueueBlocked; uint32 m_ExtraFlags; - uint64 m_curSelection; uint64 m_comboTarget; int8 m_comboPoints; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2a2a18eb609..0617dec179d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -259,7 +259,6 @@ Unit::Unit(bool isWorldObject) : m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); - _focusSpell = NULL; _lastLiquid = NULL; _isWalkingBeforeCharm = false; } @@ -568,6 +567,9 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (IsAIEnabled) GetAI()->DamageDealt(victim, damage, damagetype); + // Hook for OnDamage Event + sScriptMgr->OnDamage(this, victim, damage); + if (victim->GetTypeId() == TYPEID_PLAYER && this != victim) { // Signal to pets that their owner was attacked @@ -5249,18 +5251,19 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // cast 45429 Arcane Bolt if Exalted by Scryers case 45481: { - if (GetTypeId() != TYPEID_PLAYER) + Player* player = ToPlayer(); + if (!player) return false; // Get Aldor reputation rank - if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) + if (player->GetReputationRank(932) == REP_EXALTED) { target = this; triggered_spell_id = 45479; break; } // Get Scryers reputation rank - if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) + if (player->GetReputationRank(934) == REP_EXALTED) { // triggered at positive/self casts also, current attack target used then if (target && IsFriendlyTo(target)) @@ -5268,8 +5271,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = GetVictim(); if (!target) { - uint64 selected_guid = ToPlayer()->GetSelection(); - target = ObjectAccessor::GetUnit(*this, selected_guid); + target = player->GetSelectedUnit(); if (!target) return false; } @@ -9579,6 +9581,9 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth) if (addhealth) gain = victim->ModifyHealth(int32(addhealth)); + // Hook for OnHeal Event + sScriptMgr->OnHeal(this, victim, gain); + Unit* unit = this; if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTotem()) @@ -15872,7 +15877,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) if (GetCharmInfo()) GetCharmInfo()->SetPetNumber(0, true); else - TC_LOG_ERROR(LOG_FILTER_UNITS, "Aura::HandleModCharm: target="UI64FMTD" with typeid=%d has a charm aura but no charm info!", GetGUID(), GetTypeId()); + TC_LOG_ERROR(LOG_FILTER_UNITS, "Aura::HandleModCharm: target=" UI64FMTD " with typeid=%d has a charm aura but no charm info!", GetGUID(), GetTypeId()); } } break; @@ -16895,7 +16900,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT) if (((Minion*)vehicle->GetBase())->GetOwner() == this) - vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(); + vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(1); if (HasUnitTypeMask(UNIT_MASK_ACCESSORY)) { @@ -17176,8 +17181,8 @@ void Unit::StopAttackFaction(uint32 faction_id) void Unit::OutDebugInfo() const { TC_LOG_ERROR(LOG_FILTER_UNITS, "Unit::OutDebugInfo"); - TC_LOG_INFO(LOG_FILTER_UNITS, "GUID "UI64FMTD", entry %u, type %u, name %s", GetGUID(), GetEntry(), (uint32)GetTypeId(), GetName().c_str()); - TC_LOG_INFO(LOG_FILTER_UNITS, "OwnerGUID "UI64FMTD", MinionGUID "UI64FMTD", CharmerGUID "UI64FMTD", CharmedGUID "UI64FMTD, GetOwnerGUID(), GetMinionGUID(), GetCharmerGUID(), GetCharmGUID()); + TC_LOG_INFO(LOG_FILTER_UNITS, "GUID " UI64FMTD ", entry %u, type %u, name %s", GetGUID(), GetEntry(), (uint32)GetTypeId(), GetName().c_str()); + TC_LOG_INFO(LOG_FILTER_UNITS, "OwnerGUID " UI64FMTD ", MinionGUID " UI64FMTD ", CharmerGUID " UI64FMTD ", CharmedGUID "UI64FMTD, GetOwnerGUID(), GetMinionGUID(), GetCharmerGUID(), GetCharmGUID()); TC_LOG_INFO(LOG_FILTER_UNITS, "In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask); if (IsInWorld()) TC_LOG_INFO(LOG_FILTER_UNITS, "Mapid %u", GetMapId()); @@ -17462,43 +17467,6 @@ bool Unit::SetHover(bool enable, bool /*packetOnly = false*/) return true; } -void Unit::SetTarget(uint64 guid) -{ - if (!_focusSpell) - SetUInt64Value(UNIT_FIELD_TARGET, guid); -} - -void Unit::FocusTarget(Spell const* focusSpell, WorldObject const* target) -{ - // already focused - if (_focusSpell) - return; - - _focusSpell = focusSpell; - SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); - if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST) - AddUnitState(UNIT_STATE_ROTATING); - - // Set serverside orientation if needed (needs to be after attribute check) - SetInFront(target); -} - -void Unit::ReleaseFocus(Spell const* focusSpell) -{ - // focused to something else - if (focusSpell != _focusSpell) - return; - - _focusSpell = NULL; - if (Unit* victim = GetVictim()) - SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); - else - SetUInt64Value(UNIT_FIELD_TARGET, 0); - - if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST) - ClearUnitState(UNIT_STATE_ROTATING); -} - void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const { if (!target) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 119a1dd1966..13f8c8e781f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2124,11 +2124,8 @@ class Unit : public WorldObject TempSummon* ToTempSummon() { if (IsSummon()) return reinterpret_cast<TempSummon*>(this); else return NULL; } TempSummon const* ToTempSummon() const { if (IsSummon()) return reinterpret_cast<TempSummon const*>(this); else return NULL; } - void SetTarget(uint64 guid); - - // Handling caster facing during spellcast - void FocusTarget(Spell const* focusSpell, WorldObject const* target); - void ReleaseFocus(Spell const* focusSpell); + uint64 GetTarget() const { return GetUInt64Value(UNIT_FIELD_TARGET); } + virtual void SetTarget(uint64 /*guid*/) = 0; // Movement info Movement::MoveSpline * movespline; @@ -2253,7 +2250,6 @@ class Unit : public WorldObject bool m_cleanupDone; // lock made to not add stuff after cleanup before delete bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world - Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing bool _isWalkingBeforeCharm; // Are we walking before we were charmed? time_t _lastDamagedTime; // Part of Evade mechanics diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 637e0792a74..d0df63155b2 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -871,10 +871,10 @@ namespace Trinity class AnyFriendlyUnitInObjectRangeCheck { public: - AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool playerOnly = false) : i_obj(obj), i_funit(funit), i_range(range), i_playerOnly(playerOnly) {} bool operator()(Unit* u) { - if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u)) + if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u) && (!i_playerOnly || u->GetTypeId() == TYPEID_PLAYER)) return true; else return false; @@ -883,6 +883,7 @@ namespace Trinity WorldObject const* i_obj; Unit const* i_funit; float i_range; + bool i_playerOnly; }; class AnyGroupedUnitInObjectRangeCheck @@ -1035,7 +1036,7 @@ namespace Trinity class NearestHostileUnitCheck { public: - explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0) : me(creature) + explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0, bool playerOnly = false) : me(creature), i_playerOnly(playerOnly) { m_range = (dist == 0 ? 9999 : dist); } @@ -1047,6 +1048,9 @@ namespace Trinity if (!me->IsValidAttackTarget(u)) return false; + if (i_playerOnly && u->GetTypeId() != TYPEID_PLAYER) + return false; + m_range = me->GetDistance(u); // use found unit range as new range limit for next check return true; } @@ -1054,6 +1058,7 @@ namespace Trinity private: Creature const* me; float m_range; + bool i_playerOnly; NearestHostileUnitCheck(NearestHostileUnitCheck const&); }; diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index b47e085ab6c..c1756311bc1 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -485,7 +485,7 @@ void WorldSession::HandleCalendarEventRsvp(WorldPacket& recvData) uint32 status; recvData >> eventId >> inviteId >> status; - TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "CMSG_CALENDAR_EVENT_RSVP [" UI64FMTD"] EventId [" + TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "CMSG_CALENDAR_EVENT_RSVP [" UI64FMTD "] EventId [" UI64FMTD "], InviteId [" UI64FMTD "], status %u", guid, eventId, inviteId, status); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index f65641eaa76..71453581ed0 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1167,8 +1167,6 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_INSPECT"); - _player->SetSelection(guid); - Player* player = ObjectAccessor::FindPlayer(guid); if (!player) { diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 5a94d5b391b..4638e05ee3d 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -267,7 +267,6 @@ void WorldSession::HandleNpcTextQueryOpcode(WorldPacket& recvData) TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID); recvData >> guid; - GetPlayer()->SetSelection(guid); GossipText const* pGossip = sObjectMgr->GetGossipText(textID); diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp index c44d8a2d38e..b099ba96060 100644 --- a/src/server/game/Handlers/VehicleHandler.cpp +++ b/src/server/game/Handlers/VehicleHandler.cpp @@ -206,7 +206,7 @@ void WorldSession::HandleEjectPassenger(WorldPacket &data) TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "Player %u attempted to eject creature GUID %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); } else - TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "HandleEjectPassenger: Player %u tried to eject invalid GUID "UI64FMTD, GetPlayer()->GetGUIDLow(), guid); + TC_LOG_ERROR(LOG_FILTER_NETWORKIO, "HandleEjectPassenger: Player %u tried to eject invalid GUID " UI64FMTD, GetPlayer()->GetGUIDLow(), guid); } void WorldSession::HandleRequestVehicleExit(WorldPacket& /*recvData*/) diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 6370eda6568..d7ffb70ccfa 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -336,7 +336,7 @@ void InstanceSaveManager::LoadResetTimes() InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance); if (itr != instResetTime.end() && itr->second.second != resettime) { - CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", uint64(resettime), instance); + CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '" UI64FMTD "' WHERE id = '%u'", uint64(resettime), instance); itr->second.second = resettime; } } @@ -408,7 +408,7 @@ void InstanceSaveManager::LoadResetTimes() // calculate the next reset time t = (t / DAY) * DAY; t += ((today - t) / period + 1) * period + diff; - CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty); + CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '" UI64FMTD "' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty); } SetResetTimeFor(mapid, difficulty, t); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 04c2c22c595..4660489004d 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -360,7 +360,7 @@ void Map::EnsureGridLoadedForActiveObject(const Cell &cell, WorldObject* object) // refresh grid state & timer if (grid->GetGridState() != GRID_STATE_ACTIVE) { - TC_LOG_DEBUG(LOG_FILTER_MAPS, "Active object "UI64FMTD" triggers loading of grid [%u, %u] on map %u", object->GetGUID(), cell.GridX(), cell.GridY(), GetId()); + TC_LOG_DEBUG(LOG_FILTER_MAPS, "Active object " UI64FMTD " triggers loading of grid [%u, %u] on map %u", object->GetGUID(), cell.GridX(), cell.GridY(), GetId()); ResetGridExpiry(*grid, 0.1f); grid->SetGridState(GRID_STATE_ACTIVE); } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 8056d6263c0..6311e629641 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -78,7 +78,7 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { - TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID()); + TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for " UI64FMTD ".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID()); creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL); } diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 966b3edfcb9..fb96c327b05 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1363,6 +1363,16 @@ void ScriptMgr::OnGroupDisband(Group* group) } // Unit +void ScriptMgr::OnHeal(Unit* healer, Unit* reciever, uint32 gain) +{ + FOREACH_SCRIPT(UnitScript)->OnHeal(healer, reciever, gain); +} + +void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32 damage) +{ + FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage); +} + void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage) { FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index e7946501616..a3eff880bb9 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -396,6 +396,12 @@ class UnitScript : public ScriptObject UnitScript(const char* name, bool addToScripts = true); public: + // Called when a unit deals damage to another unit + virtual void OnHeal(Unit* /*healer*/, Unit* /*reciever*/, uint32 /*gain*/) { } + + // Called when a unit deals damage to another unit + virtual void OnDamage(Unit* /*attacker*/, Unit* /*victim*/, uint32 /*damage*/) { } + // Called when DoT's Tick Damage is being Dealt virtual void ModifyPeriodicDamageAurasTick(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { } @@ -1054,6 +1060,8 @@ class ScriptMgr public: /* UnitScript */ + void OnHeal(Unit* healer, Unit* reciever, uint32 gain); + void OnDamage(Unit* attacker, Unit* victim, uint32 damage); void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage); void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage); void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 866cd888c3e..2eee80924a4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -643,7 +643,7 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets) if (Player* playerCaster = m_caster->ToPlayer()) { // selection has to be found and to be valid target for the spell - if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetSelection())) + if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget())) if (m_spellInfo->CheckExplicitTarget(m_caster, selectedUnit) == SPELL_CAST_OK) unit = selectedUnit; } @@ -1777,9 +1777,9 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) { case SPELL_EFFECT_SUMMON_RAF_FRIEND: case SPELL_EFFECT_SUMMON_PLAYER: - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetSelection()) + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->GetTarget()) { - WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); + WorldObject* target = ObjectAccessor::FindPlayer(m_caster->GetTarget()); CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); @@ -3095,7 +3095,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // set target for proper facing if ((m_casttime || m_spellInfo->IsChanneled()) && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) - m_caster->FocusTarget(this, m_targets.GetObjectTarget()); + m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget()); if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD)) TriggerGlobalCooldown(); @@ -3661,8 +3661,8 @@ void Spell::finish(bool ok) ((Puppet*)charm)->UnSummon(); } - if (m_caster->GetTypeId() == TYPEID_UNIT) - m_caster->ReleaseFocus(this); + if (Creature* creatureCaster = m_caster->ToCreature()) + creatureCaster->ReleaseFocus(this); if (!ok) return; @@ -5323,10 +5323,10 @@ SpellCastResult Spell::CheckCast(bool strict) { if (m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_BAD_TARGETS; - if (!m_caster->ToPlayer()->GetSelection()) + if (!m_caster->GetTarget()) return SPELL_FAILED_BAD_TARGETS; - Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); + Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetTarget()); if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell return SPELL_FAILED_BAD_TARGETS; @@ -5358,10 +5358,10 @@ SpellCastResult Spell::CheckCast(bool strict) Player* playerCaster = m_caster->ToPlayer(); // - if (!(playerCaster->GetSelection())) + if (!(playerCaster->GetTarget())) return SPELL_FAILED_BAD_TARGETS; - Player* target = ObjectAccessor::FindPlayer(playerCaster->GetSelection()); + Player* target = playerCaster->GetSelectedPlayer(); if (!target || !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId())) diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 332169ebd00..45ab88e9688 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -450,12 +450,12 @@ public: uint32 pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC // Command is supposed to be: .account password [$oldpassword] [$newpassword] [$newpasswordconfirmation] [$emailconfirmation] - char* oldPassword = strtok((char*)args, " "); // This extracts [$oldpassword] - char* newPassword = strtok(NULL, " "); // This extracts [$newpassword] - char* passwordConfirmation = strtok(NULL, " "); // This extracts [$newpasswordconfirmation] - const char* emailConfirmation; // This defines the emailConfirmation variable, which is optional depending on sec type. - if (!(emailConfirmation = strtok(NULL, " "))) // This extracts [$emailconfirmation]. If it doesn't exist, however... - emailConfirmation = ""; // ... it's simply "" for emailConfirmation. + char* oldPassword = strtok((char*)args, " "); // This extracts [$oldpassword] + char* newPassword = strtok(NULL, " "); // This extracts [$newpassword] + char* passwordConfirmation = strtok(NULL, " "); // This extracts [$newpasswordconfirmation] + char const* emailConfirmation = strtok(NULL, " "); // This defines the emailConfirmation variable, which is optional depending on sec type. + if (!emailConfirmation) // This extracts [$emailconfirmation]. If it doesn't exist, however... + emailConfirmation = ""; // ... it's simply "" for emailConfirmation. //Is any of those variables missing for any reason ? We return false. if (!oldPassword || !newPassword || !passwordConfirmation) diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 6c831520d59..199b1e43f6c 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -179,7 +179,7 @@ public: return false; } - if (handler->GetSession()->GetPlayer()->GetSelection()) + if (handler->GetSession()->GetPlayer()->GetTarget()) unit->PlayDistanceSound(soundId, handler->GetSession()->GetPlayer()); else unit->PlayDirectSound(soundId, handler->GetSession()->GetPlayer()); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 513d378287b..3d531cee1f5 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -529,7 +529,7 @@ public: { Unit* target = handler->getSelectedUnit(); - if (!target || !handler->GetSession()->GetPlayer()->GetSelection()) + if (!target || !handler->GetSession()->GetPlayer()->GetTarget()) { handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); handler->SetSentErrorMessage(true); @@ -597,7 +597,7 @@ public: static bool HandleGUIDCommand(ChatHandler* handler, char const* /*args*/) { - uint64 guid = handler->GetSession()->GetPlayer()->GetSelection(); + uint64 guid = handler->GetSession()->GetPlayer()->GetTarget(); if (guid == 0) { @@ -1762,7 +1762,7 @@ public: // accept only explicitly selected target (not implicitly self targeting case) Unit* target = handler->getSelectedUnit(); - if (player->GetSelection() && target) + if (player->GetTarget() && target) { if (target->GetTypeId() != TYPEID_UNIT || target->IsPet()) { @@ -2107,7 +2107,7 @@ public: } Unit* target = handler->getSelectedUnit(); - if (!target || !handler->GetSession()->GetPlayer()->GetSelection()) + if (!target || !handler->GetSession()->GetPlayer()->GetTarget()) { handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index f10a929c675..1cedeb79c22 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1297,22 +1297,17 @@ public: char* receiver_str = strtok((char*)args, " "); char* text = strtok(NULL, ""); - uint64 guid = handler->GetSession()->GetPlayer()->GetSelection(); - Creature* creature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(guid); - + Creature* creature = handler->getSelectedCreature(); if (!creature || !receiver_str || !text) - { return false; - } - uint64 receiver_guid= atol(receiver_str); + uint64 receiver_guid = atol(receiver_str); // check online security if (handler->HasLowerSecurity(ObjectAccessor::FindPlayer(receiver_guid), 0)) return false; creature->MonsterWhisper(text, receiver_guid); - return true; } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 987807c2080..9a9dfa60521 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -1069,7 +1069,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript { me->AI()->DoCast(me, SPELL_SYLVANAS_DESTROY_ICE_WALL, false); if (_isattackingwall) - _events.ScheduleEvent(EVENT_ESCAPE_22, 1000); + _events.ScheduleEvent(EVENT_ESCAPE_23, 1000); } break; diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h index 3dc2add8132..4fe928dcc22 100644 --- a/src/server/shared/Database/MySQLThreading.h +++ b/src/server/shared/Database/MySQLThreading.h @@ -33,7 +33,7 @@ class MySQL static void Thread_Init() { mysql_thread_init(); - TC_LOG_WARN(LOG_FILTER_SQL, "Core thread with ID ["UI64FMTD"] initializing MySQL thread.", + TC_LOG_WARN(LOG_FILTER_SQL, "Core thread with ID [" UI64FMTD "] initializing MySQL thread.", (uint64)ACE_Based::Thread::currentId()); } @@ -44,7 +44,7 @@ class MySQL static void Thread_End() { mysql_thread_end(); - TC_LOG_WARN(LOG_FILTER_SQL, "Core thread with ID ["UI64FMTD"] shutting down MySQL thread.", + TC_LOG_WARN(LOG_FILTER_SQL, "Core thread with ID [" UI64FMTD "] shutting down MySQL thread.", (uint64)ACE_Based::Thread::currentId()); } diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp index 7708aa36617..c90a6e527f7 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.cpp +++ b/src/tools/mesh_extractor/ContinentBuilder.cpp @@ -6,104 +6,59 @@ #include "Cache.h" #include "ace/Task.h" #include "Recast.h" +#include "DetourCommon.h" class BuilderThread : public ACE_Task_Base { private: int X, Y, MapId; - bool Instance; std::string Continent; dtNavMeshParams Params; ContinentBuilder* cBuilder; - WorldModelRoot* Model; - const WorldModelDefinition* Definition; public: BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {} - void SetData(int x, int y, int map, const std::string& cont, bool instance, WorldModelRoot* model, const WorldModelDefinition* def) + + void SetData(int x, int y, int map, const std::string& cont) { X = x; Y = y; MapId = map; Continent = cont; - Instance = instance; - if (Instance) - { - Model = model; - Definition = def; - } - else - Model = NULL; } int svc() { - if (Instance) + Free = false; + printf("[%02i,%02i] Building tile\n", X, Y); + TileBuilder builder(cBuilder, Continent, X, Y, MapId); + char buff[100]; + sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X); + FILE* f = fopen(buff, "r"); + if (f) // Check if file already exists. { - // Build a WMO - printf("Building WMO %s ( %u )", Continent.c_str(), MapId); - TileBuilder builder(cBuilder, Continent, X, Y, MapId); - char buff[100]; - sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X); - FILE* f = fopen(buff, "r"); - if (f) // Check if file already exists. - { - printf("Instance %s ( %u ) skipped, file already exists\n", Continent.c_str(), MapId); - fclose(f); - return 0; - } - - uint8* nav = builder.BuildInstance(Params, Model, *Definition); - if (nav) - { - f = fopen(buff, "wb"); - if (!f) - { - printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); - return 0; - } - MmapTileHeader header; - header.size = builder.DataSize; - fwrite(&header, sizeof(MmapTileHeader), 1, f); - fwrite(nav, sizeof(unsigned char), builder.DataSize, f); - fclose(f); - } - dtFree(nav); + printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); + fclose(f); + Free = true; return 0; } - else + uint8* nav = builder.BuildTiled(Params); + if (nav) { - Free = false; - printf("[%02i,%02i] Building tile\n", X, Y); - TileBuilder builder(cBuilder, Continent, X, Y, MapId); - char buff[100]; - sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X); - FILE* f = fopen(buff, "r"); - if (f) // Check if file already exists. + f = fopen(buff, "wb"); + if (!f) { - printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); - fclose(f); - Free = true; + printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); return 0; } - uint8* nav = builder.Build(Params); - if (nav) - { - f = fopen(buff, "wb"); - if (!f) - { - printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); - return 0; - } - MmapTileHeader header; - header.size = builder.DataSize; - fwrite(&header, sizeof(MmapTileHeader), 1, f); - fwrite(nav, sizeof(unsigned char), builder.DataSize, f); - fclose(f); - } - dtFree(nav); - printf("[%02i,%02i] Tile Built!\n", X, Y); - Free = true; + MmapTileHeader header; + header.size = builder.DataSize; + fwrite(&header, sizeof(MmapTileHeader), 1, f); + fwrite(nav, sizeof(unsigned char), builder.DataSize, f); + fclose(f); } + dtFree(nav); + printf("[%02i,%02i] Tile Built!\n", X, Y); + Free = true; return 0; } @@ -155,26 +110,57 @@ void ContinentBuilder::Build() CalculateTileBounds(); dtNavMeshParams params; - params.maxPolys = 1 << STATIC_POLY_BITS; - params.maxTiles = TileMap->TileTable.size(); - rcVcopy(params.orig, bmin); - params.tileHeight = Constants::TileSize; - params.tileWidth = Constants::TileSize; - fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); - fclose(mmap); + std::vector<BuilderThread*> Threads; if (TileMap->IsGlobalModel) { printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId); - BuilderThread* thread = new BuilderThread(this, params); - Threads.push_back(thread); - thread->SetData(65, 65, MapId, Continent, true, TileMap->Model, &TileMap->ModelDefinition); - thread->activate(); - thread->wait(); + + TileBuilder* builder = new TileBuilder(this, Continent, 0, 0, MapId); + builder->AddGeometry(TileMap->Model, TileMap->ModelDefinition); + uint8* nav = builder->BuildInstance(params); + if (nav) + { + // Set some params for the navmesh + dtMeshHeader* header = (dtMeshHeader*)nav; + dtVcopy(params.orig, header->bmin); + params.tileWidth = header->bmax[0] - header->bmin[0]; + params.tileHeight = header->bmax[2] - header->bmin[2]; + params.maxTiles = 1; + params.maxPolys = header->polyCount; + fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); + fclose(mmap); + + char buff[100]; + sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, 0, 0); + FILE* f = fopen(buff, "wb"); + if (!f) + { + printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); + return; + } + + MmapTileHeader mheader; + mheader.size = builder->DataSize; + fwrite(&mheader, sizeof(MmapTileHeader), 1, f); + fwrite(nav, sizeof(unsigned char), builder->DataSize, f); + fclose(f); + } + + dtFree(nav); + delete builder; } else { + params.maxPolys = 32768; + params.maxTiles = 4096; + rcVcopy(params.orig, Constants::Origin); + params.tileHeight = Constants::TileSize; + params.tileWidth = Constants::TileSize; + fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); + fclose(mmap); + for (uint32 i = 0; i < NumberOfThreads; ++i) Threads.push_back(new BuilderThread(this, params)); printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads); @@ -187,7 +173,7 @@ void ContinentBuilder::Build() { if ((*_th)->Free) { - (*_th)->SetData(itr->X, itr->Y, MapId, Continent, false, NULL, NULL); + (*_th)->SetData(itr->X, itr->Y, MapId, Continent); (*_th)->activate(); next = true; break; diff --git a/src/tools/mesh_extractor/Geometry.cpp b/src/tools/mesh_extractor/Geometry.cpp index 37f5c68bb6d..df828dcd573 100644 --- a/src/tools/mesh_extractor/Geometry.cpp +++ b/src/tools/mesh_extractor/Geometry.cpp @@ -17,7 +17,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max ) max = new float[3]; for (int i = 0; i < 3; ++i) { - max[i] = std::numeric_limits<float>::min(); + max[i] = std::numeric_limits<float>::lowest(); min[i] = std::numeric_limits<float>::max(); } @@ -42,8 +42,8 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max ) void Geometry::CalculateMinMaxHeight( float& min, float& max ) { - min = 0.0f; - max = 0.0f; + min = std::numeric_limits<float>::max(); + max = std::numeric_limits<float>::lowest(); for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr) { diff --git a/src/tools/mesh_extractor/MPQ.h b/src/tools/mesh_extractor/MPQ.h index 2f8b082f526..30e11741550 100644 --- a/src/tools/mesh_extractor/MPQ.h +++ b/src/tools/mesh_extractor/MPQ.h @@ -26,7 +26,8 @@ public: libmpq__off_t size, transferred; libmpq__file_unpacked_size(mpq_a, filenum, &size); - char *buffer = new char[size]; + char* buffer = new char[size + 1]; + buffer[size] = '\0'; libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred); diff --git a/src/tools/mesh_extractor/MPQManager.cpp b/src/tools/mesh_extractor/MPQManager.cpp index 3c63aed97d0..4d3ab808a2e 100644 --- a/src/tools/mesh_extractor/MPQManager.cpp +++ b/src/tools/mesh_extractor/MPQManager.cpp @@ -23,7 +23,7 @@ void MPQManager::Initialize() for (uint32 i = 0; i < size; ++i) { MPQArchive* arc = new MPQArchive(std::string("Data/" + std::string(Files[i])).c_str()); - Archives.push_front(arc); + Archives.push_front(arc); // MPQ files have to be transversed in reverse order to properly account for patched files printf("Opened %s\n", Files[i]); } } @@ -109,5 +109,7 @@ FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file ) exit(1); } fwrite(buffer, sizeof(uint8), size, ret); + fseek(ret, 0, SEEK_SET); + delete[] buffer; return ret; } diff --git a/src/tools/mesh_extractor/MeshExtractor.cpp b/src/tools/mesh_extractor/MeshExtractor.cpp index 4a312640395..0d9160a610b 100644 --- a/src/tools/mesh_extractor/MeshExtractor.cpp +++ b/src/tools/mesh_extractor/MeshExtractor.cpp @@ -76,7 +76,7 @@ void ExtractDBCs() std::string component = "component.wow-" + std::string(MPQManager::Languages[*itr]) + ".txt"; // Extract the component file - Utils::SaveToDisk(MPQHandler->GetFile(component), path + component); + Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component); // Extract the DBC files for the given locale for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2) Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen)); @@ -328,6 +328,8 @@ void PrintUsage() void LoadTile(dtNavMesh*& navMesh, const char* tile) { FILE* f = fopen(tile, "rb"); + if (!f) + return; MmapTileHeader header; if (fread(&header, sizeof(MmapTileHeader), 1, f) != 1) @@ -376,37 +378,37 @@ int main(int argc, char* argv[]) if (extractFlags & Constants::EXTRACT_FLAG_TEST) { - float start[] = { 0.0f, 0.0f, 0.0f }; - float end[] = { 0.0f, 0.0f, 0.0f }; + float start[] = { 16226.200195f, 16257.000000f, 13.202200f }; + float end[] = { 16245.725586f, 16382.465820f, 47.384956f }; // float m_spos[3]; - m_spos[0] = -1.0f * start[1]; + m_spos[0] = -start[1]; m_spos[1] = start[2]; - m_spos[2] = -1.0f * start[0]; + m_spos[2] = -start[0]; // float m_epos[3]; - m_epos[0] = -1.0f * end[1]; + m_epos[0] = -end[1]; m_epos[1] = end[2]; - m_epos[2] = -1.0f * end[0]; + m_epos[2] = -end[0]; // dtQueryFilter m_filter; - m_filter.setIncludeFlags(0xffff); - m_filter.setExcludeFlags(0); + m_filter.setIncludeFlags(Constants::POLY_AREA_ROAD | Constants::POLY_AREA_TERRAIN); + m_filter.setExcludeFlags(Constants::POLY_AREA_WATER); // float m_polyPickExt[3]; - m_polyPickExt[0] = 2; - m_polyPickExt[1] = 4; - m_polyPickExt[2] = 2; + m_polyPickExt[0] = 2.5f; + m_polyPickExt[1] = 2.5f; + m_polyPickExt[2] = 2.5f; // dtPolyRef m_startRef; dtPolyRef m_endRef; - FILE* mmap = fopen(".mmap", "rb"); + FILE* mmap = fopen("mmaps/001.mmap", "rb"); dtNavMeshParams params; int count = fread(¶ms, sizeof(dtNavMeshParams), 1, mmap); fclose(mmap); @@ -420,13 +422,16 @@ int main(int argc, char* argv[]) dtNavMeshQuery* navMeshQuery = new dtNavMeshQuery(); navMesh->init(¶ms); - LoadTile(navMesh, ".mmtile"); - LoadTile(navMesh, ".mmtile"); - LoadTile(navMesh, ".mmtile"); - LoadTile(navMesh, ".mmtile"); - LoadTile(navMesh, ".mmtile"); - LoadTile(navMesh, ".mmtile"); - + for (int i = 0; i <= 32; ++i) + { + for (int j = 0; j <= 32; ++j) + { + char buff[100]; + sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j); + LoadTile(navMesh, buff); + } + } + navMeshQuery->init(navMesh, 2048); float nearestPt[3]; @@ -440,7 +445,24 @@ int main(int argc, char* argv[]) return 0; } - printf("Found!"); + int hops; + dtPolyRef* hopBuffer = new dtPolyRef[8192]; + dtStatus status = navMeshQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, hopBuffer, &hops, 8192); + + int resultHopCount; + float* straightPath = new float[2048*3]; + unsigned char* pathFlags = new unsigned char[2048]; + dtPolyRef* pathRefs = new dtPolyRef[2048]; + + status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048); + std::vector<Vector3> FinalPath; + FinalPath.reserve(resultHopCount); + for (uint32 i = 0; i < resultHopCount; ++i) + { + Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[i * 3 + 0], straightPath[i * 3 + 1], straightPath[i * 3 + 2])); + FinalPath.push_back(finalV); + printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z); + } } return 0; diff --git a/src/tools/mesh_extractor/TileBuilder.cpp b/src/tools/mesh_extractor/TileBuilder.cpp index 857cf7f16d8..51df91d2652 100644 --- a/src/tools/mesh_extractor/TileBuilder.cpp +++ b/src/tools/mesh_extractor/TileBuilder.cpp @@ -16,51 +16,25 @@ TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId) : World(world), X(x), Y(y), MapId(mapId), _Geometry(NULL), DataSize(0), cBuilder(_cBuilder) { - /* - Test, non-working values - // Cell Size = TileSize / TileVoxelSize - // 1800 = TileVoxelSize - Config.cs = Constants::TileSize / 1800; - // Cell Height - Config.ch = 0.4f; - // Min Region Area = 20^2 - Config.minRegionArea = 20*20; - // Merge Region Area = 40^2 - Config.mergeRegionArea = 40*40; - Config.tileSize = Constants::TileSize / 4; + // Config for normal maps + memset(&Config, 0, sizeof(rcConfig)); + Config.cs = Constants::TileSize / 1800.0f; // TileSize / voxelSize + Config.ch = 0.3f; + Config.minRegionArea = 36; + Config.mergeRegionArea = 144; Config.walkableSlopeAngle = 50.0f; Config.detailSampleDist = 3.0f; Config.detailSampleMaxError = 1.25f; - Config.walkableClimb = floorf(1.0f / Config.ch); - Config.walkableHeight = ceilf(1.652778f / Config.ch); - Config.walkableRadius = ceilf(0.2951389f / Config.cs); + Config.walkableClimb = 1.0f / Config.ch; + Config.walkableHeight = 2.1 / Config.ch; + Config.walkableRadius = 0.6f / Config.cs; Config.maxEdgeLen = Config.walkableRadius * 8; - Config.borderSize = Config.walkableRadius + 4; - Config.width = 1800 + Config.borderSize * 2; - Config.height = 1800 + Config.borderSize * 2; - Config.maxVertsPerPoly = 6; + Config.borderSize = Config.walkableRadius + 8; + Config.tileSize = 1800; Config.maxSimplificationError = 1.3f; - */ - - // All are in UNIT metrics! - memset(&Config, 0, sizeof(rcConfig)); - - Config.maxVertsPerPoly = DT_VERTS_PER_POLYGON; - Config.cs = Constants::BaseUnitDim; - Config.ch = Constants::BaseUnitDim; - Config.walkableSlopeAngle = 60.0f; - Config.tileSize = Constants::VertexPerTile; - Config.walkableRadius = 1; - Config.borderSize = Config.walkableRadius + 3; - Config.maxEdgeLen = Constants::VertexPerTile + 1; //anything bigger than tileSize - Config.walkableHeight = 3; - Config.walkableClimb = 2; // keep less than walkableHeight - Config.minRegionArea = rcSqr(60); - Config.mergeRegionArea = rcSqr(50); - Config.maxSimplificationError = 2.0f; // eliminates most jagged edges (tinny polygons) - Config.detailSampleDist = Config.cs * 64; - Config.detailSampleMaxError = Config.ch * 2; + Config.maxVertsPerPoly = 6; + // Config for instances memset(&InstanceConfig, 0, sizeof(rcConfig)); InstanceConfig.cs = 0.2f; InstanceConfig.ch = 0.3f; @@ -90,33 +64,22 @@ void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshPara bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1)); } -uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoot* root, const WorldModelDefinition& def ) +void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def) { _Geometry = new Geometry(); _Geometry->Transform = true; - WorldModelHandler::InsertModelGeometry(_Geometry->Vertices, _Geometry->Triangles, def, root); + WorldModelHandler::InsertModelGeometry(_Geometry->Vertices, _Geometry->Triangles, def, root, false); - if (Constants::Debug) - { - char buff[100]; - sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X); - FILE* debug = fopen(buff, "wb"); - for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i) - { - const Vector3& vector = _Geometry->Vertices[i]; - fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z); - } - for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i) - { - const Triangle<uint32>& triangle = _Geometry->Triangles[i]; - fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1); - } - fclose(debug); - } + OutputDebugVertices(); +} + +uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams ) +{ + float* bmin = NULL, *bmax = NULL; - float* bmin, *bmax; _Geometry->CalculateBoundingBox(bmin, bmax); + rcVcopy(InstanceConfig.bmax, bmax); rcVcopy(InstanceConfig.bmin, bmin); @@ -126,14 +89,13 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoo int* triangles; uint8* areas; _Geometry->GetRawData(vertices, triangles, areas); - _Geometry->Vertices.clear(); - _Geometry->Triangles.clear(); - // this sets the dimensions of the heightfield - should maybe happen before border padding + // this sets the dimensions of the heightfield rcCalcGridSize(InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, &InstanceConfig.width, &InstanceConfig.height); + rcHeightfield* hf = rcAllocHeightfield(); rcCreateHeightfield(Context, *hf, InstanceConfig.width, InstanceConfig.height, InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, InstanceConfig.ch); - + rcClearUnwalkableTriangles(Context, InstanceConfig.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas); rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, InstanceConfig.walkableClimb); @@ -190,9 +152,10 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoo params.walkableClimb = InstanceConfig.walkableClimb * InstanceConfig.ch; params.walkableHeight = InstanceConfig.walkableHeight * InstanceConfig.ch; params.walkableRadius = InstanceConfig.walkableRadius * InstanceConfig.cs; - params.tileX = 0; - params.tileY = 0; + params.tileX = X; + params.tileY = Y; params.tileLayer = 0; + params.buildBvTree = true; rcVcopy(params.bmax, bmax); rcVcopy(params.bmin, bmin); @@ -200,7 +163,14 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoo // Offmesh-connection settings params.offMeshConCount = 0; // none for now - //params.tileSize = Constants::VertexPerMap; + rcFreeHeightField(hf); + rcFreeCompactHeightfield(chf); + rcFreeContourSet(contours); + delete vertices; + delete triangles; + delete areas; + delete bmin; + delete bmax; if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount) { @@ -208,20 +178,18 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoo // keep in mind that we do output those into debug info // drop tiles with only exact count - some tiles may have geometry while having less tiles printf("No polygons to build on tile, skipping.\n"); - delete areas; - delete triangles; - delete vertices; + rcFreePolyMesh(pmesh); + rcFreePolyMeshDetail(dmesh); return NULL; } int navDataSize; uint8* navData; - printf("Creating the navmesh with %i vertices, %i polys, %i triangles!\n", pmesh->nverts, pmesh->npolys, dmesh->ntris); + printf("Creating the navmesh with %i vertices, %i polys, %i triangles!\n", params.vertCount, params.polyCount, params.detailTriCount); bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize); - delete areas; - delete triangles; - delete vertices; + rcFreePolyMesh(pmesh); + rcFreePolyMeshDetail(dmesh); if (result) { @@ -233,7 +201,7 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams, WorldModelRoo return NULL; } -uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) +uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams) { _Geometry = new Geometry(); _Geometry->Transform = true; @@ -245,10 +213,14 @@ uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty()) return NULL; + float* bmin = NULL, *bmax = NULL; + CalculateTileBounds(bmin, bmax, navMeshParams); + _Geometry->CalculateMinMaxHeight(bmin[1], bmax[1]); + // again, we load everything - wasteful but who cares - for (int ty = Y - 2; ty <= Y + 2; ty++) + for (int ty = Y - 1; ty <= Y + 1; ty++) { - for (int tx = X - 2; tx <= X + 2; tx++) + for (int tx = X - 1; tx <= X + 1; tx++) { // don't load main tile again if (tx == X && ty == Y) @@ -267,23 +239,7 @@ uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) } } - if (Constants::Debug) - { - char buff[100]; - sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X); - FILE* debug = fopen(buff, "wb"); - for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i) - { - const Vector3& vector = _Geometry->Vertices[i]; - fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z); - } - for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i) - { - const Triangle<uint32>& triangle = _Geometry->Triangles[i]; - fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1); - } - fclose(debug); - } + OutputDebugVertices(); uint32 numVerts = _Geometry->Vertices.size(); uint32 numTris = _Geometry->Triangles.size(); @@ -294,93 +250,38 @@ uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) _Geometry->Vertices.clear(); _Geometry->Triangles.clear(); + // add border + bmin[0] -= Config.borderSize * Config.cs; + bmin[2] -= Config.borderSize * Config.cs; + bmax[0] += Config.borderSize * Config.cs; + bmax[2] += Config.borderSize * Config.cs; - rcVcopy(Config.bmin, cBuilder->bmin); - rcVcopy(Config.bmax, cBuilder->bmax); + rcHeightfield* hf = rcAllocHeightfield(); + int width = Config.tileSize + (Config.borderSize * 2); + rcCreateHeightfield(Context, *hf, width, width, bmin, bmax, Config.cs, Config.ch); - // this sets the dimensions of the heightfield - should maybe happen before border padding - rcCalcGridSize(Config.bmin, Config.bmax, Config.cs, &Config.width, &Config.height); + rcClearUnwalkableTriangles(Context, Config.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas); + rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb); - // Initialize per tile config. - rcConfig tileCfg = Config; - tileCfg.width = Config.tileSize + Config.borderSize * 2; - tileCfg.height = Config.tileSize + Config.borderSize * 2; + rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf); + rcFilterLedgeSpans(Context, Config.walkableHeight, Config.walkableClimb, *hf); + rcFilterWalkableLowHeightSpans(Context, Config.walkableHeight, *hf); - // merge per tile poly and detail meshes - rcPolyMesh** pmmerge = new rcPolyMesh*[Constants::TilesPerMap * Constants::TilesPerMap]; - rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[Constants::TilesPerMap * Constants::TilesPerMap]; + rcCompactHeightfield* chf = rcAllocCompactHeightfield(); + rcBuildCompactHeightfield(Context, Config.walkableHeight, Config.walkableClimb, *hf, *chf); - int nmerge = 0; - for (int y = 0; y < Constants::TilesPerMap; ++y) - { - for (int x = 0; x < Constants::TilesPerMap; ++x) - { - // Calculate the per tile bounding box. - tileCfg.bmin[0] = Config.bmin[0] + float(x * Config.tileSize - Config.borderSize) * Config.cs; - tileCfg.bmin[2] = Config.bmin[2] + float(y * Config.tileSize - Config.borderSize) * Config.cs; - tileCfg.bmax[0] = Config.bmin[0] + float((x + 1) * Config.tileSize + Config.borderSize) * Config.cs; - tileCfg.bmax[2] = Config.bmin[2] + float((y + 1) * Config.tileSize + Config.borderSize) * Config.cs; - - - rcHeightfield* hf = rcAllocHeightfield(); - rcCreateHeightfield(Context, *hf, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch); - rcClearUnwalkableTriangles(Context, tileCfg.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas); - rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb); - - // Once all geometry is rasterized, we do initial pass of filtering to - // remove unwanted overhangs caused by the conservative rasterization - // as well as filter spans where the character cannot possibly stand. - rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf); - rcFilterLedgeSpans(Context, tileCfg.walkableHeight, tileCfg.walkableClimb, *hf); - rcFilterWalkableLowHeightSpans(Context, tileCfg.walkableHeight, *hf); - - // Compact the heightfield so that it is faster to handle from now on. - // This will result in more cache coherent data as well as the neighbours - // between walkable cells will be calculated. - rcCompactHeightfield* chf = rcAllocCompactHeightfield(); - rcBuildCompactHeightfield(Context, tileCfg.walkableHeight, tileCfg.walkableClimb, *hf, *chf); - - rcFreeHeightField(hf); - - // Erode the walkable area by agent radius. - rcErodeWalkableArea(Context, Config.walkableRadius, *chf); - // Prepare for region partitioning, by calculating distance field along the walkable surface. - rcBuildDistanceField(Context, *chf); - // Partition the walkable surface into simple regions without holes. - rcBuildRegions(Context, *chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea); - - // Create contours. - rcContourSet* cset = rcAllocContourSet(); - rcBuildContours(Context, *chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *cset); - - // Build polygon navmesh from the contours. - rcPolyMesh* pmesh = rcAllocPolyMesh(); - rcBuildPolyMesh(Context, *cset, tileCfg.maxVertsPerPoly, *pmesh); - - // Build detail mesh. - rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail(); - rcBuildPolyMeshDetail(Context, *pmesh, *chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *dmesh); - - // Free memory - rcFreeCompactHeightfield(chf); - rcFreeContourSet(cset); - - pmmerge[nmerge] = pmesh; - dmmerge[nmerge] = dmesh; - ++nmerge; - } - } + rcErodeWalkableArea(Context, Config.walkableRadius, *chf); + rcBuildDistanceField(Context, *chf); + rcBuildRegions(Context, *chf, Config.borderSize, Config.minRegionArea, Config.mergeRegionArea); + + rcContourSet* contours = rcAllocContourSet(); + rcBuildContours(Context, *chf, Config.maxSimplificationError, Config.maxEdgeLen, *contours); rcPolyMesh* pmesh = rcAllocPolyMesh(); - rcMergePolyMeshes(Context, pmmerge, nmerge, *pmesh); + rcBuildPolyMesh(Context, *contours, Config.maxVertsPerPoly, *pmesh); rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail(); - rcMergePolyMeshDetails(Context, dmmerge, nmerge, *dmesh); - - delete[] pmmerge; - delete[] dmmerge; - - printf("[%02i,%02i] Meshes merged!\n", X, Y); + rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh); // Set flags according to area types (e.g. Swim for Water) for (int i = 0; i < pmesh->npolys; i++) @@ -407,54 +308,60 @@ uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) params.detailVertsCount = dmesh->nverts; params.detailTris = dmesh->tris; params.detailTriCount = dmesh->ntris; - rcVcopy(params.bmin, pmesh->bmin); - rcVcopy(params.bmax, pmesh->bmax); // General settings params.ch = Config.ch; params.cs = Config.cs; - params.walkableClimb = Constants::BaseUnitDim * Config.walkableClimb; - params.walkableHeight = Constants::BaseUnitDim * Config.walkableHeight; - params.walkableRadius = Constants::BaseUnitDim * Config.walkableRadius; - params.tileX = (((cBuilder->bmin[0] + cBuilder->bmax[0]) / 2) - navMeshParams.orig[0]) / Constants::TileSize; - params.tileY = (((cBuilder->bmin[2] + cBuilder->bmax[2]) / 2) - navMeshParams.orig[2]) / Constants::TileSize; + params.walkableClimb = Config.walkableClimb * Config.ch; + params.walkableHeight = Config.walkableHeight * Config.ch; + params.walkableRadius = Config.walkableRadius * Config.cs; + params.tileX = X; + params.tileY = Y; + params.tileLayer = 0; + params.buildBvTree = true; + + // Recalculate the bounds with the added geometry + float* bmin2 = NULL, *bmax2 = NULL; + CalculateTileBounds(bmin2, bmax2, navMeshParams); + bmin2[1] = bmin[1]; + bmax2[1] = bmax[1]; - rcVcopy(params.bmin, cBuilder->bmin); - rcVcopy(params.bmax, cBuilder->bmax); + rcVcopy(params.bmax, bmax2); + rcVcopy(params.bmin, bmin2); // Offmesh-connection settings params.offMeshConCount = 0; // none for now - //params.tileSize = Constants::VertexPerMap; + rcFreeHeightField(hf); + rcFreeCompactHeightfield(chf); + rcFreeContourSet(contours); + delete vertices; + delete triangles; + delete areas; + delete bmin; + delete bmax; if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount) { // 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 // drop tiles with only exact count - some tiles may have geometry while having less tiles - printf("[%02i,%02i] No polygons to build on tile, skipping.\n", X, Y); + printf("[%02i, %02i] No polygons to build on tile, skipping.\n", X, Y); rcFreePolyMesh(pmesh); rcFreePolyMeshDetail(dmesh); - delete areas; - delete triangles; - delete vertices; return NULL; } int navDataSize; uint8* navData; - printf("[%02i,%02i] Creating the navmesh with %i vertices, %i polys, %i triangles!\n", X, Y, pmesh->nverts, pmesh->npolys, dmesh->ntris); + printf("[%02i, %02i] Creating the navmesh with %i vertices, %i polys, %i triangles!\n", X, Y, params.vertCount, params.polyCount, params.detailTriCount); bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize); - // Free some memory rcFreePolyMesh(pmesh); rcFreePolyMeshDetail(dmesh); - delete areas; - delete triangles; - delete vertices; if (result) { - printf("[%02i,%02i] NavMesh created, size %i!\n", X, Y, navDataSize); + printf("[%02i, %02i] NavMesh created, size %i!\n", X, Y, navDataSize); DataSize = navDataSize; return navData; } @@ -462,6 +369,27 @@ uint8* TileBuilder::Build(dtNavMeshParams& navMeshParams) return NULL; } +void TileBuilder::OutputDebugVertices() +{ + if (Constants::Debug) + { + char buff[100]; + sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X); + FILE* debug = fopen(buff, "wb"); + for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i) + { + const Vector3& vector = _Geometry->Vertices[i]; + fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z); + } + for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i) + { + const Triangle<uint32>& triangle = _Geometry->Triangles[i]; + fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1); + } + fclose(debug); + } +} + TileBuilder::~TileBuilder() { delete Context; diff --git a/src/tools/mesh_extractor/TileBuilder.h b/src/tools/mesh_extractor/TileBuilder.h index 814f989486e..165b3594ed6 100644 --- a/src/tools/mesh_extractor/TileBuilder.h +++ b/src/tools/mesh_extractor/TileBuilder.h @@ -16,8 +16,10 @@ public: ~TileBuilder(); void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams); - uint8* Build(dtNavMeshParams& navMeshParams); - uint8* BuildInstance(dtNavMeshParams& navMeshParams, WorldModelRoot* root, const WorldModelDefinition& def); + uint8* BuildTiled(dtNavMeshParams& navMeshParams); + uint8* BuildInstance(dtNavMeshParams& navMeshParams); + void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def); + void OutputDebugVertices(); std::string World; int X; int Y; diff --git a/src/tools/mesh_extractor/Utils.cpp b/src/tools/mesh_extractor/Utils.cpp index 10e0bdc0d04..24cfb5cd1db 100644 --- a/src/tools/mesh_extractor/Utils.cpp +++ b/src/tools/mesh_extractor/Utils.cpp @@ -87,7 +87,7 @@ std::string Utils::FixModelPath(const std::string& path ) return Utils::GetPathBase(path) + ".M2"; } -Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec) +Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate) { // Sources of information: /// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715 @@ -99,15 +99,21 @@ Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec) Vector3 ret = Utils::VectorTransform(vec, rot); // And finally scale and translate it to our origin - return (ret * def.Scale()) + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y); + ret = ret * def.Scale(); + if (translate) + ret = ret + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y); + return ret; } -Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec ) +Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate ) { G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW); Vector3 ret = Utils::VectorTransform(vec, G3D::Matrix4(quat.toRotationMatrix())); - return (ret * (inst.Scale / 1024.0f)) + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y); + ret = ret * (inst.Scale / 1024.0f); + if (translate) + ret = ret + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y); + return ret; } float Utils::ToRadians( float degrees ) @@ -138,11 +144,11 @@ Vector3 Vector3::Read( FILE* file ) return ret; } -Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/) +Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate) { if (Utils::Distance(height, 0.0f) > 0.5f) basePosition.z = 0.0f; - return Utils::TransformDoodadVertex(def, basePosition + Vector3(basePosition.x * Constants::UnitSize, basePosition.y * Constants::UnitSize, height)); + return Utils::TransformDoodadVertex(def, basePosition + Vector3(x * Constants::UnitSize, y * Constants::UnitSize, height), translate); } float Utils::Distance( float x, float y ) @@ -167,29 +173,43 @@ void Utils::SaveToDisk( FILE* stream, const std::string& path ) if (!disk) { printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str()); + fclose(stream); return; } uint32 size = Utils::Size(stream); uint8* data = new uint8[size]; // Read the data to an array - if (fread(data, 1, size, stream) != 1) + size_t read = fread(data, size, 1, stream); + if (read != 1) { - printf("SaveToDisk: Error reading from Stream while trying to save file %s to disck.\n", path.c_str()); + printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str()); + fclose(disk); + fclose(stream); return; } + // And write it in the file - fwrite(data, 1, size, disk); + size_t wrote = fwrite(data, size, 1, disk); + if (wrote != 1) + { + printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str()); + fclose(stream); + fclose(disk); + return; + } // Close the filestream fclose(disk); + fclose(stream); + // Free the used memory - delete [] data; + delete[] data; } Vector3 Utils::ToWoWCoords(const Vector3& vec ) { - return Vector3(-vec.z, vec.x, vec.y); + return Vector3(-vec.z, -vec.x, vec.y); } std::string Utils::GetExtension( std::string path ) diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h index a307dd4f695..d6bb421a633 100644 --- a/src/tools/mesh_extractor/Utils.h +++ b/src/tools/mesh_extractor/Utils.h @@ -367,7 +367,7 @@ public: } static float ToRadians(float degrees); static std::string GetPathBase(const std::string& path); - static Vector3 GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/); + static Vector3 GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/, bool translate = true); static float Distance(float x, float y); template<typename T> static bool IsAllZero(T* arr, uint32 size) @@ -383,8 +383,8 @@ public: static Vector3 ToWoWCoords(const Vector3& vec ); static std::string GetExtension( std::string path ); static char* GetPlainName(const char* FileName); - static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec); + static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate = true); static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false ); - static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec ); + static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate = true ); }; #endif diff --git a/src/tools/mesh_extractor/WorldModelHandler.cpp b/src/tools/mesh_extractor/WorldModelHandler.cpp index 24f63dc1e33..3565a1d6af0 100644 --- a/src/tools/mesh_extractor/WorldModelHandler.cpp +++ b/src/tools/mesh_extractor/WorldModelHandler.cpp @@ -79,13 +79,17 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk ) fseek(stream, mcnk->Source->Offset, SEEK_SET); } -void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root ) +void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate ) { for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group) { uint32 vertOffset = verts.size(); for (std::vector<Vector3>::iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2) - verts.push_back(Utils::TransformDoodadVertex(def, *itr2)); // Transform the vertex to world space + { + Vector3 v = Utils::TransformDoodadVertex(def, *itr2, translate); + // If translate is false, then we were called directly from the TileBuilder to add data to it's _Geometry member, hence, we have to manually convert the vertices to Recast format. + verts.push_back(translate ? v : Utils::ToRecast(v)); // Transform the vertex to world space + } for (uint32 i = 0; i < group->Triangles.size(); ++i) { @@ -122,7 +126,10 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v continue; int vertOffset = verts.size(); for (std::vector<Vector3>::iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2) - verts.push_back(Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2))); + { + Vector3 v = Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2, false), translate); + verts.push_back(translate ? v : Utils::ToRecast(v)); + } for (std::vector<Triangle<uint16> >::iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2) tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, itr2->V0 + vertOffset, itr2->V1 + vertOffset, itr2->V2 + vertOffset)); } @@ -144,14 +151,20 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v continue; uint32 vertOffset = verts.size(); - verts.push_back(Utils::GetLiquidVert(def, liquidHeader.BaseLocation, - liquidDataGeometry.HeightMap[x][y], x, y)); - verts.push_back(Utils::GetLiquidVert(def, liquidHeader.BaseLocation, - liquidDataGeometry.HeightMap[x + 1][y], x + 1, y)); - verts.push_back(Utils::GetLiquidVert(def, liquidHeader.BaseLocation, - liquidDataGeometry.HeightMap[x][y + 1], x, y + 1)); - verts.push_back(Utils::GetLiquidVert(def, liquidHeader.BaseLocation, - liquidDataGeometry.HeightMap[x + 1][y + 1], x + 1, y + 1)); + + Vector3 v1 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation, + liquidDataGeometry.HeightMap[x][y], x, y, translate); + Vector3 v2 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation, + liquidDataGeometry.HeightMap[x + 1][y], x + 1, y, translate); + Vector3 v3 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation, + liquidDataGeometry.HeightMap[x][y + 1], x, y + 1, translate); + Vector3 v4 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation, + liquidDataGeometry.HeightMap[x + 1][y + 1], x + 1, y + 1, translate); + + verts.push_back(translate ? v1 : Utils::ToRecast(v1)); + verts.push_back(translate ? v2 : Utils::ToRecast(v2)); + verts.push_back(translate ? v3 : Utils::ToRecast(v3)); + verts.push_back(translate ? v4 : Utils::ToRecast(v4)); tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset + 2, vertOffset + 1)); tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1)); diff --git a/src/tools/mesh_extractor/WorldModelHandler.h b/src/tools/mesh_extractor/WorldModelHandler.h index 0611a02f764..87a5ad62938 100644 --- a/src/tools/mesh_extractor/WorldModelHandler.h +++ b/src/tools/mesh_extractor/WorldModelHandler.h @@ -34,7 +34,7 @@ public: std::vector<Vector3> Vertices; std::vector<Triangle<uint32> > Triangles; bool IsSane() { return _definitions && _paths; } - static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root); + static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate = true); protected: void ProcessInternal(MapChunk* data); private: |
