[12672] Improve Waypoint Management

* Allow waypoints that have point-ids not from 1 to n
* Remove possibly bad sql-statements to "fix" the above property
* Simplify code a little bit

Remaining TODO: Bring commands up-to-date and also make things more simple instead of using the database to store visual waypoints
This commit is contained in:
Schmoozerd 2013-08-19 16:27:01 +03:00 committed by Antz
parent 5083596e26
commit e269f49f8e
5 changed files with 70 additions and 115 deletions

View file

@ -3635,7 +3635,8 @@ bool ChatHandler::HandleWpShowCommand(char* args)
uint32 model2 = fields[11].GetUInt32(); uint32 model2 = fields[11].GetUInt32();
// Get the creature for which we read the waypoint // Get the creature for which we read the waypoint
Creature* wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(ObjectGuid(HIGHGUID_UNIT, VISUAL_WAYPOINT, wpGuid)); CreatureData const* data = sObjectMgr.GetCreatureData(wpGuid);
Creature* wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(data ? data->GetObjectGuid(wpGuid) : ObjectGuid(HIGHGUID_UNIT, VISUAL_WAYPOINT, wpGuid));
PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : "<not found>"), wpGuid); PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : "<not found>"), wpGuid);
PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime); PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime);

View file

@ -51,8 +51,6 @@ WaypointBehavior::WaypointBehavior(const WaypointBehavior& b)
void WaypointManager::Load() void WaypointManager::Load()
{ {
Cleanup();
uint32 total_paths = 0; uint32 total_paths = 0;
uint32 total_nodes = 0; uint32 total_nodes = 0;
uint32 total_behaviors = 0; uint32 total_behaviors = 0;
@ -85,7 +83,6 @@ void WaypointManager::Load()
uint32 id = fields[0].GetUInt32(); uint32 id = fields[0].GetUInt32();
uint32 count = fields[1].GetUInt32(); uint32 count = fields[1].GetUInt32();
m_pathMap[id].resize(count);
total_nodes += count; total_nodes += count;
} }
while (result->NextRow()); while (result->NextRow());
@ -124,11 +121,7 @@ void WaypointManager::Load()
creatureNoMoveType.insert(id); creatureNoMoveType.insert(id);
WaypointPath& path = m_pathMap[id]; WaypointPath& path = m_pathMap[id];
WaypointNode& node = path[point];
// the cleanup queries make sure the following is true
MANGOS_ASSERT(point >= 1 && point <= path.size());
WaypointNode& node = path[point - 1];
node.x = fields[2].GetFloat(); node.x = fields[2].GetFloat();
node.y = fields[3].GetFloat(); node.y = fields[3].GetFloat();
@ -263,7 +256,6 @@ void WaypointManager::Load()
uint32 entry = fields[0].GetUInt32(); uint32 entry = fields[0].GetUInt32();
uint32 count = fields[1].GetUInt32(); uint32 count = fields[1].GetUInt32();
m_pathTemplateMap[entry].resize(count);
total_nodes += count; total_nodes += count;
} }
while (result->NextRow()); while (result->NextRow());
@ -297,11 +289,7 @@ void WaypointManager::Load()
} }
WaypointPath& path = m_pathTemplateMap[entry]; WaypointPath& path = m_pathTemplateMap[entry];
WaypointNode& node = path[point];
// the cleanup queries make sure the following is true
MANGOS_ASSERT(point >= 1 && point <= path.size());
WaypointNode& node = path[point - 1];
node.x = fields[2].GetFloat(); node.x = fields[2].GetFloat();
node.y = fields[3].GetFloat(); node.y = fields[3].GetFloat();
@ -394,40 +382,6 @@ void WaypointManager::Load()
} }
} }
void WaypointManager::Cleanup()
{
// check if points need to be renumbered and do it
if (QueryResult* result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
{
delete result;
WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
WorldDatabase.DirectExecute("DROP TABLE temp");
sLog.outErrorDb("Table `creature_movement` was auto corrected for using points out of order (invalid or points missing)");
MANGOS_ASSERT(!(result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1")));
}
if (QueryResult* result = WorldDatabase.Query("SELECT 1 from creature_movement_template As T WHERE point <> (SELECT COUNT(*) FROM creature_movement_template WHERE entry = T.entry AND point <= T.point) LIMIT 1"))
{
delete result;
WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement_template");
WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement_template");
WorldDatabase.DirectExecute("ALTER TABLE creature_movement_template DROP PRIMARY KEY");
WorldDatabase.DirectExecute("UPDATE creature_movement_template AS T SET point = (SELECT COUNT(*) FROM temp WHERE entry = T.entry AND point <= T.point)");
WorldDatabase.DirectExecute("ALTER TABLE creature_movement_template ADD PRIMARY KEY (entry, point)");
WorldDatabase.DirectExecute("DROP TABLE temp");
sLog.outErrorDb("Table `creature_movement_template` was auto corrected for using points out of order (invalid or points missing)");
MANGOS_ASSERT(!(result = WorldDatabase.Query("SELECT 1 from creature_movement_template As T WHERE point <> (SELECT COUNT(*) FROM creature_movement_template WHERE entry = T.entry AND point <= T.point) LIMIT 1")));
}
}
void WaypointManager::Unload() void WaypointManager::Unload()
{ {
for (WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr) for (WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
@ -442,7 +396,7 @@ void WaypointManager::Unload()
void WaypointManager::_clearPath(WaypointPath& path) void WaypointManager::_clearPath(WaypointPath& path)
{ {
for (WaypointPath::const_iterator itr = path.begin(); itr != path.end(); ++itr) for (WaypointPath::const_iterator itr = path.begin(); itr != path.end(); ++itr)
delete itr->behavior; delete itr->second.behavior;
path.clear(); path.clear();
} }
@ -464,39 +418,31 @@ void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, fl
/// - Insert without checking for collision /// - Insert without checking for collision
void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid) void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
{ {
if (point == 0) return; // counted from 1 in the DB
WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) " WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) "
"VALUES (%u,%u, %f,%f,%f,%f, %u,%u)", "VALUES (%u,%u, %f,%f,%f,%f, %u,%u)",
id, point, x, y, z, o, wpGuid, delay); id, point, x, y, z, o, wpGuid, delay);
WaypointPathMap::iterator itr = m_pathMap.find(id);
if (itr == m_pathMap.end()) m_pathMap[id][point] = WaypointNode(x, y, z, o, delay, 0, NULL);
itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, 0, NULL));
} }
uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound) uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
{ {
uint32 point = default_notfound;
/*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
if( result )
{
point = (*result)[0].GetUInt32()+1;
delete result;
}*/
WaypointPathMap::const_iterator itr = m_pathMap.find(id); WaypointPathMap::const_iterator itr = m_pathMap.find(id);
if (itr != m_pathMap.end() && itr->second.size() != 0) if (itr != m_pathMap.end() && itr->second.rbegin() != itr->second.rend())
point = itr->second.size(); default_notfound = itr->second.rbegin()->first;
return point;
return default_notfound;
} }
void WaypointManager::DeleteNode(uint32 id, uint32 point) void WaypointManager::DeleteNode(uint32 id, uint32 point)
{ {
if (point == 0) return; // counted from 1 in the DB
WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id=%u AND point=%u", id, point); WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id=%u AND point=%u", id, point);
WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id=%u AND point>%u", id, point); WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id=%u AND point>%u", id, point);
WaypointPathMap::iterator itr = m_pathMap.find(id); WaypointPathMap::iterator itr = m_pathMap.find(id);
if (itr != m_pathMap.end() && point <= itr->second.size()) if (itr == m_pathMap.end())
itr->second.erase(itr->second.begin() + (point - 1)); return;
itr->second.erase(point);
} }
void WaypointManager::DeletePath(uint32 id) void WaypointManager::DeletePath(uint32 id)
@ -513,20 +459,22 @@ void WaypointManager::DeletePath(uint32 id)
void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z) void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
{ {
if (point == 0) return; // counted from 1 in the DB
WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x=%f, position_y=%f, position_z=%f WHERE id=%u AND point=%u", x, y, z, id, point); WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x=%f, position_y=%f, position_z=%f WHERE id=%u AND point=%u", x, y, z, id, point);
WaypointPathMap::iterator itr = m_pathMap.find(id); WaypointPathMap::iterator itr = m_pathMap.find(id);
if (itr != m_pathMap.end() && point <= itr->second.size()) if (itr == m_pathMap.end())
return;
WaypointPath::iterator find = itr->second.find(point);
if (find != itr->second.end())
{ {
itr->second[point - 1].x = x; find->second.x = x;
itr->second[point - 1].y = y; find->second.y = y;
itr->second[point - 1].z = z; find->second.z = z;
} }
} }
void WaypointManager::SetNodeText(uint32 id, uint32 point, const char* text_field, const char* text) void WaypointManager::SetNodeText(uint32 id, uint32 point, const char* text_field, const char* text)
{ {
if (point == 0) return; // counted from 1 in the DB
if (!text_field) return; if (!text_field) return;
std::string field = text_field; std::string field = text_field;
WorldDatabase.escape_string(field); WorldDatabase.escape_string(field);
@ -543,9 +491,13 @@ void WaypointManager::SetNodeText(uint32 id, uint32 point, const char* text_fiel
} }
WaypointPathMap::iterator itr = m_pathMap.find(id); WaypointPathMap::iterator itr = m_pathMap.find(id);
if (itr != m_pathMap.end() && point <= itr->second.size()) if (itr == m_pathMap.end())
return;
WaypointPath::iterator find = itr->second.find(point);
if (find != itr->second.end())
{ {
WaypointNode& node = itr->second[point - 1]; WaypointNode& node = find->second;
if (!node.behavior) node.behavior = new WaypointBehavior(); if (!node.behavior) node.behavior = new WaypointBehavior();
// if(field == "text1") node.behavior->text[0] = text ? text : ""; // if(field == "text1") node.behavior->text[0] = text ? text : "";
@ -560,7 +512,7 @@ void WaypointManager::SetNodeText(uint32 id, uint32 point, const char* text_fiel
} }
} }
inline void CheckWPText(bool isTemplate, uint32 entryOrGuid, size_t point, WaypointBehavior* be, std::set<int32>& ids) inline void CheckWPText(bool isTemplate, uint32 entryOrGuid, uint32 point, WaypointBehavior* be, std::set<int32>& ids)
{ {
int zeroCount = 0; // Counting leading zeros for futher textid shift int zeroCount = 0; // Counting leading zeros for futher textid shift
for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j) for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j)
@ -573,7 +525,7 @@ inline void CheckWPText(bool isTemplate, uint32 entryOrGuid, size_t point, Waypo
if (!sObjectMgr.GetMangosStringLocale(be->textid[j])) if (!sObjectMgr.GetMangosStringLocale(be->textid[j]))
{ {
sLog.outErrorDb("Table `creature_movement%s %u, PointId %u has textid%u with non existing textid %i.", sLog.outErrorDb("Table `creature_movement%s %u, PointId %u has textid%u with non existing textid %i.",
isTemplate ? "_template` Entry:" : "` Id:", entryOrGuid, point + 1, j, be->textid[j]); isTemplate ? "_template` Entry:" : "` Id:", entryOrGuid, point, j, be->textid[j]);
be->textid[j] = 0; be->textid[j] = 0;
++zeroCount; ++zeroCount;
continue; continue;
@ -594,15 +546,15 @@ void WaypointManager::CheckTextsExistance(std::set<int32>& ids)
{ {
for (WaypointPathMap::const_iterator pmItr = m_pathMap.begin(); pmItr != m_pathMap.end(); ++pmItr) for (WaypointPathMap::const_iterator pmItr = m_pathMap.begin(); pmItr != m_pathMap.end(); ++pmItr)
{ {
for (size_t i = 0; i < pmItr->second.size(); ++i) for (WaypointPath::const_iterator pItr = pmItr->second.begin(); pItr != pmItr->second.end(); ++pItr)
if (pmItr->second[i].behavior) if (pItr->second.behavior)
CheckWPText(false, pmItr->first, i, pmItr->second[i].behavior, ids); CheckWPText(false, pmItr->first, pItr->first, pItr->second.behavior, ids);
} }
for (WaypointPathMap::const_iterator wptItr = m_pathTemplateMap.begin(); wptItr != m_pathTemplateMap.end(); ++wptItr) for (WaypointPathMap::const_iterator pmItr = m_pathTemplateMap.begin(); pmItr != m_pathTemplateMap.end(); ++pmItr)
{ {
for (size_t i = 0; i < wptItr->second.size(); ++i) for (WaypointPath::const_iterator pItr = pmItr->second.begin(); pItr != pmItr->second.end(); ++pItr)
if (wptItr->second[i].behavior) if (pItr->second.behavior)
CheckWPText(true, wptItr->first, i, wptItr->second[i].behavior, ids); CheckWPText(false, pmItr->first, pItr->first, pItr->second.behavior, ids);
} }
} }

View file

@ -53,7 +53,7 @@ struct WaypointNode
: x(_x), y(_y), z(_z), orientation(_o), delay(_delay), script_id(_script_id), behavior(_behavior) {} : x(_x), y(_y), z(_z), orientation(_o), delay(_delay), script_id(_script_id), behavior(_behavior) {}
}; };
typedef std::vector<WaypointNode> WaypointPath; typedef std::map<uint32 /*pointId*/, WaypointNode> WaypointPath;
class WaypointManager class WaypointManager
{ {
@ -64,8 +64,6 @@ class WaypointManager
void Load(); void Load();
void Unload(); void Unload();
void Cleanup();
WaypointPath* GetPath(uint32 id) WaypointPath* GetPath(uint32 id)
{ {
WaypointPathMap::iterator itr = m_pathMap.find(id); WaypointPathMap::iterator itr = m_pathMap.find(id);
@ -91,7 +89,7 @@ class WaypointManager
void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid); void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
void _clearPath(WaypointPath& path); void _clearPath(WaypointPath& path);
typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap; typedef UNORDERED_MAP<uint32 /*guidOrEntry*/, WaypointPath> WaypointPathMap;
WaypointPathMap m_pathMap; WaypointPathMap m_pathMap;
WaypointPathMap m_pathTemplateMap; WaypointPathMap m_pathTemplateMap;
}; };

View file

@ -16,20 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/*
creature_movement Table
alter table creature_movement add `textid1` int(11) NOT NULL default '0';
alter table creature_movement add `textid2` int(11) NOT NULL default '0';
alter table creature_movement add `textid3` int(11) NOT NULL default '0';
alter table creature_movement add `textid4` int(11) NOT NULL default '0';
alter table creature_movement add `textid5` int(11) NOT NULL default '0';
alter table creature_movement add `emote` int(10) unsigned default '0';
alter table creature_movement add `spell` int(5) unsigned default '0';
alter table creature_movement add `wpguid` int(11) default '0';
*/
#include <ctime> #include <ctime>
#include "WaypointMovementGenerator.h" #include "WaypointMovementGenerator.h"
@ -76,6 +62,11 @@ void WaypointMovementGenerator<Creature>::LoadPath(Creature& creature)
return; return;
} }
} }
// Initialize the i_currentNode to point to the first node
if (i_path->empty())
return;
i_currentNode = i_path->begin()->first;
} }
void WaypointMovementGenerator<Creature>::Initialize(Creature& creature) void WaypointMovementGenerator<Creature>::Initialize(Creature& creature)
@ -119,14 +110,18 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
m_isArrivalDone = true; m_isArrivalDone = true;
if (i_path->at(i_currentNode).script_id) WaypointPath::const_iterator currPoint = i_path->find(i_currentNode);
MANGOS_ASSERT(currPoint != i_path->end());
WaypointNode const& node = currPoint->second;
if (node.script_id)
{ {
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetGuidStr().c_str()); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", node.script_id, i_currentNode, creature.GetGuidStr().c_str());
creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(i_currentNode).script_id, &creature, &creature); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, node.script_id, &creature, &creature);
} }
// We have reached the destination and can process behavior // We have reached the destination and can process behavior
if (WaypointBehavior* behavior = i_path->at(i_currentNode).behavior) if (WaypointBehavior* behavior = node.behavior)
{ {
if (behavior->emote != 0) if (behavior->emote != 0)
creature.HandleEmote(behavior->emote); creature.HandleEmote(behavior->emote);
@ -159,7 +154,7 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
// Inform script // Inform script
MovementInform(creature); MovementInform(creature);
Stop(i_path->at(i_currentNode).delay); Stop(node.delay);
} }
void WaypointMovementGenerator<Creature>::StartMoveNow(Creature& creature) void WaypointMovementGenerator<Creature>::StartMoveNow(Creature& creature)
@ -177,7 +172,10 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature& creature)
if (Stopped(creature)) if (Stopped(creature))
return; return;
if (WaypointBehavior* behavior = i_path->at(i_currentNode).behavior) WaypointPath::const_iterator currPoint = i_path->find(i_currentNode);
MANGOS_ASSERT(currPoint != i_path->end());
if (WaypointBehavior* behavior = currPoint->second.behavior)
{ {
if (behavior->model2 != 0) if (behavior->model2 != 0)
creature.SetDisplayId(behavior->model2); creature.SetDisplayId(behavior->model2);
@ -185,18 +183,24 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature& creature)
} }
if (m_isArrivalDone) if (m_isArrivalDone)
i_currentNode = (i_currentNode + 1) % i_path->size(); {
++currPoint;
if (currPoint == i_path->end())
currPoint = i_path->begin();
i_currentNode = currPoint->first;
}
m_isArrivalDone = false; m_isArrivalDone = false;
creature.addUnitState(UNIT_STAT_ROAMING_MOVE); creature.addUnitState(UNIT_STAT_ROAMING_MOVE);
const WaypointNode& node = i_path->at(i_currentNode); WaypointNode const& nextNode = currPoint->second;;
Movement::MoveSplineInit init(creature); Movement::MoveSplineInit init(creature);
init.MoveTo(node.x, node.y, node.z, true); init.MoveTo(nextNode.x, nextNode.y, nextNode.z, true);
if (node.orientation != 100 && node.delay != 0) if (nextNode.orientation != 100 && nextNode.delay != 0)
init.SetFacing(node.orientation); init.SetFacing(nextNode.orientation);
creature.SetWalk(!creature.hasUnitState(UNIT_STAT_RUNNING_STATE) && !creature.IsLevitating(), false); creature.SetWalk(!creature.hasUnitState(UNIT_STAT_RUNNING_STATE) && !creature.IsLevitating(), false);
init.Launch(); init.Launch();
} }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "12671" #define REVISION_NR "12672"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__