root/trunk/src/game/WaypointManager.cpp @ 268

Revision 263, 12.6 kB (checked in by yumileroy, 17 years ago)

Some missing changes. This should fix the bug that loading char causes crash.
Please do not commit to the other tip (I do not know how to delete it).

Original author: megamage
Date: 2008-11-20 17:40:13-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            // load and store without holes in array
128            int j = 0;
129            for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
130            {
131                be.textid[j]        = fields[9+i].GetUInt32();
132                if(be.textid[j])
133                {
134                    if (be.textid[j] < MIN_DB_SCRIPT_STRING_ID || be.textid[j] >= MAX_DB_SCRIPT_STRING_ID)
135                    {
136                        sLog.outErrorDb( "Table `db_script_string` not have string id  %u", be.textid[j]);
137                        continue;
138                    }
139
140                    if (!objmgr.GetTrinityStringLocale (be.textid[j]))
141                    {
142                        sLog.outErrorDb("ERROR: Waypoint path %d (point %d), have invalid text id (%i) in `textid%d, ignored.",
143                            id, point, be.textid[j], i+1);
144                        continue;
145                    }
146
147                    ++j;                                    // to next internal field
148                }
149            }
150            // fill array tail
151            for(; j < MAX_WAYPOINT_TEXT; ++j)
152                be.textid[j] = 0;
153
154            // save memory by not storing empty behaviors
155            if(!be.isEmpty())
156            {
157                node.behavior   = new WaypointBehavior(be);
158                ++total_behaviors;
159            }
160            else
161                node.behavior   = NULL;
162            bar.step();
163        } while( result->NextRow() );
164        delete result;
165    }
166    sLog.outString( ">> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
167}
168
169void WaypointManager::Cleanup()
170{
171    // check if points need to be renumbered and do it
172    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"))
173    {
174        delete result;
175        WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
176        WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
177        WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
178        WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
179        WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
180        WorldDatabase.DirectExecute("DROP TABLE temp");
181        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")));
182    }
183}
184
185void WaypointManager::Unload()
186{
187    for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
188        _clearPath(itr->second);
189    m_pathMap.clear();
190}
191
192void WaypointManager::_clearPath(WaypointPath &path)
193{
194    for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr)
195        if(itr->behavior)
196            delete itr->behavior;
197    path.clear();
198}
199
200/// - Insert after the last point
201void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
202{
203    _addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid);
204}
205
206/// - Insert after a certain point
207void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
208{
209    for(uint32 i = GetLastPoint(id, 0); i > point; i--)
210        WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i);
211
212    _addNode(id, point + 1, x, y, z, o, delay, wpGuid);
213}
214
215/// - Insert without checking for collision
216void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
217{
218    if(point == 0) return;                                  // counted from 1 in the DB
219    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);
220    WaypointPathMap::iterator itr = m_pathMap.find(id);
221    if(itr == m_pathMap.end())
222        itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
223    itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL));
224}
225
226uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
227{
228    uint32 point = default_notfound;
229    /*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
230    if( result )
231    {
232        point = (*result)[0].GetUInt32()+1;
233        delete result;
234    }*/
235    WaypointPathMap::iterator itr = m_pathMap.find(id);
236    if(itr != m_pathMap.end() && itr->second.size() != 0)
237        point = itr->second.size();
238    return point;
239}
240
241void WaypointManager::DeleteNode(uint32 id, uint32 point)
242{
243    if(point == 0) return;                                  // counted from 1 in the DB
244    WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point);
245    WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point);
246    WaypointPathMap::iterator itr = m_pathMap.find(id);
247    if(itr != m_pathMap.end() && point <= itr->second.size())
248        itr->second.erase(itr->second.begin() + (point-1));
249}
250
251void WaypointManager::DeletePath(uint32 id)
252{
253    WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id);
254    WaypointPathMap::iterator itr = m_pathMap.find(id);
255    if(itr != m_pathMap.end())
256        _clearPath(itr->second);
257    // the path is not removed from the map, just cleared
258    // WMGs have pointers to the path, so deleting them would crash
259    // this wastes some memory, but these functions are
260    // only meant to be called by GM commands
261}
262
263void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
264{
265    if(point == 0) return;                                  // counted from 1 in the DB
266    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);
267    WaypointPathMap::iterator itr = m_pathMap.find(id);
268    if(itr != m_pathMap.end() && point <= itr->second.size())
269    {
270        itr->second[point-1].x = x;
271        itr->second[point-1].y = y;
272        itr->second[point-1].z = z;
273    }
274}
275
276void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text)
277{
278    if(point == 0) return;                                  // counted from 1 in the DB
279    if(!text_field) return;
280    std::string field = text_field;
281    WorldDatabase.escape_string(field);
282
283    if(!text)
284    {
285        WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point);
286    }
287    else
288    {
289        std::string text2 = text;
290        WorldDatabase.escape_string(text2);
291        WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point);
292    }
293
294    WaypointPathMap::iterator itr = m_pathMap.find(id);
295    if(itr != m_pathMap.end() && point <= itr->second.size())
296    {
297        WaypointNode &node = itr->second[point-1];
298        if(!node.behavior) node.behavior = new WaypointBehavior();
299
300//        if(field == "text1") node.behavior->text[0] = text ? text : "";
301//        if(field == "text2") node.behavior->text[1] = text ? text : "";
302//        if(field == "text3") node.behavior->text[2] = text ? text : "";
303//        if(field == "text4") node.behavior->text[3] = text ? text : "";
304//        if(field == "text5") node.behavior->text[4] = text ? text : "";
305        if(field == "emote") node.behavior->emote   = text ? atoi(text) : 0;
306        if(field == "spell") node.behavior->spell   = text ? atoi(text) : 0;
307        if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0;
308        if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0;
309    }
310}
Note: See TracBrowser for help on using the browser.