1 #include "pch.h"
2 #include "Replay.h"
3 #include "common/Def_Str.h"
4 #include <OgreTimer.h>
5 #include <string>
6 #include "CHud.h" //
7 using namespace std;
8 using namespace Ogre;
9 
10 
11 //  header
12 //----------------------------------------------------------------
ReplayHeader2()13 ReplayHeader2::ReplayHeader2()
14 {
15 	Default();
16 }
SetHead()17 void ReplayHeader2::SetHead()
18 {
19 	head[0] = 'S';  head[1] = 'R';  head[2] = '/';  head[3] = '^';  head[4] = 0;
20 }
Default()21 void ReplayHeader2::Default()
22 {
23 	SetHead();
24 	track = "";  track_user = 0;
25 	ver = 30;  time = -0.01f;
26 
27 	numPlayers = 0;  trees = 1.f;
28 	num_laps = 1;  networked = 0;
29 	sim_mode = "";
30 
31 	cars.clear();  numWh.clear();  nicks.clear();
32 }
33 
FromOld(const struct ReplayHeader & h)34 void ReplayHeader2::FromOld(const struct ReplayHeader& h)
35 {
36 	time = -0.01f;  //set later
37 	ver = h.ver;
38 	track = h.track;
39 	track_user = h.track_user;
40 
41 	numPlayers = h.numPlayers;
42 	cars.clear();  cars.resize(numPlayers);
43 	numWh.clear();  numWh.resize(numPlayers);
44 
45 	cars[0] = h.car;
46 	int i;
47 	for (i=1; i < numPlayers; ++i)
48 		cars[i] = h.cars[i-1];
49 
50 	for (i=0; i < numPlayers; ++i)
51 	{	string s = cars[i];  char w = 4;
52 		if (s=="BV")  w = 2;  else  // old, not 4 wheeled veh
53 		if (s=="O"||s=="V1"||s=="V2"||s=="V3")  w = 0;
54 		numWh[i] = w;
55 	}
56 	trees = h.trees;
57 	num_laps = h.num_laps;
58 	networked = h.networked;
59 	sim_mode = h.sim_mode;
60 
61 	nicks.clear();
62 	if (networked)
63 	{	nicks.resize(numPlayers);
64 		for (i=0; i < numPlayers; ++i)
65 			nicks[i] = h.nicks[i];
66 	}
67 }
68 
ReplayFrame2()69 ReplayFrame2::ReplayFrame2()
70 	:gear(0),fl(0)  //..
71 {
72 }
73 
74 ///  convert old frame to new
75 //-------------------------------------------------------------------------------
FromOld(const ReplayFrame & f,uchar numWh,half prevHitTime)76 void ReplayFrame2::FromOld(const ReplayFrame& f, uchar numWh, half prevHitTime)
77 {
78 	time = f.time;  // save once..
79 	pos = f.pos;  rot = f.rot;
80 
81 	fl = 0;  // zero flags
82 	set(b_braking, f.braking);
83 
84 	//  hud
85 	gear = f.gear;  rpm = f.rpm;  vel = f.vel;
86 	percent = f.percent /100.f*255.f;  // track %
87 	damage = 0.f;  // wasnt saved
88 
89 	//  sound, input
90 	//LogO(String(" % ")+fToStr(f.percent)+"  th "+fToStr(f.throttle)+"  st "+fToStr(f.steer)+"  b "+fToStr(f.fboost)+"  c "+fToStr(f.clutch));
91 	throttle = f.throttle *255.f;	steer = f.steer *127.f;
92 	fboost = f.fboost *255.f;		clutch = f.clutch *255.f;
93 	speed = f.speed;  dynVel = f.dynVel;
94 
95 	hov_roll = f.hov_roll;  //=sph_yaw for O
96 	if (f.hov_roll != 0.f)  set(b_hov, true);
97 
98 
99 	//  hit continuous  ---
100 	bool hasScr = f.fCarScrap > 0.f || f.fCarScreech > 0.f;
101 	set(b_scrap, hasScr);
102 	if (hasScr)
103 	{	RScrap scr;
104 		scr.fScrap = half(f.fCarScrap);  scr.fScreech = half(f.fCarScreech);
105 		scrap.clear();  scrap.push_back(scr);
106 	};
107 
108 	//  new hit data impact
109 	fHitTime = f.fHitTime;
110 	bool h = fHitTime > prevHitTime;  //== 1.f;
111 	//  wrong if saving every nth frame, what with higher force in skipped frames?..
112 	set(b_hit, h);
113 	if (h)
114 	{	RHit ht;
115 		ht.fParIntens = f.fParIntens;  ht.fParVel = f.fParVel;
116 		ht.vHitPos = f.vHitPos;  ht.vHitNorm = f.vHitNorm;  // world
117 		ht.fHitForce = f.fHitForce;
118 		hit.push_back(ht);
119 	};
120 
121 	//  wheels  ---
122 	wheels.clear();
123 	for (int i=0; i < numWh; ++i)
124 	{	RWheel wh;
125 
126 		wh.pos = f.whPos[i];
127 		for (int q=0; q<4; ++q)  wh.rot[q] = f.whRot[i][q];
128 
129 		//  wheel trails, particles, snd
130 		wh.surfType = f.surfType[i];    wh.whTerMtr = f.whTerMtr[i];
131 		wh.whRoadMtr = f.whRoadMtr[i];  wh.whP = f.whP[i];  //particle type
132 
133 		wh.squeal = f.squeal[i];  wh.slide = f.slide[i];  wh.whVel = f.whVel[i];
134 		wh.suspVel = f.suspVel[i];  wh.suspDisp = f.suspDisp[i];
135 
136 		//  fluids
137 		wh.whH = f.whH[i] / 255.f;  // submerge
138 		wh.whAngVel = f.whAngVel[i];
139 		wh.whSteerAng = i >= 2 ? 0.f : f.whSteerAng[i];
140 
141 		wheels.push_back(wh);
142 	};
143 }
144 
145 
Replay2()146 Replay2::Replay2()
147 	:idLast(0)
148 {
149 	Clear();
150 }
151 
152 //  Init  once per game
InitHeader(const char * track,bool trk_user,bool bClear)153 void Replay2::InitHeader(const char* track, bool trk_user, bool bClear)
154 {
155 	header.Default();
156 	header.track = track;  header.track_user = trk_user ? 1 : 0;
157 	if (bClear)
158 		Clear();
159 }
160 
ClearCars()161 void Replay2::ClearCars()
162 {
163 	int pp = header.numPlayers;
164 	header.cars.clear();  header.cars.resize(pp);
165 	header.nicks.clear();  header.nicks.resize(pp);
166 	header.numWh.clear();  header.numWh.resize(pp);
167 }
168 
Clear(bool time)169 void Replay2::Clear(bool time)
170 {
171 	idLast = 0;
172 	if (time)
173 		header.time = -0.01f;  // so new 0.0 counts
174 
175 	int p,pp = header.numPlayers;
176 	frames.resize(pp);
177 	for (p=0; p < pp; ++p)
178 	{	frames[p].clear();
179 		frames[p].reserve(cDefSize);
180 	}
181 }
182 
183 
184 ///  Load
185 //-------------------------------------------------------------------------------------------------------
LoadFile(string file,bool onlyHdr)186 bool Replay2::LoadFile(string file, bool onlyHdr)
187 {
188 	ifstream fi(file.c_str(), ios::binary | ios::in);
189 	if (!fi)  return false;
190 
191 	Ogre::Timer ti;
192 	bool convert = false;
193 
194 	//  header check
195 	fi.read(header.head,5);
196 	if (strcmp(header.head,"SR\\_")==0)
197 		convert = true;
198 	else
199 	if (strcmp(header.head,"SR/^")!=0)
200 	{
201 		LogO(">- Load replay2: "+file+"  Error: Unknown header");
202 		return false;
203 	}
204 
205 	if (convert)
206 	{
207 		LogO(">- Load replay2 convert: "+file);
208 
209 		//  load old, convert
210 		Replay r;
211 		r.LoadFile(file, onlyHdr);
212 		header.FromOld(r.header);
213 
214 		Clear();  //  clear
215 
216 		if (onlyHdr)
217 		{	header.time = r.GetTimeLength();  return true;  }
218 
219 		header.ver = r.header.ver + 10;  // ver +10 after convert
220 
221 		//  check, rare
222 		int p,i,ii = r.GetNumFrames();
223 		for (p=0; p < header.numPlayers; ++p)
224 		{	int si = r.frames[p].size()-1;
225 			ii = std::min(ii, si);
226 		}
227 
228 		for (p=0; p < header.numPlayers; ++p)
229 		{
230 			uchar wh = header.numWh[p];
231 			half prevHitTime = half(0.f);
232 
233 			for (i=0; i < ii; ++i)
234 			if (i%2==0)  // half frames
235 			{
236 				ReplayFrame2 f2;
237 				f2.FromOld(r.frames[p][i], wh, prevHitTime);
238 				AddFrame(f2,p);
239 				prevHitTime = f2.fHitTime;
240 		}	}
241 		header.time = r.GetTimeLength();
242 	}
243 	else  // load new
244 	{
245 		uchar l;  int i,s;  char buf[256];
246 		#define rd(a)  fi.read((char*)&a, sizeof(a))
247 		#define rs(s)  {  fi.read((char*)&l, 1);  if (l>0)  fi.read(buf, l);  buf[l]=0;  s = buf;  }  //string
248 		//TODO: endianness, swap 2bytes..  ENDIAN_SWAP_16
249 
250 		//  header  ------
251 		ReplayHeader2& h = header;
252 		rd(h.ver);  rd(h.time);
253 		rs(h.track)  rd(h.track_user);
254 		String ss = ">- Load replay2  ";
255 		ss += h.track+"  ";
256 		ss += StrTime(h.time)+"  ";
257 
258 		rd(h.numPlayers);  s = h.numPlayers;
259 		h.cars.clear();  h.cars.resize(s);
260 		h.numWh.clear();  h.numWh.resize(s);
261 		for (i=0; i < s; ++i)
262 		{	rs(h.cars[i])  ss += h.cars[i]+" ";  }  ss+=" ";
263 		for (i=0; i < s; ++i)
264 		{	rd(h.numWh[i]);  ss += toStr(h.numWh[i])+" ";  }  ss+=" ";
265 
266 		rd(h.trees);  rd(h.num_laps);
267 		rd(h.networked);  rs(h.sim_mode)
268 
269 		h.nicks.clear();  h.nicks.resize(s);
270 		if (h.networked)
271 			for (i=0; i < s; ++i)
272 			{	rs(h.nicks[i])  ss += h.nicks[i]+" ";  }  ss+=" ";
273 
274 		#ifdef LOG_RPL
275 			LogO(ss);
276 			//if (!onlyHdr)
277 			//	LogO(">- Load replay2: "+file+"  players:"+toStr(h.numPlayers));
278 		#endif
279 
280 		Clear(false);  //  clear
281 
282 		if (onlyHdr){	fi.close();  return true;  }
283 
284 		//  frames  ------
285 		i=0;  int p,w;  float prevTime = -1.f;
286 		while (!fi.eof())
287 		{
288 			float time;  rd(time);  // once
289 			for (p=0; p < header.numPlayers; ++p)
290 			{
291 				ReplayFrame2 f;
292 				f.time = time;
293 				//  car
294 				rd(f.pos);  rd(f.rot);  rd(f.fl);  //b_braking etc
295 				//  hud
296 				rd(f.gear);  rd(f.rpm);  rd(f.vel);
297 				rd(f.damage);  rd(f.clutch);  rd(f.percent);
298 				//  sound, input
299 				rd(f.throttle);  rd(f.steer);  rd(f.fboost);
300 				rd(f.speed);  rd(f.dynVel);
301 				//  ext
302 				if (f.get(b_hov))  rd(f.hov_roll);
303 				bool flu = f.get(b_fluid);
304 				if (flu)  rd(f.whMudSpin);
305 
306 				//  wheels
307 				int ww = header.numWh[p];
308 				for (w=0; w < ww; ++w)
309 				{
310 					RWheel wh;
311 					rd(wh.pos);  rd(wh.rot);
312 					//  trl, par, snd
313 					rd(wh.surfType);  rd(wh.whTerMtr);
314 					rd(wh.whRoadMtr);  rd(wh.whP);
315 					//  tire
316 					rd(wh.squeal);  rd(wh.slide);  rd(wh.whVel);
317 					rd(wh.suspVel);  rd(wh.suspDisp);
318 					//  fluids
319 					if (flu)  rd(wh.whH);
320 					rd(wh.whAngVel);  rd(wh.whSteerAng);
321 					f.wheels.push_back(wh);
322 				}
323 
324 				//  hit data
325 				if (f.get(b_scrap))
326 				{
327 					RScrap s;
328 					rd(s.fScrap);  rd(s.fScreech);
329 					f.scrap.push_back(s);
330 				}
331 				rd(f.fHitTime);
332 				if (f.get(b_hit))
333 				{
334 					RHit h;
335 					rd(h.fHitForce);  rd(h.fParIntens);  rd(h.fParVel);
336 					rd(h.vHitPos.x);   rd(h.vHitPos.y);   rd(h.vHitPos.z);
337 					rd(h.vHitNorm.x);  rd(h.vHitNorm.y);  rd(h.vHitNorm.z);
338 					f.hit.push_back(h);
339 				}
340 
341 				if (time <= prevTime)
342 				{
343 					#ifdef LOG_RPL
344 					LogO(">- Load replay2  =time  id:"+toStr(i)+"  plr:"+toStr(p)+"  t-1:"+fToStr(prevTime,5,7)+" => t:"+fToStr(time,5,7));
345 					#endif
346 				}else
347 				if (!fi.eof())
348 					frames[p].push_back(f);
349 			}
350 			++i;  prevTime = time;
351 		}
352 		fi.close();
353     }
354 
355     #ifdef LOG_RPL
356 		if (frames.empty() || frames[0].empty())
357 			LogO(">- Load replay2  empty!!  time: "+fToStr(GetTimeLength(),2,5));
358 		else
359 			LogO(">- Load replay2  plr: "+toStr(header.numPlayers)+"  t1st: "+fToStr(frames[0][0].time,5,7)+
360 				"  time: "+fToStr(GetTimeLength(),2,5)+"  frames: "+toStr(frames[0].size()));
361 	#endif
362 
363 	LogO(String("::: Time Replay2 Load: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
364 	return true;
365 }
366 
367 ///  Save
368 //-------------------------------------------------------------------------------------------------------
SaveFile(string file)369 bool Replay2::SaveFile(string file)
370 {
371 	ofstream of(file.c_str(), ios::binary | ios::out);
372 	if (!of)  return false;
373 
374 	uchar l;  int i,s;
375 	#define ws(s)  {  l = s.length();  of.write((char*)&l, 1);  of.write(s.c_str(), l);  }  //string
376 	#define wr(a)  of.write((char*)&a, sizeof(a))
377 	//todo: portability, endianness for shorts?..
378 
379 	//  header  ------
380 	const ReplayHeader2& h = header;
381 	header.SetHead();
382 	of.write((char*)&h.head, 5);
383 	wr(h.ver);  wr(h.time);
384 	ws(h.track)  wr(h.track_user);
385 
386 	wr(h.numPlayers);
387 	s = h.numPlayers;  // car names
388 	for (i=0; i < s; ++i)  ws(h.cars[i])
389 	for (i=0; i < s; ++i)  wr(h.numWh[i]);
390 
391 	wr(h.trees);  wr(h.num_laps);
392 	wr(h.networked);  ws(h.sim_mode)
393 
394 	if (h.networked)
395 		for (i=0; i < s; ++i)  ws(h.nicks[i])
396 
397 
398 	//  frames  ------
399 	s = frames[0].size();  int p,w;
400 	//s = 1;  p = 1;  //test
401 
402 	for (i=0; i < s; ++i)
403 	{
404 		float time = frames[0][i].time;
405 		wr(time);  // once
406 		for (p=0; p < header.numPlayers; ++p)
407 		{
408 			ReplayFrame2 f = frames[p][i];
409 			//  car
410 			wr(f.pos);  wr(f.rot);  wr(f.fl);  //b_braking etc
411 			//  hud
412 			wr(f.gear);  wr(f.rpm);  wr(f.vel);
413 			wr(f.damage);  wr(f.clutch);  wr(f.percent);
414 			//  sound, input
415 			wr(f.throttle);  wr(f.steer);  wr(f.fboost);
416 			wr(f.speed);  wr(f.dynVel);
417 			//  ext
418 			if (f.get(b_hov))  wr(f.hov_roll);
419 			bool flu = f.get(b_fluid);
420 			if (flu)  wr(f.whMudSpin);
421 
422 			//  wheels
423 			int ww = f.wheels.size();
424 			for (w=0; w < ww; ++w)
425 			{
426 				const RWheel& wh = f.wheels[w];
427 				wr(wh.pos);  wr(wh.rot);
428 				//  trl, par, snd
429 				wr(wh.surfType);  wr(wh.whTerMtr);
430 				wr(wh.whRoadMtr);  wr(wh.whP);
431 				//  tire
432 				wr(wh.squeal);  wr(wh.slide);  wr(wh.whVel);
433 				wr(wh.suspVel);  wr(wh.suspDisp);
434 				//  fluids
435 				if (flu)  wr(wh.whH);
436 				wr(wh.whAngVel);  wr(wh.whSteerAng);
437 			}
438 
439 			//  hit data
440 			if (f.get(b_scrap) /*&& scrap.size()==1*/)
441 			{
442 				const RScrap& s = f.scrap[0];
443 				wr(s.fScrap);  wr(s.fScreech);
444 			}
445 			wr(f.fHitTime);
446 			if (f.get(b_hit) /*&& hit.size()==1*/)
447 			{
448 				const RHit& h = f.hit[0];
449 				wr(h.fHitForce);  wr(h.fParIntens);  wr(h.fParVel);
450 				wr(h.vHitPos.x);   wr(h.vHitPos.y);   wr(h.vHitPos.z);
451 				wr(h.vHitNorm.x);  wr(h.vHitNorm.y);  wr(h.vHitNorm.z);
452 			}
453 		}
454 	}
455 
456     of.close();
457     return true;
458 }
459 //-------------------------------------------------------------------------------------------------------
460 
461 
462 //  add (Record)
AddFrame(const ReplayFrame2 & frame,int carNum)463 void Replay2::AddFrame(const ReplayFrame2& frame, int carNum)
464 {
465 	if (carNum > 0 || frame.time > GetTimeLength())  // dont add before last
466 	{
467 		frames[carNum].push_back(frame);
468 		header.time = frame.time;
469 	}
470 }
471 
472 //  CopyFrom
CopyFrom(const Replay2 & rpl)473 void Replay2::CopyFrom(const Replay2& rpl)
474 {
475 	header.numPlayers = rpl.header.numPlayers;
476 	Clear();
477 	header.time = rpl.header.time;
478 
479 	//  plr 1 only, for ghost
480 	for (int i=0; i < rpl.GetNumFrames(); ++i)
481 		frames[0].push_back(rpl.frames[0][i]);
482 }
483 
484 //  last frame time, sec
GetTimeLength() const485 const float Replay2::GetTimeLength() const
486 {
487 	return header.time;
488 }
489 
490 //  get Last
GetLastFrame(ReplayFrame2 * pFr,int carNum)491 bool Replay2::GetLastFrame(ReplayFrame2* pFr, int carNum)
492 {
493 	int s = frames[carNum].size();
494 	if (s < 2)  return false;  // empty
495 
496 	*pFr = frames[carNum][s-1];
497 	return false;
498 }
499 
GetLastHitTime(int carNum)500 half Replay2::GetLastHitTime(int carNum)
501 {
502 	int s = frames[carNum].size();
503 	if (s < 2)  return half(0.f);  // empty
504 
505 	return frames[carNum][s-1].fHitTime;
506 }
507 
508 
509 ///  get (Play)
510 //----------------------------------------------------------------
GetFrame(float time1,ReplayFrame2 * pFr,int carNum)511 bool Replay2::GetFrame(float time1, ReplayFrame2* pFr, int carNum)
512 {
513 	if (frames.empty())  return false;
514 	int& ic = idLast;  // last index
515 
516 	int s = frames[carNum].size();
517 	if (ic > s-1)  ic = s-1;  // new size
518 	if (s < 2)  return false;  // empty
519 
520 	///  find which frame for given time
521 	float time = std::min(time1, GetTimeLength());
522 	while (ic+1 < s-1 && frames[carNum][ic+1].time <= time)  ++ic;
523 	while (ic > 0     && frames[carNum][ic].time > time)  --ic;
524 
525 	if (ic < 0 || ic >= s)
526 		return false;  //-
527 
528 
529 	if (ic == 0 || ic == s-1)
530 		*pFr = frames[carNum][ic];
531 	else
532 	{	///  linear interpolation
533 		const ReplayFrame2& t1 = frames[carNum][ic];  //cur
534 		const ReplayFrame2& t0 = frames[carNum][std::max(0, ic-1)];  //prev
535 		*pFr = frames[carNum][ic];  // rest, no interp
536 
537 		float dt = t1.time - t0.time;
538 		if (dt > 0.0001f)
539 		{
540 			float f = (time - t0.time) / dt;
541 			(*pFr).pos = t0.pos + (t1.pos - t0.pos) * f;
542 			(*pFr).rot = t0.rot.QuatSlerp(t1.rot, f);
543 
544 			int w, ww = t0.wheels.size();
545 			for (w=0; w < ww; ++w)
546 			{
547 				(*pFr).wheels[w].pos = t0.wheels[w].pos + (t1.wheels[w].pos - t0.wheels[w].pos) * f;
548 				//(*pFr).wheels[w].rot = t0.wheels[w].rot.QuatSlerp(t1.wheels[w].rot, f);  // no need
549 			}
550 	}	}
551 
552 	//  last time
553 	float end = GetTimeLength();
554 	if (time1 >= end)
555 	{
556 		pFr->fboost = 0.f;
557 		//  clear emitters at end..
558 		int w, ww = (*pFr).wheels.size();
559 		for (w=0; w < ww; ++w)
560 		{
561 			RWheel& wh = (*pFr).wheels[w];
562 			wh.slide = wh.squeal = wh.whVel = half(0.f);
563 		}
564 	}
565 
566 	//  check if ended
567 	return time1 <= end;
568 }
569 
570 //  delete frames after current time (when time did go back)
DeleteFrames(int c,float fromTime)571 void Replay2::DeleteFrames(int c, float fromTime)
572 {
573 	if (frames[c].empty())  return;
574 	while (!frames[c].empty() && frames[c][ frames[c].size()-1 ].time >= fromTime)
575 		frames[c].pop_back();
576 	header.time = fromTime;
577 }
578 
579