root/trunk/src/game/WaypointManager.cpp

Revision 293, 13.7 kB (checked in by yumileroy, 17 years ago)

*Fix a typo.

Original author: megamage
Date: 2008-11-22 11:05:07-06:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "Database/DatabaseEnv.h"
22#include "GridDefines.h"
23#include "Policies/SingletonImp.h"
24#include "WaypointManager.h"
25#include "ProgressBar.h"
26#include "MapManager.h"
27#include "ObjectMgr.h"
28
29INSTANTIATE_SINGLETON_1(WaypointManager);
30
31bool WaypointBehavior::isEmpty()
32{
33    if (emote || spell || model1 || model2)
34        return false;
35
36    for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
37        if(textid[i])
38            return false;
39
40    return true;
41}
42
43WaypointBehavior::WaypointBehavior(const WaypointBehavior &b)
44{
45    emote = b.emote;
46    spell = b.spell;
47    model1 = b.model1;
48    model2 = b.model2;
49    for(int i=0; i < MAX_WAYPOINT_TEXT; ++i)
50        textid[i] = b.textid[i];
51}
52
53void WaypointManager::Load()
54{
55    Cleanup();
56
57    uint32 total_paths = 0;
58    uint32 total_nodes = 0;
59    uint32 total_behaviors = 0;
60
61    QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
62    if(result)
63    {
64        total_paths = result->GetRowCount();
65        barGoLink bar( total_paths );
66        do
67        {
68            Field *fields = result->Fetch();
69            uint32 id    = fields[0].GetUInt32();
70            uint32 count = fields[1].GetUInt32();
71            m_pathMap[id].resize(count);
72
73            total_nodes += count;
74            bar.step();
75        } while( result->NextRow() );
76        delete result;
77    }
78
79    result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement");
80    if(result)
81    {
82        barGoLink bar( result->GetRowCount() );
83        do
84        {
85            Field *fields = result->Fetch();
86            uint32 point        = fields[15].GetUInt32();
87            uint32 id           = fields[14].GetUInt32();
88
89            WaypointPath &path  = m_pathMap[id];
90            // the cleanup queries make sure the following is true
91            assert(point >= 1 && point <= path.size());
92            WaypointNode &node  = path[point-1];
93
94            node.x              = fields[0].GetFloat();
95            node.y              = fields[1].GetFloat();
96            node.z              = fields[2].GetFloat();
97            node.orientation    = fields[3].GetFloat();
98            node.delay          = fields[6].GetUInt16();
99
100            // prevent using invalid coordinates
101            if(!Trinity::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
102            {
103                QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
104                if(result1)
105                    sLog.outErrorDb("ERROR: Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
106                        id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
107                else
108                    sLog.outErrorDb("ERROR: Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
109                        id, point, node.x, node.y);
110
111                Trinity::NormalizeMapCoord(node.x);
112                Trinity::NormalizeMapCoord(node.y);
113                if(result1)
114                {
115                    node.z = MapManager::Instance ().GetBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
116                    delete result1;
117                }
118                WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
119            }
120
121            WaypointBehavior be;
122            be.model1           = fields[4].GetUInt32();
123            be.model2           = fields[5].GetUInt32();
124            be.emote            = fields[7].GetUInt32();
125            be.spell            = fields[8].GetUInt32();
126
127            for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
128            {
129                be.textid[i]        = fields[9+i].GetUInt32();
130                if(be.textid[i])
131                {
132                    if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
133                    {
134                        sLog.outErrorDb( "Table `db_script_string` not have string id  %u", be.textid[i]);
135                        continue;
136                    }
137                }
138            }
139
140            // save memory by not storing empty behaviors
141            if(!be.isEmpty())
142            {
143                node.behavior   = new WaypointBehavior(be);
144                ++total_behaviors;
145            }
146            else
147                node.behavior   = NULL;
148            bar.step();
149        } while( result->NextRow() );
150        delete result;
151    }
152    sLog.outString( ">> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
153}
154
155void WaypointManager::Cleanup()
156{
157    // check if points need to be renumbered and do it
158    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"))
159    {
160        delete result;
161        WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
162        WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
163        WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
164        WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
165        WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
166        WorldDatabase.DirectExecute("DROP TABLE temp");
167        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")));
168    }
169}
170
171void WaypointManager::Unload()
172{
173    for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
174        _clearPath(itr->second);
175    m_pathMap.clear();
176}
177
178void WaypointManager::_clearPath(WaypointPath &path)
179{
180    for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr)
181        if(itr->behavior)
182            delete itr->behavior;
183    path.clear();
184}
185
186/// - Insert after the last point
187void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
188{
189    _addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid);
190}
191
192/// - Insert after a certain point
193void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
194{
195    for(uint32 i = GetLastPoint(id, 0); i > point; i--)
196        WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i);
197
198    _addNode(id, point + 1, x, y, z, o, delay, wpGuid);
199}
200
201/// - Insert without checking for collision
202void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
203{
204    if(point == 0) return;                                  // counted from 1 in the DB
205    WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) VALUES ('%u','%u','%f', '%f', '%f', '%f', '%d', '%d')", id, point, x, y, z, o, wpGuid, delay);
206    WaypointPathMap::iterator itr = m_pathMap.find(id);
207    if(itr == m_pathMap.end())
208        itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
209    itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL));
210}
211
212uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
213{
214    uint32 point = default_notfound;
215    /*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
216    if( result )
217    {
218        point = (*result)[0].GetUInt32()+1;
219        delete result;
220    }*/
221    WaypointPathMap::iterator itr = m_pathMap.find(id);
222    if(itr != m_pathMap.end() && itr->second.size() != 0)
223        point = itr->second.size();
224    return point;
225}
226
227void WaypointManager::DeleteNode(uint32 id, uint32 point)
228{
229    if(point == 0) return;                                  // counted from 1 in the DB
230    WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point);
231    WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point);
232    WaypointPathMap::iterator itr = m_pathMap.find(id);
233    if(itr != m_pathMap.end() && point <= itr->second.size())
234        itr->second.erase(itr->second.begin() + (point-1));
235}
236
237void WaypointManager::DeletePath(uint32 id)
238{
239    WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id);
240    WaypointPathMap::iterator itr = m_pathMap.find(id);
241    if(itr != m_pathMap.end())
242        _clearPath(itr->second);
243    // the path is not removed from the map, just cleared
244    // WMGs have pointers to the path, so deleting them would crash
245    // this wastes some memory, but these functions are
246    // only meant to be called by GM commands
247}
248
249void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
250{
251    if(point == 0) return;                                  // counted from 1 in the DB
252    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);
253    WaypointPathMap::iterator itr = m_pathMap.find(id);
254    if(itr != m_pathMap.end() && point <= itr->second.size())
255    {
256        itr->second[point-1].x = x;
257        itr->second[point-1].y = y;
258        itr->second[point-1].z = z;
259    }
260}
261
262void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text)
263{
264    if(point == 0) return;                                  // counted from 1 in the DB
265    if(!text_field) return;
266    std::string field = text_field;
267    WorldDatabase.escape_string(field);
268
269    if(!text)
270    {
271        WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point);
272    }
273    else
274    {
275        std::string text2 = text;
276        WorldDatabase.escape_string(text2);
277        WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point);
278    }
279
280    WaypointPathMap::iterator itr = m_pathMap.find(id);
281    if(itr != m_pathMap.end() && point <= itr->second.size())
282    {
283        WaypointNode &node = itr->second[point-1];
284        if(!node.behavior) node.behavior = new WaypointBehavior();
285
286//        if(field == "text1") node.behavior->text[0] = text ? text : "";
287//        if(field == "text2") node.behavior->text[1] = text ? text : "";
288//        if(field == "text3") node.behavior->text[2] = text ? text : "";
289//        if(field == "text4") node.behavior->text[3] = text ? text : "";
290//        if(field == "text5") node.behavior->text[4] = text ? text : "";
291        if(field == "emote") node.behavior->emote   = text ? atoi(text) : 0;
292        if(field == "spell") node.behavior->spell   = text ? atoi(text) : 0;
293        if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0;
294        if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0;
295    }
296}
297
298void WaypointManager::CheckTextsExistance(std::set<int32>& ids)
299{
300    WaypointPathMap::iterator pmItr = m_pathMap.begin();
301    for ( ; pmItr != m_pathMap.end(); ++pmItr)
302    {
303        for (int i = 0; i < pmItr->second.size(); ++i)
304        {
305            if (!pmItr->second[i].behavior)
306                continue;
307
308            // Now we check text existence and put all zero texts ids to the end of array
309
310            // Counting leading zeros for futher textid shift
311            int zeroCount = 0;
312            for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j)
313            {
314                if (!pmItr->second[i].behavior->textid[j])
315                {
316                    ++zeroCount;
317                    continue;
318                }
319                else
320                {
321                    if (!objmgr.GetTrinityStringLocale(pmItr->second[i].behavior->textid[j]))
322                    {
323                        sLog.outErrorDb("ERROR: Some waypoint has textid%u with not existing %u text.", j, pmItr->second[i].behavior->textid[j]);
324                        pmItr->second[i].behavior->textid[j] = 0;
325                        ++zeroCount;
326                        continue;
327                    }
328                    else
329                        ids.erase(pmItr->second[i].behavior->textid[j]);
330
331                    // Shifting check
332                    if (zeroCount)
333                    {
334                        // Correct textid but some zeros leading, so move it forward.
335                        pmItr->second[i].behavior->textid[j-zeroCount] = pmItr->second[i].behavior->textid[j];
336                        pmItr->second[i].behavior->textid[j] = 0;
337                    }
338                }
339            }
340        }
341    }
342}
Note: See TracBrowser for help on using the browser.