Merge branch '164-crash-on-patching-and-possibly-right-after-login' into main/gingo...
[ryzomcore.git] / ryzom / client / src / 3d_notes.cpp
blobc53ac7ef1a37374f2c8a12c2e2ea55d03fab51ad
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
22 #include "3d_notes.h"
23 #include "client_cfg.h"
24 #include "init_main_loop.h"
25 #include "user_entity.h"
27 using namespace std;
28 using namespace NLMISC;
30 void cbNotesChanged()
32 nlinfo("cbNotesChanged called");
33 Notes.Notes.clear();
35 CConfigFile::CVar &var = Notes.NotesConfigFile.getVar("Notes");
36 for(sint i = 0; i < var.size(); i+=3)
38 sint id = var.asInt(i);
39 if(i == 0 && id == 0)
41 // first is always 0
42 continue;
44 if(id == 0)
46 nlwarning("Malformated id 0 in note file '%s', discard all notes", ClientCfg.NotesFilename.c_str());
47 Notes.Notes.clear();
48 return;
51 CVector pos;
52 vector<string> posstr;
53 explode(var.asString(i+1), ",", posstr);
54 if(posstr.size() != 3)
56 nlwarning("Malformated position in note number %d in file '%s', discard all notes", id, ClientCfg.NotesFilename.c_str());
57 Notes.Notes.clear();
58 return;
61 NLMISC::fromString(posstr[0], pos.x);
62 NLMISC::fromString(posstr[1], pos.y);
63 NLMISC::fromString(posstr[2], pos.z);
65 string note(var.asString(i+2));
66 if(note.empty())
68 nlwarning("Malformated because empty note in note number %d in file '%s', skipping it", id, ClientCfg.NotesFilename.c_str());
70 else
72 Notes.addNote(pos, note, id);
77 C3DNotes::CNote::CNote(const NLMISC::CVector &pos, const std::string &note, sint id) :
78 Id(id), Position(pos), Note(note), Bubble(NULL)
80 nlassert(Id > 0);
83 C3DNotes::CNote::~CNote()
85 if(Bubble)
87 Bubble->setActive(false);
88 Bubble->unlink();
89 Bubble = NULL;
93 void C3DNotes::init()
95 if(!ClientCfg.NotesFilename.empty())
97 // load the 3d notes
98 try
100 NotesConfigFile.load(ClientCfg.NotesFilename);
101 NotesConfigFile.setCallback(cbNotesChanged);
102 NotesAvailable = true;
103 cbNotesChanged();
105 catch(Exception &e)
107 nlwarning("Error while loading '%s': %s", ClientCfg.NotesFilename.c_str(), e.what());
108 NotesAvailable = false;
113 void C3DNotes::update()
115 if (!NotesAvailable) return;
117 // check if we need new bubble
118 CVector userPos = UserEntity->pos();
119 for(list<CNote>::iterator it = Notes.begin(); it != Notes.end(); it++)
121 if((*it).Bubble == NULL && ((*it).Position - userPos).norm() < 100)
123 string n = toString("NOTE: %d %s", (*it).Id, (*it).Note.c_str());
124 (*it).Bubble = InSceneBubbleManager.newBubble (ucstring(n));
125 if((*it).Bubble)
127 (*it).Bubble->link(NULL, 60*60*10);
128 (*it).Bubble->setActive (true);
129 nlinfo("NOTE: id %d pos(%f,%f,%f) note '%s'", (*it).Id, (*it).Position.x, (*it).Position.y, (*it).Position.z, (*it).Note.c_str());
132 else if((*it).Bubble && ((*it).Position - userPos).norm() >= 100)
134 (*it).Bubble->setActive(false);
135 (*it).Bubble->unlink();
136 (*it).Bubble = NULL;
139 if((*it).Bubble)
141 (*it).Bubble->Position = (*it).Position;
146 void C3DNotes::release()
148 Notes.clear();
151 void C3DNotes::saveNotes()
153 if (!NotesAvailable) return;
155 vector<string> vals;
156 vals.push_back("0");
157 vals.push_back("0,0,0");
158 vals.push_back("0");
159 for(list<CNote>::iterator it = Notes.begin(); it != Notes.end(); it++)
161 vals.push_back(toString("%d", (*it).Id));
162 vals.push_back(toString("%f,%f,%f", (*it).Position.x, (*it).Position.y, (*it).Position.z));
163 vals.push_back((*it).Note);
166 CConfigFile::CVar &var = NotesConfigFile.getVar("Notes");
167 var.setAsString(vals);
168 var.SaveWrap = 3;
169 NotesConfigFile.save();
172 void C3DNotes::addNote(const NLMISC::CVector &pos, const string &note, sint id)
174 if (!NotesAvailable) return;
176 bool needToSave = false;
177 if(id == 0)
179 id = NextId++;
180 needToSave = true;
183 Notes.push_back(CNote(pos, note, id));
184 if(id >= NextId)
186 NextId = id + 1;
188 if(needToSave)
190 saveNotes();
194 void C3DNotes::removeNote(sint id)
196 if (!NotesAvailable) return;
198 for(list<CNote>::iterator it = Notes.begin(); it != Notes.end(); it++)
200 if((*it).Id == id)
202 Notes.erase(it);
203 saveNotes();
204 return;
209 NLMISC_COMMAND(note, "Add a 3d note at your location", "<note>")
211 if(args.size() == 0)
212 return false;
214 #ifdef NL_OS_WINDOWS
215 char un[256];
216 DWORD s = 256;
217 GetUserName(un,&s);
218 #else
219 char *un="";
220 #endif
222 string note = toString("%s %s", un, IDisplayer::dateToHumanString());
223 for (uint i = 0; i < args.size(); i++)
225 note += " " + args[i];
228 CVector pos = UserEntity->pos();
230 Notes.addNote(pos, note);
232 return true;
235 NLMISC_COMMAND(removeNote, "Remove a 3d note with its id", "<id>")
237 if(args.size() == 0)
238 return false;
240 sint id = atoi(args[0].c_str());
241 if(id == 0)
243 log.displayNL("0 is an invalid note id");
244 return false;
247 Notes.removeNote(id);
249 return true;
252 NLMISC_COMMAND(displayNotes, "display all notes", "")
254 if(args.size() != 0)
255 return false;
257 log.displayNL("Displaying %d notes:", Notes.Notes.size());
258 for(list<C3DNotes::CNote>::iterator it = Notes.Notes.begin(); it != Notes.Notes.end(); it++)
260 log.displayNL("id %d pos(%f,%f,%f) note '%s'", (*it).Id, (*it).Position.x, (*it).Position.y, (*it).Position.z, (*it).Note.c_str());
263 return true;
266 NLMISC_COMMAND(gotoNote, "go to a note", "<id>|<text>")
268 if(args.size() == 0)
269 return false;
271 CVector pos(CVector::Null);
273 sint id = atoi(args[0].c_str());
274 if(id == 0)
276 // it's a text
277 string tok;
278 for(uint i = 0; i < args.size(); i++)
280 if(i != 0) tok += " ";
281 tok += args[i];
283 tok = toLower(tok);
284 list<C3DNotes::CNote>::iterator it;
285 for(it = Notes.Notes.begin(); it != Notes.Notes.end(); it++)
287 string note = toLower((*it).Note);
288 if(note.find(tok) != string::npos)
290 pos = (*it).Position;
291 break;
294 if(it == Notes.Notes.end())
296 log.displayNL("No notes match the text '%s'", tok.c_str());
299 else
301 // it's an id
302 list<C3DNotes::CNote>::iterator it;
303 for(it = Notes.Notes.begin(); it != Notes.Notes.end(); it++)
305 if((*it).Id == id)
307 pos = (*it).Position;
308 break;
311 if(it == Notes.Notes.end())
313 log.displayNL("No notes match the id %d", id);
317 if(pos != CVector::Null)
319 string cmd;
320 if (ClientCfg.Local)
322 cmd = toString("pos %f %f %f", pos.x, pos.y, pos.z);
324 else
326 cmd = toString("a Position %f,%f", pos.x, pos.y);
328 log.displayNL("Go to note at position (%f,%f,%f)", pos.x, pos.y, pos.z);
329 ICommand::execute(cmd, *InfoLog);
332 return true;
336 #if !FINAL_VERSION
337 NLMISC_COMMAND(debug, "open the debug window. alias to ah show_hide debug_info", "")
339 if(args.size() != 0) return false;
340 string cmd("ah show debug_info");
341 ICommand::execute(cmd, log);
342 return true;
344 #endif