1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 // Filename:-	g_savegame.cpp
24 
25 #include "g_headers.h"
26 
27 #ifndef _WIN32
28 #include <unistd.h>
29 #endif
30 #include "g_local.h"
31 #include "fields.h"
32 #include "objectives.h"
33 #include "../cgame/cg_camera.h"
34 #include "g_icarus.h"
35 #include "../../code/qcommon/sstring.h"
36 #include "../code/qcommon/ojk_saved_game_helper.h"
37 
38 extern void OBJ_LoadTacticalInfo(void);
39 
40 extern int Q3_VariableSave( void );
41 extern int Q3_VariableLoad( void );
42 
43 extern void G_LoadSave_WriteMiscData(void);
44 extern void G_LoadSave_ReadMiscData(void);
45 
46 
47 static const field_t savefields_gEntity[] =
48 {
49 	{strFOFS(client),			F_GCLIENT},
50 	{strFOFS(owner),			F_GENTITY},
51 	{strFOFS(classname),		F_STRING},
52 	{strFOFS(model),			F_STRING},
53 	{strFOFS(model2),			F_STRING},
54 //	{strFOFS(model3),			F_STRING}, - MCG
55 	{strFOFS(nextTrain),		F_GENTITY},
56 	{strFOFS(prevTrain),		F_GENTITY},
57 	{strFOFS(message),			F_STRING},
58 	{strFOFS(target),			F_STRING},
59 	{strFOFS(target2),			F_STRING},
60 	{strFOFS(target3),			F_STRING},
61 	{strFOFS(target4),			F_STRING},
62 	{strFOFS(targetname),		F_STRING},
63 	{strFOFS(team),				F_STRING},
64 	{strFOFS(roff),				F_STRING},
65 //	{strFOFS(target_ent),		F_GENTITY}, - MCG
66 	{strFOFS(chain),			F_GENTITY},
67 	{strFOFS(enemy),			F_GENTITY},
68 	{strFOFS(activator),		F_GENTITY},
69 	{strFOFS(teamchain),		F_GENTITY},
70 	{strFOFS(teammaster),		F_GENTITY},
71 	{strFOFS(item),				F_ITEM},
72 	{strFOFS(NPC_type),			F_STRING},
73 	{strFOFS(closetarget),		F_STRING},
74 	{strFOFS(opentarget),		F_STRING},
75 	{strFOFS(paintarget),		F_STRING},
76 	{strFOFS(NPC_targetname),	F_STRING},
77 	{strFOFS(NPC_target),		F_STRING},
78 	{strFOFS(ownername),		F_STRING},
79 	{strFOFS(lastEnemy),		F_GENTITY},
80 	{strFOFS(behaviorSet),		F_BEHAVIORSET},
81 	{strFOFS(script_targetname),F_STRING},
82 	{strFOFS(sequencer),		F_NULL},	// CSequencer	*sequencer;
83 	{strFOFS(taskManager),		F_NULL},	// CTaskManager	*taskManager;
84 	{strFOFS(NPC),				F_BOOLPTR},
85 	{strFOFS(soundSet),			F_STRING},
86 	{strFOFS(cameraGroup),		F_STRING},
87 	{strFOFS(parms),			F_BOOLPTR},
88 	{strFOFS(fullName),			F_STRING},
89 //	{strFOFS(timers),			F_BOOLPTR},	// handled directly
90 
91 	{NULL, 0, F_IGNORE}
92 };
93 
94 static const field_t savefields_gNPC[] =
95 {
96 //	{strNPCOFS(pendingEnemy),		F_GENTITY},
97 	{strNPCOFS(touchedByPlayer),	F_GENTITY},
98 	{strNPCOFS(aimingBeam),			F_GENTITY},
99 	{strNPCOFS(eventOwner),			F_GENTITY},
100 	{strNPCOFS(coverTarg),			F_GENTITY},
101 	{strNPCOFS(tempGoal),			F_GENTITY},
102 	{strNPCOFS(goalEntity),			F_GENTITY},
103 	{strNPCOFS(lastGoalEntity),		F_GENTITY},
104 	{strNPCOFS(eventualGoal),		F_GENTITY},
105 	{strNPCOFS(captureGoal),		F_GENTITY},
106 	{strNPCOFS(defendEnt),			F_GENTITY},
107 	{strNPCOFS(greetEnt),			F_GENTITY},
108 	{strNPCOFS(group),				F_GROUP},
109 
110 	{NULL, 0, F_IGNORE}
111 };
112 
113 static const field_t savefields_LevelLocals[] =
114 {
115 	{strLLOFS(locationHead),	F_GENTITY},
116 	{strLLOFS(alertEvents),		F_ALERTEVENT},
117 	{strLLOFS(groups),			F_AIGROUPS},
118 	{NULL, 0, F_IGNORE}
119 };
120 
121 /*
122 struct gclient_s {
123 	// ps MUST be the first element, because the server expects it
124 ok	playerState_t	ps;				// communicated by server to clients
125 
126 	// private to game
127 ok	clientPersistant_t	pers;
128 ok	clientSession_t		sess;
129 
130 ok	usercmd_t	usercmd;			// most recent usercmd
131 
132 	//Client info - updated when ClientInfoChanged is called, instead of using configstrings
133 ok	clientInfo_t	clientInfo;
134 ok	renderInfo_t	renderInfo;
135 };
136 */
137 // I'll keep a blank one for now in case I need to add anything...
138 //
139 static const field_t savefields_gClient[] =
140 {
141 	{strCLOFS(ps.saberModel),	F_STRING},
142 	{strCLOFS(squadname),		F_STRING},
143 	{strCLOFS(team_leader),		F_GENTITY},
144 	{strCLOFS(leader),			F_GENTITY},
145 	{strCLOFS(follower),		F_GENTITY},
146 	{strCLOFS(formationGoal),	F_GENTITY},
147 	{strCLOFS(clientInfo.customBasicSoundDir),F_STRING},
148 	{strCLOFS(clientInfo.customCombatSoundDir),F_STRING},
149 	{strCLOFS(clientInfo.customExtraSoundDir),F_STRING},
150 	{strCLOFS(clientInfo.customJediSoundDir),F_STRING},
151 
152 	{NULL, 0, F_IGNORE}
153 };
154 
155 
156 static std::list<sstring_t> strList;
157 
158 
159 /////////// char * /////////////
160 //
161 //
GetStringNum(const char * psString)162 int GetStringNum(const char *psString)
163 {
164 	assert( psString != (char *)0xcdcdcdcd );
165 
166 	// NULL ptrs I'll write out as a strlen of -1...
167 	//
168 	if (!psString)
169 	{
170 		return -1;
171 	}
172 
173 	strList.push_back( psString );
174 	return strlen(psString) + 1;	// this gives us the chunk length for the reader later
175 }
176 
GetStringPtr(int iStrlen,char * psOriginal)177 char *GetStringPtr(int iStrlen, char *psOriginal/*may be NULL*/)
178 {
179 	if (iStrlen != -1)
180 	{
181 		static char sString[768];	// arb, inc if nec.
182 
183 		memset(sString,0, sizeof(sString));
184 
185 		assert(iStrlen+1<=(int)sizeof(sString));
186 
187 		ojk::SavedGameHelper saved_game(
188 			::gi.saved_game);
189 
190 		saved_game.read_chunk(
191 			INT_ID('S', 'T', 'R', 'G'),
192 			sString,
193 			iStrlen);
194 
195 		// we can't do string recycling with the new g_alloc pool dumping, so just always alloc here...
196 		//
197 		return G_NewString(sString);
198 	}
199 
200 	return NULL;
201 }
202 //
203 //
204 ////////////////////////////////
205 
206 
207 
208 
209 /////////// gentity_t * ////////
210 //
211 //
GetGEntityNum(gentity_t * ent)212 intptr_t GetGEntityNum(gentity_t* ent)
213 {
214 	assert( ent != (gentity_t *) 0xcdcdcdcd);
215 
216 	if (ent == NULL)
217 	{
218 		return -1;
219 	}
220 
221 	// note that I now validate the return value (to avoid triggering asserts on re-load) because of the
222 	//	way that the level_locals_t alertEvents struct contains a count of which ones are valid, so I'm guessing
223 	//	that some of them aren't (valid)...
224 	//
225 	intptr_t iReturnIndex = ent - g_entities;
226 
227 	if (iReturnIndex < 0 || iReturnIndex >= MAX_GENTITIES)
228 	{
229 		iReturnIndex = -1;	// will get a NULL ptr on reload
230 	}
231 	return iReturnIndex;
232 }
233 
GetGEntityPtr(intptr_t iEntNum)234 gentity_t *GetGEntityPtr(intptr_t iEntNum)
235 {
236 	if (iEntNum == -1)
237 	{
238 		return NULL;
239 	}
240 	assert(iEntNum >= 0);
241 	assert(iEntNum < MAX_GENTITIES);
242 	return (g_entities + iEntNum);
243 }
244 
GetGroupNumber(AIGroupInfo_t * pGroup)245 static intptr_t GetGroupNumber(AIGroupInfo_t *pGroup)
246 {
247 	assert( pGroup != (AIGroupInfo_t *) 0xcdcdcdcd);
248 
249 	if (pGroup == NULL)
250 	{
251 		return -1;
252 	}
253 
254 	int iReturnIndex = pGroup - level.groups;
255 	if (iReturnIndex < 0 || iReturnIndex >= (int)(sizeof(level.groups) / sizeof(level.groups[0])) )
256 	{
257 		iReturnIndex = -1;	// will get a NULL ptr on reload
258 	}
259 	return iReturnIndex;
260 }
261 
GetGroupPtr(intptr_t iGroupNum)262 static AIGroupInfo_t *GetGroupPtr(intptr_t iGroupNum)
263 {
264 	if (iGroupNum == -1)
265 	{
266 		return NULL;
267 	}
268 	assert(iGroupNum >= 0);
269 	assert( iGroupNum < (int)ARRAY_LEN( level.groups ) );
270 	return (level.groups + iGroupNum);
271 }
272 
273 
274 
275 /////////// gclient_t * ////////
276 //
277 //
GetGClientNum(gclient_t * c)278 intptr_t GetGClientNum(gclient_t *c)
279 {
280 	assert(c != (gclient_t *)0xcdcdcdcd);
281 
282 	if (c == NULL)
283 	{
284 		return -1;
285 	}
286 
287 	return (c - level.clients);
288 }
289 
GetGClientPtr(intptr_t c)290 gclient_t *GetGClientPtr(intptr_t c)
291 {
292 	if (c == -1)
293 	{
294 		return NULL;
295 	}
296 	if (c == -2)
297 	{
298 		return (gclient_t *) -2;	// preserve this value so that I know to load in one of Mike's private NPC clients later
299 	}
300 
301 	assert(c >= 0);
302 	assert(c < level.maxclients);
303 	return (level.clients + c);
304 }
305 //
306 //
307 ////////////////////////////////
308 
309 
310 /////////// gitem_t * //////////
311 //
312 //
GetGItemNum(gitem_t * pItem)313 int GetGItemNum (gitem_t *pItem)
314 {
315 	assert(pItem != (gitem_t*) 0xcdcdcdcd);
316 
317 	if (pItem == NULL)
318 	{
319 		return -1;
320 	}
321 
322 	return pItem - bg_itemlist;
323 }
324 
GetGItemPtr(int iItem)325 gitem_t *GetGItemPtr(int iItem)
326 {
327 	if (iItem == -1)
328 	{
329 		return NULL;
330 	}
331 
332 	assert(iItem >= 0);
333 	assert(iItem < bg_numItems);
334 	return &bg_itemlist[iItem];
335 }
336 //
337 //
338 ////////////////////////////////
339 
340 
EnumerateField(const field_t * pField,byte * pbBase)341 void EnumerateField(const field_t *pField, byte *pbBase)
342 {
343 	void *pv = (void *)(pbBase + pField->iOffset);
344 
345 	switch (pField->eFieldType)
346 	{
347 	case F_STRING:
348 		*(intptr_t *)pv = GetStringNum(*(char **)pv);
349 		break;
350 
351 	case F_GENTITY:
352 		*(intptr_t *)pv = GetGEntityNum(*(gentity_t **)pv);
353 		break;
354 
355 	case F_GROUP:
356 		*(intptr_t *)pv = GetGroupNumber(*(AIGroupInfo_t **)pv);
357 		break;
358 
359 	case F_GCLIENT:
360 	{
361 		// unfortunately, I now need to see if this is a 'real' client (and therefore resolve to an enum), or
362 		//	whether it's one of Mike G's private clients that needs saving here (thanks Mike...)
363 		//
364 		gentity_t *ent = (gentity_t *) pbBase;
365 
366 		if (ent->NPC == NULL)
367 		{
368 			// regular client...
369 			//
370 			*(intptr_t *)pv = GetGClientNum(*(gclient_t **)pv);
371 			break;
372 		}
373 		else
374 		{
375 			// this must be one of Mike's, so mark it as special...
376 			//
377 			*(intptr_t *)pv = -2;	// yeuch, but distinguishes it from a valid 0 index, or -1 for client==NULL
378 		}
379 	}
380 		break;
381 
382 	case F_ITEM:
383 		*(intptr_t *)pv = GetGItemNum(*(gitem_t **)pv);
384 		break;
385 
386 	case F_BEHAVIORSET:
387 		{
388 			const char **p = (const char **) pv;
389 			for (int i=0; i<NUM_BSETS; i++)
390 			{
391 				pv = &p[i];	// since you can't ++ a void ptr
392 				*(intptr_t *)pv = GetStringNum(*(char **)pv);
393 			}
394 		}
395 		break;
396 
397 /*MCG
398 	case F_BODYQUEUE:
399 		{
400 			gentity_t **p = (gentity_t **) pv;
401 			for (int i=0; i<BODY_QUEUE_SIZE; i++)
402 			{
403 				pv = &p[i];	// since you can't ++ a void ptr
404 				*(int *)pv = GetGEntityNum(*(gentity_t **)pv);
405 			}
406 		}
407 		break;
408 */
409 
410 	case F_ALERTEVENT:	// convert all gentity_t ptrs in an alertEvent array into indexes...
411 		{
412 			alertEvent_t* p = (alertEvent_t *) pv;
413 
414 			for (int i=0; i<MAX_ALERT_EVENTS; i++)
415 			{
416 				p[i].owner = (gentity_t *) GetGEntityNum(p[i].owner);
417 			}
418 		}
419 		break;
420 
421 	case F_AIGROUPS:	// convert to ptrs within this into indexes...
422 		{
423 			AIGroupInfo_t* p = (AIGroupInfo_t *) pv;
424 
425 			for (int i=0; i<MAX_FRAME_GROUPS; i++)
426 			{
427 				p[i].enemy		= (gentity_t *) GetGEntityNum(p[i].enemy);
428 				p[i].commander	= (gentity_t *) GetGEntityNum(p[i].commander);
429 			}
430 		}
431 		break;
432 
433 	case F_BOOLPTR:
434 		*(qboolean *)pv = (*(int *)pv) ? qtrue : qfalse;
435 		break;
436 
437 	// These are pointers that are always recreated
438 	case F_NULL:
439 		*(void **)pv = NULL;
440 		break;
441 
442 	case F_IGNORE:
443 		break;
444 
445 	default:
446 		G_Error ("EnumerateField: unknown field type");
447 		break;
448 	}
449 }
450 
451 template<typename T>
EnumerateFields(const field_t * pFields,T * src_instance,unsigned int ulChid)452 static void EnumerateFields(
453 	const field_t* pFields,
454 	T* src_instance,
455 	unsigned int ulChid)
456 {
457 	strList.clear();
458 
459 	byte* pbData = reinterpret_cast<byte*>(
460 		src_instance);
461 
462 	// enumerate all the fields...
463 	//
464 	if (pFields)
465 	{
466 		for (auto pField = pFields; pField->psName; ++pField)
467 		{
468 			assert(pField->iOffset < sizeof(T));
469 			::EnumerateField(pField, pbData);
470 		}
471 	}
472 
473 	ojk::SavedGameHelper saved_game(
474 		::gi.saved_game);
475 
476 	// save out raw data...
477 	//
478 	saved_game.reset_buffer();
479 
480 	src_instance->sg_export(
481 		saved_game);
482 
483 	saved_game.write_chunk(
484 		ulChid);
485 
486 	// save out any associated strings..
487 	//
488 	for (const auto& it : strList)
489 	{
490 		saved_game.write_chunk(
491 			INT_ID('S', 'T', 'R', 'G'),
492 			it.c_str(),
493 			static_cast<int>(it.length() + 1));
494 	}
495 }
496 
EvaluateField(const field_t * pField,byte * pbBase,byte * pbOriginalRefData)497 static void EvaluateField(const field_t *pField, byte *pbBase, byte *pbOriginalRefData/* may be NULL*/)
498 {
499 	void *pv		 = (void *)(pbBase			  + pField->iOffset);
500 	void *pvOriginal = (void *)(pbOriginalRefData + pField->iOffset);
501 
502 	switch (pField->eFieldType)
503 	{
504 	case F_STRING:
505 		*(char **)pv = GetStringPtr(*(intptr_t *)pv, pbOriginalRefData?*(char**)pvOriginal:NULL);
506 		break;
507 
508 	case F_GENTITY:
509 		*(gentity_t **)pv = GetGEntityPtr(*(intptr_t *)pv);
510 		break;
511 
512 	case F_GROUP:
513 		*(AIGroupInfo_t **)pv = GetGroupPtr(*(intptr_t *)pv);
514 		break;
515 
516 	case F_GCLIENT:
517 		*(gclient_t **)pv = GetGClientPtr(*(intptr_t *)pv);
518 		break;
519 
520 	case F_ITEM:
521 		*(gitem_t **)pv = GetGItemPtr(*(intptr_t *)pv);
522 		break;
523 
524 	case F_BEHAVIORSET:
525 		{
526 			char **p = (char **) pv;
527 			char **pO= (char **) pvOriginal;
528 			for (int i=0; i<NUM_BSETS; i++, p++, pO++)
529 			{
530 				*p = GetStringPtr(*(intptr_t *)p, pbOriginalRefData?*(char **)pO:NULL);
531 			}
532 		}
533 		break;
534 
535 /*MCG
536 	case F_BODYQUEUE:
537 		{
538 			gentity_t **p = (gentity_t **) pv;
539 			for (int i=0; i<BODY_QUEUE_SIZE; i++, p++)
540 			{
541 				*p = GetGEntityPtr(*(int *)p);
542 			}
543 		}
544 		break;
545 */
546 
547 	case F_ALERTEVENT:
548 		{
549 			alertEvent_t* p = (alertEvent_t *) pv;
550 
551 			for (int i=0; i<MAX_ALERT_EVENTS; i++)
552 			{
553 				p[i].owner = GetGEntityPtr((intptr_t)(p[i].owner));
554 			}
555 		}
556 		break;
557 
558 	case F_AIGROUPS:	// convert to ptrs within this into indexes...
559 		{
560 			AIGroupInfo_t* p = (AIGroupInfo_t *) pv;
561 
562 			for (int i=0; i<MAX_FRAME_GROUPS; i++)
563 			{
564 				p[i].enemy		= GetGEntityPtr((intptr_t)(p[i].enemy));
565 				p[i].commander	= GetGEntityPtr((intptr_t)(p[i].commander));
566 			}
567 		}
568 		break;
569 
570 //	// These fields are patched in when their relevant owners are loaded
571 	case F_BOOLPTR:
572 	case F_NULL:
573 		break;
574 
575 	case F_IGNORE:
576 		break;
577 
578 	default:
579 		G_Error ("EvaluateField: unknown field type");
580 		break;
581 	}
582 }
583 
584 
585 // copy of function in sv_savegame
SG_GetChidText(unsigned int chid)586 static const char *SG_GetChidText(unsigned int chid)
587 {
588 	static char	chidtext[5];
589 
590 	byteAlias_t *ba = (byteAlias_t *)&chidtext;
591 	ba->ui = BigLong( chid );
592 	chidtext[4] = '\0';
593 
594 	return chidtext;
595 }
596 
597 template<typename T>
EvaluateFields(const field_t * pFields,T * pbData,T * pbOriginalRefData,unsigned int ulChid)598 static void EvaluateFields(
599 	const field_t* pFields,
600 	T* pbData,
601 	T* pbOriginalRefData,
602 	unsigned int ulChid)
603 {
604 	ojk::SavedGameHelper saved_game(
605 		::gi.saved_game);
606 
607 	if (!saved_game.try_read_chunk(
608 		ulChid,
609 		*pbData))
610 	{
611 		::G_Error(
612 			::va("EvaluateFields(): variable-sized chunk '%s' without handler!",
613 				::SG_GetChidText(ulChid)));
614 	}
615 
616 	if (pFields)
617 	{
618 		for (auto pField = pFields; pField->psName; ++pField)
619 		{
620 			::EvaluateField(
621 				pField,
622 				reinterpret_cast<byte*>(pbData),
623 				reinterpret_cast<byte*>(pbOriginalRefData));
624 		}
625 	}
626 }
627 
628 /*
629 ==============
630 WriteLevelLocals
631 
632 All pointer variables (except function pointers) must be handled specially.
633 ==============
634 */
WriteLevelLocals()635 static void WriteLevelLocals ()
636 {
637 	level_locals_t *temp = (level_locals_t *)gi.Malloc(sizeof(level_locals_t), TAG_TEMP_WORKSPACE, qfalse);
638 	*temp = level;	// copy out all data into a temp space
639 
640 	EnumerateFields(savefields_LevelLocals, temp, INT_ID('L','V','L','C'));
641 	gi.Free(temp);
642 }
643 
644 /*
645 ==============
646 ReadLevelLocals
647 
648 All pointer variables (except function pointers) must be handled specially.
649 ==============
650 */
ReadLevelLocals()651 static void ReadLevelLocals ()
652 {
653 	// preserve client ptr either side of the load, because clients are already saved/loaded through Read/Writegame...
654 	//
655 	gclient_t *pClients = level.clients;	// save clients
656 
657 	level_locals_t *temp = (level_locals_t *)gi.Malloc(sizeof(level_locals_t), TAG_TEMP_WORKSPACE, qfalse);
658 	*temp = level;
659 	EvaluateFields(savefields_LevelLocals, temp, &level, INT_ID('L','V','L','C'));
660 	level = *temp;					// struct copy
661 
662 	level.clients = pClients;				// restore clients
663 	gi.Free(temp);
664 }
665 
WriteGEntities(qboolean qbAutosave)666 static void WriteGEntities(qboolean qbAutosave)
667 {
668 	int iCount = 0;
669 	int i;
670 
671 	for (i=0; i<(qbAutosave?1:globals.num_entities); i++)
672 	{
673 		gentity_t* ent = &g_entities[i];
674 
675 		if ( ent->inuse )
676 		{
677 			iCount++;
678 		}
679 	}
680 
681 	ojk::SavedGameHelper saved_game(
682 		::gi.saved_game);
683 
684 	saved_game.write_chunk<int32_t>(
685 		INT_ID('N', 'M', 'E', 'D'),
686 		iCount);
687 
688 	for (i=0; i<(qbAutosave?1:globals.num_entities); i++)
689 	{
690 		gentity_t* ent = &g_entities[i];
691 
692 		if ( ent->inuse)
693 		{
694 			saved_game.write_chunk<int32_t>(
695 				INT_ID('E', 'D', 'N', 'M'),
696 				i);
697 
698 			qboolean qbLinked = ent->linked;
699 			gi.unlinkentity( ent );
700 			gentity_t tempEnt = *ent;	// make local copy
701 			tempEnt.linked = qbLinked;
702 
703 			if (qbLinked)
704 			{
705 				gi.linkentity( ent );
706 			}
707 
708 			EnumerateFields(savefields_gEntity, &tempEnt, INT_ID('G','E','N','T'));
709 
710 			// now for any fiddly bits that would be rather awkward to build into the enumerator...
711 			//
712 			if (tempEnt.NPC)
713 			{
714 				gNPC_t npc = *ent->NPC;	// NOT *tempEnt.NPC; !! :-)
715 
716 				EnumerateFields(savefields_gNPC, &npc, INT_ID('G','N','P','C'));
717 			}
718 
719 			if (tempEnt.client == (gclient_t *)-2)	// I know, I know...
720 			{
721 				gclient_t client = *ent->client;	// NOT *tempEnt.client!!
722 				EnumerateFields(savefields_gClient, &client, INT_ID('G','C','L','I'));
723 			}
724 
725 			if (tempEnt.parms)
726 			{
727 				saved_game.write_chunk(
728 					INT_ID('P', 'A', 'R', 'M'),
729 					*ent->parms);
730 			}
731 
732 			// the scary ghoul2 saver stuff...  (fingers crossed)
733 			//
734 			gi.G2API_SaveGhoul2Models(tempEnt.ghoul2);
735 			tempEnt.ghoul2.kill(); // this handle was shallow copied from an ent. We don't want it destroyed
736 		}
737 	}
738 
739 	//Write out all entity timers
740 	TIMER_Save();//WriteEntityTimers();
741 
742 	if (!qbAutosave)
743 	{
744 		//Save out ICARUS information
745 		iICARUS->Save();
746 
747 		// this marker needs to be here, it lets me know if Icarus doesn't load everything back later,
748 		//	which has happened, and doesn't always show up onscreen until certain game situations.
749 		//	This saves time debugging, and makes things easier to track.
750 		//
751 		static int iBlah = 1234;
752 
753 		saved_game.write_chunk<int32_t>(
754 			INT_ID('I', 'C', 'O', 'K'),
755 			iBlah);
756 	}
757 	if (!qbAutosave )//really shouldn't need to write these bits at all, just restore them from the ents...
758 	{
759 		WriteInUseBits();
760 	}
761 }
762 
ReadGEntities(qboolean qbAutosave)763 static void ReadGEntities(qboolean qbAutosave)
764 {
765 	int		iCount = 0;
766 	int		i;
767 
768 	ojk::SavedGameHelper saved_game(
769 		::gi.saved_game);
770 
771 	saved_game.read_chunk<int32_t>(
772 		INT_ID('N', 'M', 'E', 'D'),
773 		iCount);
774 
775 	int iPreviousEntRead = -1;
776 	for (i=0; i<iCount; i++)
777 	{
778 		int iEntIndex = 0;
779 
780 		saved_game.read_chunk<int32_t>(
781 			INT_ID('E', 'D', 'N', 'M'),
782 			iEntIndex);
783 
784 		if (iEntIndex >= globals.num_entities)
785 		{
786 			globals.num_entities = iEntIndex + 1;
787 		}
788 
789 		if (iPreviousEntRead != iEntIndex-1)
790 		{
791 			for (int j=iPreviousEntRead+1; j!=iEntIndex; j++)
792 			{
793 				if ( g_entities[j].inuse )		// not actually necessary
794 				{
795 					G_FreeEntity(&g_entities[j]);
796 				}
797 			}
798 		}
799 		iPreviousEntRead = iEntIndex;
800 
801 		// slightly naff syntax here, but makes a few ops clearer later...
802 		//
803 		gentity_t  entity;
804 //		gentity_t* pEntOriginal	= &g_entities[iEntIndex];
805 //		gentity_t* pEnt			= &entity;
806 		gentity_t* pEntOriginal	= &entity;
807 		gentity_t* pEnt			= &g_entities[iEntIndex];
808 		*pEntOriginal = *pEnt;	// struct copy, so we can refer to original
809 		pEntOriginal->ghoul2.kill();
810 		gi.unlinkentity(pEnt);
811 		ICARUS_FreeEnt (pEnt);
812 		//
813 		// sneaky:  destroy the ghoul2 object within this struct before binary-loading over the top of it...
814 		//
815 		gi.G2API_LoadSaveCodeDestructGhoul2Info(pEnt->ghoul2);
816 		pEnt->ghoul2.kill();
817 		EvaluateFields(savefields_gEntity, pEnt, pEntOriginal, INT_ID('G','E','N','T'));
818 		pEnt->ghoul2.kill();
819 
820 		// now for any fiddly bits...
821 		//
822 		if (pEnt->NPC)	// will be qtrue/qfalse
823 		{
824 			gNPC_t tempNPC;
825 
826 			EvaluateFields(savefields_gNPC, &tempNPC,pEntOriginal->NPC, INT_ID('G','N','P','C'));
827 
828 			// so can we pinch the original's one or do we have to alloc a new one?...
829 			//
830 			if (pEntOriginal->NPC)
831 			{
832 				// pinch this G_Alloc handle...
833 				//
834 				pEnt->NPC = pEntOriginal->NPC;
835 			}
836 			else
837 			{
838 				// original didn't have one (hmmm...), so make a new one...
839 				//
840 				//assert(0);	// I want to know about this, though not in release
841 				pEnt->NPC = (gNPC_t *) G_Alloc(sizeof(*pEnt->NPC));
842 			}
843 
844 			// copy over the one we've just loaded...
845 			//
846 			*pEnt->NPC = tempNPC;	// struct copy
847 
848 		}
849 
850 		if (pEnt->client == (gclient_t*) -2)	// one of Mike G's NPC clients?
851 		{
852 			gclient_t tempGClient;
853 
854 			EvaluateFields(savefields_gClient, &tempGClient, pEntOriginal->client, INT_ID('G','C','L','I'));
855 
856 			// can we pinch the original's client handle or do we have to alloc a new one?...
857 			//
858 			if (pEntOriginal->client)
859 			{
860 				// pinch this G_Alloc handle...
861 				//
862 				pEnt->client = pEntOriginal->client;
863 			}
864 			else
865 			{
866 				// original didn't have one (hmmm...) so make a new one...
867 				//
868 				pEnt->client = (gclient_t *) G_Alloc(sizeof(*pEnt->client));
869 			}
870 
871 			// copy over the one we've just loaded....
872 			//
873 			*pEnt->client = tempGClient;	// struct copy
874 		}
875 
876 		// Some Icarus thing... (probably)
877 		//
878 		if (pEnt->parms)	// will be qtrue/qfalse
879 		{
880 			parms_t tempParms;
881 
882 			saved_game.read_chunk(
883 				INT_ID('P', 'A', 'R', 'M'),
884 				tempParms);
885 
886 			// so can we pinch the original's one or do we have to alloc a new one?...
887 			//
888 			if (pEntOriginal->parms)
889 			{
890 				// pinch this G_Alloc handle...
891 				//
892 				pEnt->parms = pEntOriginal->parms;
893 			}
894 			else
895 			{
896 				// original didn't have one, so make a new one...
897 				//
898 				pEnt->parms = (parms_t *) G_Alloc(sizeof(*pEnt->parms));
899 			}
900 
901 			// copy over the one we've just loaded...
902 			//
903 			*pEnt->parms = tempParms;	// struct copy
904 		}
905 
906 		// the scary ghoul2 stuff...  (fingers crossed)
907 		//
908 		{
909 #ifdef JK2_MODE
910 			// Skip GL2 data size
911 			saved_game.read_chunk(
912 				INT_ID('G', 'L', '2', 'S'));
913 #endif // JK2_MODE
914 
915 			saved_game.read_chunk(
916 				INT_ID('G', 'H', 'L', '2'));
917 
918 			gi.G2API_LoadGhoul2Models(
919 				pEnt->ghoul2,
920 				nullptr);
921 		}
922 
923 //		gi.unlinkentity (pEntOriginal);
924 //		ICARUS_FreeEnt( pEntOriginal );
925 //		*pEntOriginal = *pEnt;	// struct copy
926 //		qboolean qbLinked = pEntOriginal->linked;
927 //		pEntOriginal->linked = qfalse;
928 //		if (qbLinked)
929 //		{
930 //			gi.linkentity (pEntOriginal);
931 //		}
932 
933 		// because the sytem stores sfx_t handles directly instead of the set, we have to reget the set's sfx_t...
934 		//
935 		if (pEnt->s.eType == ET_MOVER && pEnt->s.loopSound>0)
936 		{
937 			if ( VALIDSTRING( pEnt->soundSet ))
938 			{
939 				extern int BMS_MID;	// from g_mover
940 				pEnt->s.loopSound = CAS_GetBModelSound( pEnt->soundSet, BMS_MID );
941 				if (pEnt->s.loopSound == -1)
942 				{
943 					pEnt->s.loopSound = 0;
944 				}
945 			}
946 		}
947 
948 		qboolean qbLinked = pEnt->linked;
949 		pEnt->linked = qfalse;
950 		if (qbLinked)
951 		{
952 			gi.linkentity (pEnt);
953 		}
954 	}
955 
956 	//Read in all the entity timers
957 	TIMER_Load();//ReadEntityTimers();
958 
959 	if (!qbAutosave)
960 	{
961 		// now zap any g_ents that were inuse when the level was loaded, but are no longer in use in the saved version
962 		//	that we've just loaded...
963 		//
964 		for (i=iPreviousEntRead+1; i<globals.num_entities; i++)
965 		{
966 			if ( g_entities[i].inuse )	// not actually necessary
967 			{
968 				G_FreeEntity(&g_entities[i]);
969 			}
970 		}
971 
972 		//Load ICARUS information
973 		ICARUS_EntList.clear();
974 		iICARUS->Load();
975 
976 		// check that Icarus has loaded everything it saved out by having a marker chunk after it...
977 		//
978 		static int iBlah = 1234;
979 
980 		saved_game.read_chunk<int32_t>(
981 			INT_ID('I', 'C', 'O', 'K'),
982 			iBlah);
983 	}
984 	if (!qbAutosave)
985 	{
986 		ReadInUseBits();//really shouldn't need to read these bits in at all, just restore them from the ents...
987 	}
988 }
989 
990 
WriteLevel(qboolean qbAutosave)991 void WriteLevel(qboolean qbAutosave)
992 {
993 	if (!qbAutosave) //-always save the client
994 	{
995 		// write out one client - us!
996 		//
997 		assert(level.maxclients == 1);	// I'll need to know if this changes, otherwise I'll need to change the way ReadGame works
998 		gclient_t client = level.clients[0];
999 		EnumerateFields(savefields_gClient, &client, INT_ID('G','C','L','I'));
1000 		WriteLevelLocals();	// level_locals_t level
1001 	}
1002 
1003 	OBJ_SaveObjectiveData();
1004 
1005 	/////////////
1006 	WriteGEntities(qbAutosave);
1007 	Q3_VariableSave();
1008 	G_LoadSave_WriteMiscData();
1009 
1010 	extern void CG_WriteTheEvilCGHackStuff(void);
1011 	CG_WriteTheEvilCGHackStuff();
1012 
1013 	// (Do NOT put any write-code below this line)
1014 	//
1015 	// put out an end-marker so that the load code can check everything was read in...
1016 	//
1017 	static int iDONE = 1234;
1018 
1019 	ojk::SavedGameHelper saved_game(
1020 		::gi.saved_game);
1021 
1022 	saved_game.write_chunk<int32_t>(
1023 		INT_ID('D', 'O', 'N', 'E'),
1024 		iDONE);
1025 }
1026 
ReadLevel(qboolean qbAutosave,qboolean qbLoadTransition)1027 void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
1028 {
1029 	if ( qbLoadTransition )
1030 	{
1031 		//loadtransitions do not need to read the objectives and client data from the level they're going to
1032 		//In a loadtransition, client data is carried over on the server and will be stomped later anyway.
1033 		//The objective info (in client->sess data), however, is read in from G_ReadSessionData which is called before this func,
1034 		//we do NOT want to stomp that session data when doing a load transition
1035 
1036 		//However, we should still save this info out because these savegames may need to be
1037 		//loaded normally later- perhaps if you die and need to respawn, perhaps as some kind
1038 		//of emergency savegame for resuming, etc.
1039 
1040 		//SO: We read it in, but throw it away.
1041 
1042 		//Read & throw away gclient info
1043 		gclient_t junkClient;
1044 		EvaluateFields(savefields_gClient, &junkClient, &level.clients[0], INT_ID('G','C','L','I'));
1045 
1046 		//Read & throw away objective info
1047 		ojk::SavedGameHelper saved_game(
1048 			::gi.saved_game);
1049 
1050 		saved_game.read_chunk(
1051 			INT_ID('O', 'B', 'J', 'T'));
1052 
1053 		ReadLevelLocals();	// level_locals_t level
1054 	}
1055 	else
1056 	{
1057 		if (!qbAutosave )//always load the client unless it's an autosave
1058 		{
1059 			assert(level.maxclients == 1);	// I'll need to know if this changes, otherwise I'll need to change the way things work
1060 
1061 			gclient_t GClient;
1062 			EvaluateFields(savefields_gClient, &GClient, &level.clients[0], INT_ID('G','C','L','I'));
1063 			level.clients[0] = GClient;	// struct copy
1064 			ReadLevelLocals();	// level_locals_t level
1065 		}
1066 
1067 		OBJ_LoadObjectiveData();//loads mission objectives AND tactical info
1068 	}
1069 
1070 	/////////////
1071 
1072 	ReadGEntities(qbAutosave);
1073 	Q3_VariableLoad();
1074 	G_LoadSave_ReadMiscData();
1075 
1076 	extern void CG_ReadTheEvilCGHackStuff(void);
1077 	CG_ReadTheEvilCGHackStuff();
1078 
1079 	// (Do NOT put any read-code below this line)
1080 	//
1081 	// check that the whole file content was loaded by specifically requesting an end-marker...
1082 	//
1083 	static int iDONE = 1234;
1084 
1085 	ojk::SavedGameHelper saved_game(
1086 		::gi.saved_game);
1087 
1088 	saved_game.read_chunk<int32_t>(
1089 		INT_ID('D', 'O', 'N', 'E'),
1090 		iDONE);
1091 }
1092 
1093 extern int killPlayerTimer;
GameAllowedToSaveHere(void)1094 qboolean GameAllowedToSaveHere(void)
1095 {
1096 	return (qboolean)(!in_camera && !killPlayerTimer);
1097 }
1098 
1099 //////////////////// eof /////////////////////
1100