Core/Movement: Add new SplineChainMovementGenerator that allows accurate replication of sniffed waypoints in static sequences, along with DB facilities that allow loading of waypoints from DB.

This commit is contained in:
treeston authored and Aokromes committed 2016-09-20 12:54:54 +02:00
1 parent 4869105623
commit c1cc7e0a36
12 files changed
+394 -21

No files matched your search

@@ -0,0 +1,21 @@
-- add tables for spline chain DB storage
DROP TABLE IF EXISTS `script_spline_chain_meta`;
CREATE TABLE `script_spline_chain_meta` (
`entry` INT UNSIGNED NOT NULL,
`chainId` TINYINT UNSIGNED NOT NULL,
`splineId` TINYINT UNSIGNED NOT NULL,
`expectedDuration` INT UNSIGNED NOT NULL,
`msUntilNext` INT UNSIGNED NOT NULL,
PRIMARY KEY USING BTREE (`entry`,`chainId`,`splineId`)
);
DROP TABLE IF EXISTS `script_spline_chain_waypoints`;
CREATE TABLE `script_spline_chain_waypoints` (
`entry` INT UNSIGNED NOT NULL,
`chainId` TINYINT UNSIGNED NOT NULL,
`splineId` TINYINT UNSIGNED NOT NULL,
`wpId` TINYINT UNSIGNED NOT NULL,
`x` FLOAT NOT NULL,
`y` FLOAT NOT NULL,
`z` FLOAT NOT NULL,
PRIMARY KEY USING BTREE (`entry`,`chainId`,`splineId`,`wpId`)
);
@@ -402,12 +402,11 @@ void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 wait
void npc_escortAI::FillPointMovementListForCreature()
{
ScriptPointVector const& movePoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
if (movePoints.empty())
ScriptPointVector const* movePoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
if (!movePoints)
return;
ScriptPointVector::const_iterator itrEnd = movePoints.end();
for (ScriptPointVector::const_iterator itr = movePoints.begin(); itr != itrEnd; ++itr)
for (ScriptPointVector::const_iterator itr = movePoints->begin(); itr != movePoints->end(); ++itr)
{
Escort_Waypoint point(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
WaypointList.push_back(point);
@@ -563,11 +562,11 @@ bool npc_escortAI::SetNextWaypoint(uint32 pointId, bool setPosition, bool resetW
bool npc_escortAI::GetWaypointPosition(uint32 pointId, float& x, float& y, float& z)
{
ScriptPointVector const& waypoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
if (waypoints.empty())
ScriptPointVector const* waypoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
if (!waypoints)
return false;
for (ScriptPointVector::const_iterator itr = waypoints.begin(); itr != waypoints.end(); ++itr)
for (ScriptPointVector::const_iterator itr = waypoints->begin(); itr != waypoints->end(); ++itr)
{
if (itr->uiPointId == pointId)
{
@@ -573,7 +573,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
case SMART_EVENT_MOVEMENTINFORM:
{
if (e.event.movementInform.type > NULL_MOTION_TYPE)
if (e.event.movementInform.type >= MAX_MOTION_TYPE)
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type);
return false;
+29
View File
@@ -19,6 +19,7 @@
#include "MotionMaster.h"
#include "CreatureAISelector.h"
#include "Creature.h"
#include "ScriptSystem.h"
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
@@ -28,6 +29,7 @@
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "SplineChainMovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
@@ -468,6 +470,33 @@ void MotionMaster::MoveSmoothPath(uint32 pointId, Movement::PointsArray const& p
//MovePoint(EVENT_CHARGE_PREPATH, pos, false);
}
void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint32 dbChainId, bool walk)
{
Creature* owner = _owner->ToCreature();
if (!owner)
{
TC_LOG_ERROR("misc", "MotionMaster::MoveAlongSplineChain: non-creature %s tried to walk along DB spline chain. Ignoring.", _owner->GetGUID().ToString().c_str());
return;
}
SplineChain const* chain = sScriptSystemMgr->GetSplineChain(owner, dbChainId);
if (!chain)
{
TC_LOG_ERROR("misc", "MotionMaster::MoveAlongSplineChain: creature with entry %u tried to walk along non-existing spline chain with DB id %u.", owner->GetEntry(), dbChainId);
return;
}
MoveAlongSplineChain(pointId, *chain, walk);
}
void MotionMaster::MoveAlongSplineChain(uint32 pointId, SplineChain const& chain, bool walk)
{
Mutate(new SplineChainMovementGenerator(pointId, chain, walk), MOTION_SLOT_ACTIVE);
}
void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info)
{
Mutate(new SplineChainMovementGenerator(info), MOTION_SLOT_ACTIVE);
}
void MotionMaster::MoveFall(uint32 id /*=0*/)
{
// use larger distance for vmap height search than in most other cases
+8 -1
View File
@@ -24,6 +24,7 @@
#include "SharedDefines.h"
#include "Object.h"
#include "MoveSplineInitArgs.h"
#include "SplineChain.h"
class MovementGenerator;
class Unit;
@@ -53,7 +54,9 @@ enum MovementGeneratorType
FOLLOW_MOTION_TYPE = 14,
ROTATE_MOTION_TYPE = 15,
EFFECT_MOTION_TYPE = 16,
NULL_MOTION_TYPE = 17
NULL_MOTION_TYPE = 17,
SPLINE_CHAIN_MOTION_TYPE = 18, // SplineChainMovementGenerator.h
MAX_MOTION_TYPE // limit
};
enum MovementSlot
@@ -196,6 +199,10 @@ class TC_GAME_API MotionMaster //: private std::stack<MovementGenerator *>
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
void MoveSmoothPath(uint32 pointId, G3D::Vector3 const* pathPoints, size_t pathSize, bool walk);
void MoveSmoothPath(uint32 pointId, Movement::PointsArray const& points, bool walk);
// Walk along spline chain stored in DB (script_spline_chain_meta and script_spline_chain_waypoints)
void MoveAlongSplineChain(uint32 pointId, uint32 dbChainId, bool walk);
void MoveAlongSplineChain(uint32 pointId, SplineChain const& chain, bool walk);
void ResumeSplineChain(SplineChainResumeInfo const& info);
void MoveFall(uint32 id = 0);
void MoveSeekAssistance(float x, float y, float z);
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* 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 "SplineChainMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Log.h"
uint32 SplineChainMovementGenerator::SendPathSpline(Unit* me, Movement::PointsArray const& wp) const
{
uint32 numWp = wp.size();
ASSERT(numWp > 1 && "Every path must have source & destination");
Movement::MoveSplineInit init(me);
if (numWp > 2)
init.MovebyPath(wp);
else
init.MoveTo(wp[1], false, true);
init.SetWalk(_walk);
return init.Launch();
}
void SplineChainMovementGenerator::SendSplineFor(Unit* me, uint32 index, uint32& toNext)
{
ASSERT(index < _chainSize);
TC_LOG_DEBUG("movement.splinechain", "%s: Sending spline for %u.", me->GetGUID().ToString().c_str(), index);
SplineChainLink const& thisLink = _chain[index];
uint32 actualDuration = SendPathSpline(me, thisLink.Points);
if (actualDuration != thisLink.ExpectedDuration)
{
TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms. Expected was %u ms (delta %d ms). Adjusting.", me->GetGUID().ToString().c_str(), index, actualDuration, thisLink.ExpectedDuration, int32(actualDuration) - int32(thisLink.ExpectedDuration));
toNext = uint32(double(actualDuration)/double(thisLink.ExpectedDuration) * toNext);
}
else
{
TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms.", me->GetGUID().ToString().c_str(), index, actualDuration);
}
}
void SplineChainMovementGenerator::Initialize(Unit* me)
{
if (_chainSize)
{
if (_nextFirstWP) // this is a resumed movegen that has to start with a partial spline
{
if (finished)
return;
SplineChainLink const& thisLink = _chain[_nextIndex];
if (_nextFirstWP >= thisLink.Points.size())
{
TC_LOG_ERROR("movement.splinechain", "%s: Attempted to resume spline chain from invalid resume state (%u, %u).", me->GetGUID().ToString().c_str(), _nextIndex, _nextFirstWP);
_nextFirstWP = thisLink.Points.size()-1;
}
Movement::PointsArray partial(thisLink.Points.begin() + (_nextFirstWP-1), thisLink.Points.end());
SendPathSpline(me, partial);
TC_LOG_DEBUG("movement.splinechain", "%s: Resumed spline chain generator from resume state.", me->GetGUID().ToString().c_str());
++_nextIndex;
if (!_msToNext)
_msToNext = 1;
_nextFirstWP = 0;
}
else
{
_msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
SendSplineFor(me, _nextIndex, _msToNext);
++_nextIndex;
if (_nextIndex >= _chainSize)
_msToNext = 0;
}
}
else
{
TC_LOG_ERROR("movement", "SplineChainMovementGenerator::Initialize - empty spline chain passed for %s.", me->GetGUID().ToString().c_str());
}
}
void SplineChainMovementGenerator::Finalize(Unit* me)
{
if (!finished)
return;
Creature* cMe = me->ToCreature();
if (cMe && cMe->IsAIEnabled)
cMe->AI()->MovementInform(SPLINE_CHAIN_MOTION_TYPE, _id);
}
bool SplineChainMovementGenerator::Update(Unit* me, uint32 diff)
{
if (finished)
return false;
// _msToNext being zero here means we're on the final spline
if (!_msToNext)
{
finished = me->movespline->Finalized();
return !finished;
}
if (_msToNext <= diff)
{
// Send next spline
TC_LOG_DEBUG("movement.splinechain", "%s: Should send spline %u (%u ms late).", me->GetGUID().ToString().c_str(), _nextIndex, diff - _msToNext);
_msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
SendSplineFor(me, _nextIndex, _msToNext);
++_nextIndex;
if (_nextIndex >= _chainSize)
{
// We have reached the final spline, once it finalizes we should also finalize the movegen (start checking on next update)
_msToNext = 0;
return true;
}
}
else
_msToNext -= diff;
return true;
}
SplineChainResumeInfo SplineChainMovementGenerator::GetResumeInfo(Unit const* me) const
{
if (!_nextIndex)
return SplineChainResumeInfo(_id, &_chain, _walk, 0, 0, _msToNext);
if (me->movespline->Finalized())
return SplineChainResumeInfo(_id, &_chain, _walk, _nextIndex, 0, 1u);
return SplineChainResumeInfo(_id, &_chain, _walk, uint8(_nextIndex - 1), uint8(me->movespline->_currentSplineIdx()), _msToNext);
}
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* 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 TRINITY_SPLINECHAINMOVEMENTGENERATOR_H
#define TRINITY_SPLINECHAINMOVEMENTGENERATOR_H
#include "SplineChain.h"
#include "MovementGenerator.h"
class TC_GAME_API SplineChainMovementGenerator : public MovementGenerator
{
public:
explicit SplineChainMovementGenerator(uint32 id, SplineChain const& chain, bool walk = false) : _id(id), _chain(chain), _chainSize(chain.size()), _walk(walk), finished(false), _nextIndex(0), _nextFirstWP(0), _msToNext(0) { }
explicit SplineChainMovementGenerator(SplineChainResumeInfo const& info) : _id(info.PointID), _chain(*info.Chain), _chainSize(info.Chain->size()), _walk(info.IsWalkMode), finished(info.SplineIndex >= info.Chain->size()), _nextIndex(info.SplineIndex), _nextFirstWP(info.PointIndex), _msToNext(info.TimeToNext) { }
void Initialize(Unit* me) override;
void Finalize(Unit* me) override;
void Reset(Unit* /*me*/) override { };
bool Update(Unit* me, uint32 diff) override;
MovementGeneratorType GetMovementGeneratorType() const override { return SPLINE_CHAIN_MOTION_TYPE; }
// Builds info that can later be used to resume this spline chain movement at the current position
SplineChainResumeInfo GetResumeInfo(Unit const* me) const;
private:
void SendSplineFor(Unit* me, uint32 index, uint32& toNext);
uint32 SendPathSpline(Unit* me, Movement::PointsArray const& wp) const;
uint32 const _id;
SplineChain const& _chain;
uint8 const _chainSize;
bool const _walk;
bool finished;
uint8 _nextIndex;
uint8 _nextFirstWP; // only used for resuming
uint32 _msToNext;
};
#endif
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* 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 TRINITY_SPLINECHAIN_H
#define TRINITY_SPLINECHAIN_H
#include "MoveSplineInitArgs.h"
struct TC_GAME_API SplineChainLink
{
SplineChainLink(Movement::PointsArray const& points, uint32 expectedDuration, uint32 msToNext) : Points(points), ExpectedDuration(expectedDuration), TimeToNext(msToNext) { }
template <typename iteratorType> SplineChainLink(iteratorType begin, iteratorType end, uint32 expectedDuration, uint32 msToNext) : Points(begin, end), ExpectedDuration(expectedDuration), TimeToNext(msToNext) { }
SplineChainLink(uint32 expectedDuration, uint32 msToNext) : Points(), ExpectedDuration(expectedDuration), TimeToNext(msToNext) { }
Movement::PointsArray Points;
uint32 ExpectedDuration;
uint32 TimeToNext;
};
typedef std::vector<SplineChainLink> SplineChain;
struct TC_GAME_API SplineChainResumeInfo
{
SplineChainResumeInfo(uint32 id, SplineChain const* chain, bool walk, uint8 splineIndex, uint8 wpIndex, uint32 msToNext) :
PointID(id), Chain(chain), IsWalkMode(walk), SplineIndex(splineIndex), PointIndex(wpIndex), TimeToNext(msToNext) { }
uint32 PointID;
SplineChain const* Chain;
bool IsWalkMode;
uint8 SplineIndex;
uint8 PointIndex;
uint32 TimeToNext;
};
#endif
+1
View File
@@ -1113,6 +1113,7 @@ void ScriptMgr::Unload()
void ScriptMgr::LoadDatabase()
{
sScriptSystemMgr->LoadScriptWaypoints();
sScriptSystemMgr->LoadScriptSplineChains();
}
void ScriptMgr::FillSpellSummary()
+72 -6
View File
@@ -21,8 +21,6 @@
#include "DatabaseEnv.h"
#include "ScriptMgr.h"
TC_GAME_API ScriptPointVector const SystemMgr::_empty;
SystemMgr* SystemMgr::instance()
{
static SystemMgr instance;
@@ -53,7 +51,6 @@ void SystemMgr::LoadScriptWaypoints()
TC_LOG_INFO("server.loading", ">> Loaded 0 Script Waypoints. DB table `script_waypoint` is empty.");
return;
}
uint32 count = 0;
do
@@ -62,7 +59,7 @@ void SystemMgr::LoadScriptWaypoints()
ScriptPointMove temp;
temp.uiCreatureEntry = pFields[0].GetUInt32();
uint32 uiEntry = temp.uiCreatureEntry;
uint32 uiEntry = temp.uiCreatureEntry;
temp.uiPointId = pFields[1].GetUInt32();
temp.fX = pFields[2].GetFloat();
temp.fY = pFields[3].GetFloat();
@@ -82,8 +79,77 @@ void SystemMgr::LoadScriptWaypoints()
m_mPointMoveMap[uiEntry].push_back(temp);
++count;
}
while (result->NextRow());
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u Script Waypoint nodes in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SystemMgr::LoadScriptSplineChains()
{
uint32 oldMSTime = getMSTime();
m_mSplineChainsMap.clear();
// 0 1 2 3 4
QueryResult resultMeta = WorldDatabase.Query("SELECT entry, chainId, splineId, expectedDuration, msUntilNext FROM script_spline_chain_meta ORDER BY entry asc, chainId asc, splineId asc");
// 0 1 2 3 4 5 6
QueryResult resultWP = WorldDatabase.Query("SELECT entry, chainId, splineId, wpId, x, y, z FROM script_spline_chain_waypoints ORDER BY entry asc, chainId asc, splineId asc, wpId asc");
if (!resultMeta || !resultWP)
{
TC_LOG_INFO("server.loading", ">> Loaded spline chain data for 0 chains, consisting of 0 splines with 0 waypoints. DB tables `script_spline_chain_meta` and `script_spline_chain_waypoints` are empty.");
}
else
{
uint32 chainCount = 0, splineCount = 0, wpCount = 0;
do
{
Field* fieldsMeta = resultMeta->Fetch();
uint32 entry = fieldsMeta[0].GetUInt32();
uint8 chainId = fieldsMeta[1].GetUInt8(), splineId = fieldsMeta[2].GetUInt8();
SplineChain& chain = m_mSplineChainsMap[{entry,chainId}];
if (splineId != chain.size())
{
TC_LOG_WARN("server.loading", "Creature #%u: Chain %u has orphaned spline %u, skipped.", entry, chainId, splineId);
continue;
}
uint32 expectedDuration = fieldsMeta[3].GetUInt32(), msUntilNext = fieldsMeta[4].GetUInt32();
chain.push_back(SplineChainLink(expectedDuration, msUntilNext));
if (splineId == 0)
++chainCount;
++splineCount;
} while (resultMeta->NextRow());
do
{
Field* fieldsWP = resultWP->Fetch();
uint32 entry = fieldsWP[0].GetUInt32();
uint8 chainId = fieldsWP[1].GetUInt8(), splineId = fieldsWP[2].GetUInt8(), wpId = fieldsWP[3].GetUInt8();
float posX = fieldsWP[4].GetFloat(), posY = fieldsWP[5].GetFloat(), posZ = fieldsWP[6].GetFloat();
auto it = m_mSplineChainsMap.find({entry,chainId});
if (it == m_mSplineChainsMap.end())
{
TC_LOG_WARN("server.loading", "Creature #%u has waypoint data for spline chain %u. No such chain exists - entry skipped.", entry, chainId);
continue;
}
SplineChain& chain = it->second;
if (splineId >= chain.size())
{
TC_LOG_WARN("server.loading", "Creature #%u has waypoint data for spline (%u,%u). The specified chain does not have a spline with this index - entry skipped.", entry, chainId, splineId);
continue;
}
SplineChainLink& spline = chain[splineId];
if (wpId != spline.Points.size())
{
TC_LOG_WARN("server.loading", "Creature #%u has orphaned waypoint data in spline (%u,%u) at index %u. Skipped.", entry, chainId, splineId, wpId);
continue;
}
spline.Points.emplace_back(posX, posY, posZ);
++wpCount;
} while (resultWP->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded spline chain data for %u chains, consisting of %u splines with %u waypoints in %u ms", chainCount, splineCount, wpCount, GetMSTimeDiffToNow(oldMSTime));
}
}
+19 -6
View File
@@ -58,22 +58,35 @@ class TC_GAME_API SystemMgr
//Database
void LoadScriptWaypoints();
void LoadScriptSplineChains();
ScriptPointVector const& GetPointMoveList(uint32 creatureEntry) const
ScriptPointVector const* GetPointMoveList(uint32 creatureEntry) const
{
PointMoveMap::const_iterator itr = m_mPointMoveMap.find(creatureEntry);
if (itr == m_mPointMoveMap.end())
return _empty;
return nullptr;
return itr->second;
return &itr->second;
}
SplineChain const* GetSplineChain(uint32 entry, uint8 id) const
{
auto it = m_mSplineChainsMap.find({ entry, id });
if (it == m_mSplineChainsMap.end())
return nullptr;
return &it->second;
}
SplineChain const* GetSplineChain(Creature const* who, uint8 id) const
{
return GetSplineChain(who->GetEntry(), id);
}
protected:
PointMoveMap m_mPointMoveMap; //coordinates for waypoints
private:
static ScriptPointVector const _empty;
typedef std::pair<uint32, uint8> ChainKeyType; // creature entry + chain ID
std::unordered_map<ChainKeyType, SplineChain> m_mSplineChainsMap; // spline chains
};
#define sScriptSystemMgr SystemMgr::instance()
@@ -1272,6 +1272,7 @@ class npc_crate_helper : public CreatureScript
}
};
void AddSC_culling_of_stratholme()
{
new npc_arthas();