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

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

Merged commit 269 (5f0e38da128a).

Original author: gvcoman
Date: 2008-11-21 14:34:05-05: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.