1 #include "pch.h"
2 #include "common/Def_Str.h"
3 #include "common/Gui_Def.h"
4 #include "common/GuiCom.h"
5 #include "../vdrift/pathmanager.h"
6 #include "../vdrift/game.h"
7 #include "CGame.h"
8 #include "CHud.h"
9 #include "CGui.h"
10 #include "FollowCamera.h"
11 #include <time.h>
12 #include <boost/filesystem.hpp>
13 using namespace std;
14 using namespace Ogre;
15 using namespace MyGUI;
16 namespace fs = boost::filesystem;
17
18
19 /// [Replay] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20 //------------------------------------------------------------------------------------------------------------------
21
slRplPosEv(SL)22 void CGui::slRplPosEv(SL) // change play pos
23 {
24 if (!app->bRplPlay) return;
25 double oldt = pGame->timer.GetReplayTime(0);
26 double v = val; v = std::max(0.0, std::min(1.0, v)); v *= app->replay.GetTimeLength();
27 pGame->timer.SetReplayTime(0, v);
28
29 FollowCamera* fCam = (*app->carModels.begin())->fCam;
30 fCam->First(); // instant change
31 //for (int i=0; i < 10; ++i)
32 // fCam->update(fabs(v-oldt)/10.f, 0); //..?
33 }
34
getRplName()35 String CGui::getRplName()
36 {
37 String name;
38 int i = rplList->getIndexSelected(), p; if (i == ITEM_NONE) return name;
39 name = rplList->getItemNameAt(i);
40 if (name.length() > 7 && name[0]=='#') name = name.substr(7);
41 return name;
42 }
43
44
btnRplLoad(WP)45 void CGui::btnRplLoad(WP) // Load
46 {
47 // from list
48 String name = getRplName(); if (name.empty()) return;
49 string file = GetRplListDir() + "/" + name + ".rpl";
50
51 if (!app->replay.LoadFile(file))
52 {
53 Message::createMessageBox(
54 "Message", TR("#{Replay} - #{RplLoad}"), TR("#{Error}."),
55 MessageBoxStyle::IconWarning | MessageBoxStyle::Ok);
56 }else
57 { // car, track change
58 const ReplayHeader2& h = app->replay.header;
59 string trk = h.track;
60 bool usr = h.track_user == 1;
61
62 // check if cars, track exist
63 String er; int p;
64 if (!h.track_user && !fs::exists(PATHMANAGER::Tracks()+"/"+trk))
65 er += TR("#{Track}: ")+trk+TR(" - #{DoesntExist}.\n");
66 if (h.track_user && !fs::exists(PATHMANAGER::TracksUser()+"/"+trk))
67 er += TR("#{Track} (#{TweakUser}): ")+trk+TR(" - #{DoesntExist}.\n");
68
69 for (p=0; p < h.numPlayers; ++p)
70 if (!fs::exists(PATHMANAGER::Cars()+"/"+h.cars[p]))
71 er += TR("#{Vehicle}: ")+h.cars[p]+TR(" - #{DoesntExist}.\n");
72
73 if (!er.empty())
74 { Message::createMessageBox(
75 "Message", TR("#{Replay} - #{RplLoad} - #{Error}"), "\n"+er,
76 MessageBoxStyle::IconError | MessageBoxStyle::Ok);
77 return;
78 }
79 //trackreverse num_laps
80 //collis_veget, collis_cars, collis_roadw, dyn_objects;
81 //int boost_type, flip_type; float boost_power;
82 //float pre_time;
83
84 // set game config from replay
85 pSet->game = pSet->gui;
86 pSet->game.track = trk; pSet->game.track_user = usr;
87
88 pSet->game.trees = h.trees;
89 pSet->game.local_players = h.numPlayers;
90 BackFromChs();
91 LogO("RPL btn Load players: "+toStr(h.numPlayers)+" netw: "+ toStr(h.networked));
92
93 for (p=0; p < h.numPlayers; ++p)
94 { pSet->game.car[p] = h.cars[p];
95 }
96 app->newGameRpl = true;
97 btnNewGame(0);
98 app->bRplPlay = 1; app->iRplSkip = 0;
99 }
100 }
101
btnRplSave(WP)102 void CGui::btnRplSave(WP) // Save
103 {
104 String edit = edRplName->getCaption();
105 String file = PATHMANAGER::Replays() + "/" + pSet->game.track + "_" + edit + ".rpl";
106 /// save
107 if (PATHMANAGER::FileExists(file))
108 {
109 Message::createMessageBox(
110 "Message", TR("#{Replay} - #{RplSave}"), TR("#{AlreadyExists}."),
111 MessageBoxStyle::IconWarning | MessageBoxStyle::Ok);
112 return;
113 }
114 if (!app->replay.SaveFile(file.c_str()))
115 {
116 Message::createMessageBox(
117 "Message", TR("#{Replay} - #{RplSave}"), TR("#{Error}."),
118 MessageBoxStyle::IconWarning | MessageBoxStyle::Ok);
119 }
120 updReplaysList();
121 }
122
123 // list change
listRplChng(List * li,size_t pos)124 void CGui::listRplChng(List* li, size_t pos)
125 {
126 String name = getRplName(); if (name.empty()) return;
127 string file = GetRplListDir() + "/" + name + ".rpl";
128 valRplName->setCaption(name);
129 edRplName->setCaption(name);
130
131 // load replay header, upd info text
132 Replay2 rpl; char stm[128];
133 if (rpl.LoadFile(file,true))
134 {
135 const ReplayHeader2& rh = rpl.header;
136 String ss = String(TR("#{Track}: ")) + gcom->GetSceneryColor(rh.track) +
137 rh.track + (rh.track_user ? " *"+TR("#{TweakUser}")+"*" : "");
138 valRplName->setCaption(ss);
139 char pp = rh.numPlayers, netw = rh.networked, n;
140
141 ss = String(TR("#{Vehicles}: "));
142 for (n=0; n < pp; ++n) ss += rh.cars[n] + " ";
143 ss += //(netw == 0 ? "" : "M") + //TR("#{Multiplayer}")
144 "\n#C0D8F0" + TR("#{RplTime}: ") + StrTime(rpl.GetTimeLength()) +
145 "\n#90A0B0" + TR("#{Simulation}: ") + rh.sim_mode;
146
147 if (netw == 1) // list nicks
148 { ss += String("\n#90C0E0");
149 for (n=0; n < pp; ++n)
150 ss += rh.nicks[n]+" ";
151 }
152 valRplInfo->setCaption(ss);
153
154 // file stats
155 int size = fs::file_size(file);
156 std::time_t ti = fs::last_write_time(file);
157 if (!std::strftime(stm, 126, "%d.%b'%y %a %H:%M", std::localtime(&ti))) stm[0]=0;
158
159 ss = String(stm)+"\n#A0A0A0"+ // date
160 String(TR("#{RplFileSize}: ")) + fToStr( float(size)/1000000.f, 2,5) + TR(" #{UnitMB}") + "\n#808080" +
161 TR("#{RplVersion}: ") + toStr(rh.ver);
162 if (valRplInfo2) valRplInfo2->setCaption(ss);
163 }
164 //edRplDesc
165 }
166
167
168 // replay settings
169
slRplNumViewports(SL)170 void CGui::slRplNumViewports(SL)
171 {
172 int v = 1.f + 3.f * val; if (bGI) pSet->rpl_numViews = v;
173 if (valRplNumViewports) valRplNumViewports->setCaption(toStr(v));
174 }
175
176
177 // replays list filtering
178
btnRplAll(WP)179 void CGui::btnRplAll(WP)
180 {
181 rbRplCur->setStateSelected(false); rbRplAll->setStateSelected(true);
182 pSet->rpl_listview = 0; updReplaysList();
183 }
184
btnRplCur(WP)185 void CGui::btnRplCur(WP)
186 {
187 rbRplCur->setStateSelected(true); rbRplAll->setStateSelected(false);
188 pSet->rpl_listview = 1; updReplaysList();
189 }
190
chkRplGhosts(Ck *)191 void CGui::chkRplGhosts(Ck*)
192 {
193 updReplaysList();
194 }
195
196
197 // replay controls
198
btnRplToStart(WP)199 void CGui::btnRplToStart(WP)
200 {
201 pGame->timer.RestartReplay(0);
202 }
203
btnRplToEnd(WP)204 void CGui::btnRplToEnd(WP)
205 {
206 }
207
btnRplBackDn(WP,int,int,MouseButton)208 void CGui::btnRplBackDn(WP, int, int, MouseButton){ bRplBack = true; }
btnRplBackUp(WP,int,int,MouseButton)209 void CGui::btnRplBackUp(WP, int, int, MouseButton){ bRplBack = false; }
btnRplFwdDn(WP,int,int,MouseButton)210 void CGui::btnRplFwdDn(WP, int, int, MouseButton){ bRplFwd = true; }
btnRplFwdUp(WP,int,int,MouseButton)211 void CGui::btnRplFwdUp(WP, int, int, MouseButton){ bRplFwd = false; }
212
btnRplPlay(WP)213 void CGui::btnRplPlay(WP) // play / pause
214 {
215 app->bRplPause = !app->bRplPause;
216 UpdRplPlayBtn();
217 }
218
UpdRplPlayBtn()219 void CGui::UpdRplPlayBtn()
220 {
221 String sign = app->bRplPause ? "|>" : "||";
222 if (btRplPl)
223 btRplPl->setCaption(sign);
224 }
225
226
227 // List
updReplaysList()228 void CGui::updReplaysList()
229 {
230 if (!rplList) return;
231 //Ogre::Timer ti;
232
233 rplList->removeAllItems();
234
235 strlist li;
236 PATHMANAGER::DirList(GetRplListDir(), li, "rpl");
237
238 for (strlist::iterator i = li.begin(); i != li.end(); ++i)
239 if (StringUtil::endsWith(*i, ".rpl"))
240 {
241 String s = *i; s = StringUtil::replaceAll(s,".rpl","");
242 String slow = s; StringUtil::toLowerCase(slow);
243 if (sRplFind == "" || strstr(slow.c_str(), sRplFind.c_str()) != 0)
244 if (pSet->rpl_listview != 1 || StringUtil::startsWith(s,pSet->gui.track, false))
245 { String t = s;
246 size_t p = t.find_first_of("_");
247 if (p != string::npos)
248 t = s.substr(0, p);
249 rplList->addItem(gcom->GetSceneryColor(t) + s);
250 } }
251 //LogO(String("::: Time ReplaysList: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
252 }
253
254
255 // Delete
btnRplDelete(WP)256 void CGui::btnRplDelete(WP)
257 {
258 String name = getRplName(); if (name.empty()) return;
259
260 Message* message = Message::createMessageBox(
261 "Message", TR("#{Replay} - #{RplDelete} ?"), name,
262 MessageBoxStyle::IconQuest | MessageBoxStyle::Yes | MessageBoxStyle::No);
263 message->eventMessageBoxResult += newDelegate(this, &CGui::msgRplDelete);
264 }
msgRplDelete(Message * sender,MessageBoxStyle result)265 void CGui::msgRplDelete(Message* sender, MessageBoxStyle result)
266 {
267 if (result != MessageBoxStyle::Yes) return;
268 String name = getRplName(); if (name.empty()) return;
269 string file = GetRplListDir() +"/"+ name + ".rpl";
270
271 if (fs::exists(file))
272 fs::remove(file);
273 updReplaysList();
274 }
275
276 // Rename
btnRplRename(WP)277 void CGui::btnRplRename(WP)
278 {
279 if (pSet->rpl_listghosts) return; // cant rename ghosts
280 String name = getRplName(); if (name.empty()) return;
281 string edit = edRplName->getCaption();
282
283 if (name == edit) // same name
284 { Message::createMessageBox(
285 "Message", TR("#{Replay} - #{RplRename}"), TR("#{AlreadyExists}."),
286 MessageBoxStyle::IconInfo | MessageBoxStyle::Ok);
287 return; }
288
289 string file = PATHMANAGER::Replays() + "/" + name + ".rpl";
290 string fileNew = PATHMANAGER::Replays() + "/" + edit + ".rpl";
291
292 if (fs::exists(fileNew))
293 { Message::createMessageBox(
294 "Message", TR("#{Replay} - #{RplRename}"), TR("#{AlreadyExists}."),
295 MessageBoxStyle::IconInfo | MessageBoxStyle::Ok);
296 return; }
297
298 if (fs::exists(file))
299 fs::rename(file, fileNew);
300 updReplaysList();
301 }
302
303
304
305 // Game replay Tools
306 //--------------------------------------------------------------------------------
fixOldTrkName(string & s)307 bool Replay::fixOldTrkName(string& s)
308 {
309 if (s.length() <= 4) return false;
310
311 if (s[0]=='0' && s[1]=='W')
312 s = s.substr(1);
313 if (s[0]>='A' && s[0]<='Z' && (s[2]=='-' || s[3]=='-'))
314 {
315 if (s[0]=='J') s= "Jng" +s.substr(1); else
316 if (s[0]=='D') s= "Des" +s.substr(1); else
317 if (s[0]=='S') s= "Sav" +s.substr(1); else
318 if (s[0]=='W') s= "Wnt" +s.substr(1); else
319 if (s[0]=='F') s= "For" +s.substr(1); else
320 if (s[0]=='E') s= "Fin" +s.substr(1); else
321 if (s[0]=='I') s= "Isl" +s.substr(1); else
322 if (s[0]=='M') s= "Mud" +s.substr(1); else
323 if (s[0]=='A') s= "Aus" +s.substr(1); else
324 if (s[0]=='G') s= "Grc" +s.substr(1); else
325 if (s[0]=='C') s= "Can" +s.substr(1); else
326 if (s[0]=='T') s= "Atm" +s.substr(1); else
327 if (s[0]=='O') s= "Mos" +s.substr(1); else
328 if (s[0]=='V') s= "Vlc" +s.substr(1); else
329 if (s[0]=='X') s= "Uni" +s.substr(1); else
330 if (s[0]=='R') s= "Mrs" +s.substr(1); else
331 if (s[0]=='Y') s= "Cry" +s.substr(1); else return false;
332 return true;
333 }
334 return false;
335 }
336
337 // Rename old track names
btnRenameOldTrk(WP)338 void CGui::btnRenameOldTrk(WP)
339 {
340 LogO("==------ Renaming old replays and ghosts");
341 std::vector<string> pp;
342 pp.push_back(PATHMANAGER::Replays());
343 pp.push_back(PATHMANAGER::Ghosts() +"/easy");
344 pp.push_back(PATHMANAGER::Ghosts() +"/normal");
345 pp.push_back(PATHMANAGER::Records()+"/easy");
346 pp.push_back(PATHMANAGER::Records()+"/normal");
347 strlist li;
348 for (int ip=0; ip < pp.size(); ++ip)
349 {
350 li.clear();
351 string p = pp[ip];
352 PATHMANAGER::DirList(p, li);
353 LogO("PATH: "+p);
354 for (strlist::iterator i = li.begin(); i != li.end(); ++i)
355 {
356 String s = *i, sn;
357 if (s.length() > 3)
358 if (s[0]>='A' && s[0]<='Z' && (s[2]=='-' || s[3]=='-'))
359 { sn = s;
360 if (Replay::fixOldTrkName(sn))
361 if (!fs::exists(p+"/"+s)) LogO(s+" to "+sn+" source doesnt exist!");
362 /**/else if (fs::exists(p+"/"+sn)) LogO(s+" to "+sn+" destination already exists");
363 else
364 { LogO(s+" to "+sn);
365 fs::rename(p+"/"+s, p+"/"+sn);
366 } }
367 } }
368 LogO("==------ Renaming End");
369 }
370
371 // Convert to Replay2
btnConvertAllRpl(WP)372 void CGui::btnConvertAllRpl(WP)
373 {
374 if (bConvertRpl) return;
375 bConvertRpl = true;
376
377 txtConvert->setVisible(true);
378
379 iConvCur = -1; iConvAll = 1;
380 mThrConvert = boost::thread(boost::bind(&CGui::ThreadConvert, boost::ref(*this)));
381 }
382
ThreadConvert()383 void CGui::ThreadConvert()
384 {
385 LogO("====---- Converting old replays and ghosts");
386 Ogre::Timer ti;
387
388 std::vector<string> paths, files[3];
389 // paths
390 paths.push_back(PATHMANAGER::Ghosts() +"/easy");
391 paths.push_back(PATHMANAGER::Ghosts() +"/normal");
392 paths.push_back(PATHMANAGER::Replays());
393
394 iConvPathCur = 0; iConvPathAll = paths.size();
395 iConvFiles = 0; totalConv = 0; totalConvNew = 0; totalConvCur = 0;
396
397 // List files ------------
398 strlist li; int p;
399 Replay2 rpl;
400 for (p=0; p < iConvPathAll; ++p)
401 { iConvPathCur = p;
402
403 const string& path = paths[p];
404 li.clear();
405 PATHMANAGER::DirList(path, li, "rpl");
406 iConvCur = 0; iConvAll = li.size();
407
408 for (strlist::iterator i = li.begin(); i != li.end(); ++i)
409 {
410 if (app->mShutDown) return;
411 String file = *i, s = path +"/"+ file;
412
413 //Replay2 rpl;
414 rpl.LoadFile(s, true); // header
415 if (rpl.header.ver <= 10) // old, not converted, 10 was last 2.5
416 {
417 ++iConvFiles;
418 files[p].push_back(file);
419 boost::uintmax_t size = fs::file_size(s);
420 totalConv += size;
421 }
422 ++iConvCur;
423 }
424 LogO("PATH: "+path+" total size: "+fToStr( float(totalConv)/1000000.f, 2,5)+" MiB");
425 LogO("PATH: "+path+" total after: "+fToStr( float(totalConvNew)/1000000.f, 2,5)+" MiB");
426 }
427 LogO(String("::: Time Convert get list: ") + fToStr(ti.getMilliseconds()/1000.f,1,4) + " s");
428 LogO("====---- Converting Start");
429
430 iConvCur = 0; iConvAll = iConvFiles;
431
432
433 LogO(String("FILES to convert: ") + toStr(iConvFiles));
434
435 // Convert ------------
436 for (p=0; p < iConvPathAll; ++p)
437 { iConvPathCur = p;
438
439 const string& path = paths[p];
440 iConvCur = 0; iConvAll = files[p].size();
441
442 while (iConvCur < iConvAll && !app->mShutDown)
443 {
444 const string s = path +"/"+ files[p][iConvCur];
445 //Replay2 rpl;
446 rpl.LoadFile(s); // converts old
447 boost::uintmax_t size = fs::file_size(s); // for progress
448 totalConvCur += size;
449 std::time_t tim = fs::last_write_time(s);
450
451 rpl.SaveFile(s); // same name, no backup
452 fs::last_write_time(s, tim); // restore original date
453 boost::uintmax_t sizeNew = fs::file_size(s);
454 totalConvNew += sizeNew;
455 ++iConvCur;
456 }
457 }
458
459 // Results ------------
460 bConvertRpl = false;
461 LogO("====---- Converting Results");
462 LogO(" Sizes");
463 LogO(" old: "+ fToStr( float(totalConv)/1000000.f, 2,5) +" MiB");
464 LogO(" new: "+ fToStr( float(totalConvNew)/1000000.f, 2,5) +" MiB");
465 if (totalConvCur!=totalConv || totalConv==0){} else
466 LogO(" ratio: "+ fToStr(100.f* float(totalConvNew)/float(totalConv), 2,5) +" %");
467
468 LogO(String("::: Time Convert: ") + fToStr(ti.getMilliseconds()/1000.f,1,4) + " s");
469 LogO("====---- Converting End");
470 }
471