1 //----------------------------------------------------------------------------
2 //  EDGE New SaveGame Handling (Main)
3 //----------------------------------------------------------------------------
4 //
5 //  Copyright (c) 1999-2008  The EDGE Team.
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 // See the file "docs/save_sys.txt" for a complete description of the
20 // new savegame system.
21 //
22 
23 #include "i_defs.h"
24 
25 #include "epi/path.h"
26 #include "epi/str_format.h"
27 #include "epi/filesystem.h"
28 
29 #include "dm_state.h"
30 #include "dstrings.h"
31 #include "e_main.h"
32 #include "g_game.h"
33 #include "f_interm.h"
34 #include "m_math.h"
35 #include "m_random.h"
36 #include "p_local.h"
37 #include "p_spec.h"
38 #include "r_state.h"
39 #include "sv_chunk.h"
40 #include "sv_main.h"
41 #include "w_wad.h"
42 #include "z_zone.h"
43 
44 
45 savestruct_t *sv_known_structs;
46 savearray_t  *sv_known_arrays;
47 
48 // the current element of an array being read/written
49 void *sv_current_elem;
50 
51 
52 // sv_mobj.c
53 extern savestruct_t sv_struct_mobj;
54 extern savestruct_t sv_struct_spawnpoint;
55 extern savestruct_t sv_struct_iteminque;
56 
57 extern savearray_t sv_array_mobj;
58 extern savearray_t sv_array_iteminque;
59 
60 // sv_play.c
61 extern savestruct_t sv_struct_player;
62 extern savestruct_t sv_struct_playerweapon;
63 extern savestruct_t sv_struct_playerammo;
64 extern savestruct_t sv_struct_psprite;
65 
66 extern savearray_t sv_array_player;
67 
68 // sv_level.c
69 extern savestruct_t sv_struct_surface;
70 extern savestruct_t sv_struct_side;
71 extern savestruct_t sv_struct_line;
72 extern savestruct_t sv_struct_regprops;
73 extern savestruct_t sv_struct_exfloor;
74 extern savestruct_t sv_struct_sector;
75 
76 extern savearray_t sv_array_side;
77 extern savearray_t sv_array_line;
78 extern savearray_t sv_array_exfloor;
79 extern savearray_t sv_array_sector;
80 
81 // sv_misc.c
82 extern savestruct_t sv_struct_button;
83 extern savestruct_t sv_struct_light;
84 extern savestruct_t sv_struct_trigger;
85 extern savestruct_t sv_struct_drawtip;
86 extern savestruct_t sv_struct_plane_move;
87 extern savestruct_t sv_struct_slider_move;
88 
89 extern savearray_t sv_array_button;
90 extern savearray_t sv_array_light;
91 extern savearray_t sv_array_trigger;
92 extern savearray_t sv_array_drawtip;
93 extern savearray_t sv_array_plane_move;
94 extern savearray_t sv_array_slider_move;
95 
96 
97 //----------------------------------------------------------------------------
98 //
99 //  GET ROUTINES
100 //
101 
SR_GetByte(void * storage,int index,void * extra)102 bool SR_GetByte(void *storage, int index, void *extra)
103 {
104 	((unsigned char *)storage)[index] = SV_GetByte();
105 	return true;
106 }
107 
SR_GetShort(void * storage,int index,void * extra)108 bool SR_GetShort(void *storage, int index, void *extra)
109 {
110 	((unsigned short *)storage)[index] = SV_GetShort();
111 	return true;
112 }
113 
SR_GetInt(void * storage,int index,void * extra)114 bool SR_GetInt(void *storage, int index, void *extra)
115 {
116 	((unsigned int *)storage)[index] = SV_GetInt();
117 	return true;
118 }
119 
SR_GetAngle(void * storage,int index,void * extra)120 bool SR_GetAngle(void *storage, int index, void *extra)
121 {
122 	((angle_t *)storage)[index] = SV_GetAngle();
123 	return true;
124 }
125 
SR_GetFloat(void * storage,int index,void * extra)126 bool SR_GetFloat(void *storage, int index, void *extra)
127 {
128 	((float *)storage)[index] = SV_GetFloat();
129 	return true;
130 }
131 
SR_GetBoolean(void * storage,int index,void * extra)132 bool SR_GetBoolean(void *storage, int index, void *extra)
133 {
134 	((bool *)storage)[index] = SV_GetInt() ? true : false;
135 	return true;
136 }
137 
SR_GetVec2(void * storage,int index,void * extra)138 bool SR_GetVec2(void *storage, int index, void *extra)
139 {
140 	((vec2_t *)storage)[index].x = SV_GetFloat();
141 	((vec2_t *)storage)[index].y = SV_GetFloat();
142 	return true;
143 }
144 
SR_GetVec3(void * storage,int index,void * extra)145 bool SR_GetVec3(void *storage, int index, void *extra)
146 {
147 	((vec3_t *)storage)[index].x = SV_GetFloat();
148 	((vec3_t *)storage)[index].y = SV_GetFloat();
149 	((vec3_t *)storage)[index].z = SV_GetFloat();
150 	return true;
151 }
152 
SR_GetFloatFromInt(void * storage,int index,void * extra)153 bool SR_GetFloatFromInt(void *storage, int index, void *extra)
154 {
155 	((float *)storage)[index] = (float)SV_GetInt();
156 	return true;
157 }
158 
159 //
160 // For backwards compatibility with old savegames, keep the mlook angle
161 // stored in the savegame file as a slope.  Because we forbid looking
162 // directly up and down, there is no problem with infinity.
163 //
SR_GetAngleFromSlope(void * storage,int index,void * extra)164 bool SR_GetAngleFromSlope(void *storage, int index, void *extra)
165 {
166 	((angle_t *)storage)[index] = M_ATan(SV_GetFloat());
167 	return true;
168 }
169 
170 
171 //----------------------------------------------------------------------------
172 //
173 //  COMMON PUT ROUTINES
174 //
175 
SR_PutByte(void * storage,int index,void * extra)176 void SR_PutByte(void *storage, int index, void *extra)
177 {
178 	SV_PutByte(((unsigned char *)storage)[index]);
179 }
180 
SR_PutShort(void * storage,int index,void * extra)181 void SR_PutShort(void *storage, int index, void *extra)
182 {
183 	SV_PutShort(((unsigned short *)storage)[index]);
184 }
185 
SR_PutInt(void * storage,int index,void * extra)186 void SR_PutInt(void *storage, int index, void *extra)
187 {
188 	SV_PutInt(((unsigned int *)storage)[index]);
189 }
190 
SR_PutAngle(void * storage,int index,void * extra)191 void SR_PutAngle(void *storage, int index, void *extra)
192 {
193 	SV_PutAngle(((angle_t *)storage)[index]);
194 }
195 
SR_PutFloat(void * storage,int index,void * extra)196 void SR_PutFloat(void *storage, int index, void *extra)
197 {
198 	SV_PutFloat(((float *)storage)[index]);
199 }
200 
SR_PutBoolean(void * storage,int index,void * extra)201 void SR_PutBoolean(void *storage, int index, void *extra)
202 {
203 	SV_PutInt(((bool *)storage)[index] ? 1 : 0);
204 }
205 
SR_PutVec2(void * storage,int index,void * extra)206 void SR_PutVec2(void *storage, int index, void *extra)
207 {
208 	SV_PutFloat(((vec2_t *)storage)[index].x);
209 	SV_PutFloat(((vec2_t *)storage)[index].y);
210 }
211 
SR_PutVec3(void * storage,int index,void * extra)212 void SR_PutVec3(void *storage, int index, void *extra)
213 {
214 	SV_PutFloat(((vec3_t *)storage)[index].x);
215 	SV_PutFloat(((vec3_t *)storage)[index].y);
216 	SV_PutFloat(((vec3_t *)storage)[index].z);
217 }
218 
SR_PutAngleToSlope(void * storage,int index,void * extra)219 void SR_PutAngleToSlope(void *storage, int index, void *extra)
220 {
221 	angle_t val = ((angle_t *)storage)[index];
222 
223 	SYS_ASSERT(val < ANG90 || val > ANG270);
224 
225 	SV_PutFloat(M_Tan(val));
226 }
227 
228 
229 //----------------------------------------------------------------------------
230 //
231 //  ADMININISTRATION
232 //
233 
AddKnownStruct(savestruct_t * S)234 static void AddKnownStruct(savestruct_t *S)
235 {
236 	S->next = sv_known_structs;
237 	sv_known_structs = S;
238 }
239 
AddKnownArray(savearray_t * A)240 static void AddKnownArray(savearray_t *A)
241 {
242 	A->next = sv_known_arrays;
243 	sv_known_arrays = A;
244 }
245 
246 
SV_MainInit(void)247 void SV_MainInit(void)
248 {
249 	// One-time initialisation.  Sets up lists of known structures
250 	// and arrays.
251 
252 	SV_ChunkInit();
253 
254 	// sv_mobj.c
255 	AddKnownStruct(&sv_struct_mobj);
256 	AddKnownStruct(&sv_struct_spawnpoint);
257 	AddKnownStruct(&sv_struct_iteminque);
258 
259 	AddKnownArray(&sv_array_mobj);
260 	AddKnownArray(&sv_array_iteminque);
261 
262 	// sv_play.c
263 	AddKnownStruct(&sv_struct_player);
264 	AddKnownStruct(&sv_struct_playerweapon);
265 	AddKnownStruct(&sv_struct_playerammo);
266 	AddKnownStruct(&sv_struct_psprite);
267 
268 	AddKnownArray(&sv_array_player);
269 
270 	// sv_level.c
271 	AddKnownStruct(&sv_struct_surface);
272 	AddKnownStruct(&sv_struct_side);
273 	AddKnownStruct(&sv_struct_line);
274 	AddKnownStruct(&sv_struct_regprops);
275 	AddKnownStruct(&sv_struct_exfloor);
276 	AddKnownStruct(&sv_struct_sector);
277 
278 	AddKnownArray(&sv_array_side);
279 	AddKnownArray(&sv_array_line);
280 	AddKnownArray(&sv_array_exfloor);
281 	AddKnownArray(&sv_array_sector);
282 
283 	// sv_misc.c
284 	AddKnownStruct(&sv_struct_button);
285 	AddKnownStruct(&sv_struct_light);
286 	AddKnownStruct(&sv_struct_trigger);
287 	AddKnownStruct(&sv_struct_drawtip);
288 	AddKnownStruct(&sv_struct_plane_move);
289 	AddKnownStruct(&sv_struct_slider_move);
290 
291 	AddKnownArray(&sv_array_button);
292 	AddKnownArray(&sv_array_light);
293 	AddKnownArray(&sv_array_trigger);
294 	AddKnownArray(&sv_array_drawtip);
295 	AddKnownArray(&sv_array_plane_move);
296 	AddKnownArray(&sv_array_slider_move);
297 }
298 
SV_MainLookupStruct(const char * name)299 savestruct_t *SV_MainLookupStruct(const char *name)
300 {
301 	savestruct_t *cur;
302 
303 	for (cur=sv_known_structs; cur; cur=cur->next)
304 		if (strcmp(cur->struct_name, name) == 0)
305 			return cur;
306 
307 	// not found
308 	return NULL;
309 }
310 
SV_MainLookupArray(const char * name)311 savearray_t *SV_MainLookupArray(const char *name)
312 {
313 	savearray_t *cur;
314 
315 	for (cur=sv_known_arrays; cur; cur=cur->next)
316 		if (strcmp(cur->array_name, name) == 0)
317 			return cur;
318 
319 	// not found
320 	return NULL;
321 }
322 
323 //----------------------------------------------------------------------------
324 //
325 //  TEST CODE
326 //
327 
328 #if 0
329 void SV_MainTestPrimitives(void)
330 {
331 	int i;
332 	int version;
333 
334 	if (! SV_OpenWriteFile("savegame/prim.tst", 0x7654))
335 		I_Error("SV_MainTestPrimitives: couldn't create output\n");
336 
337 	SV_PutByte(0x00);
338 	SV_PutByte(0x55);
339 	SV_PutByte(0xAA);
340 	SV_PutByte(0xFF);
341 
342 	SV_PutShort(0x0000);
343 	SV_PutShort(0x4567);
344 	SV_PutShort(0xCDEF);
345 	SV_PutShort(0xFFFF);
346 
347 	SV_PutInt(0x00000000);
348 	SV_PutInt(0x11223344);
349 	SV_PutInt(0xbbccddee);
350 	SV_PutInt(0xffffffff);
351 
352 	SV_PutAngle(ANG1);
353 	SV_PutAngle(ANG45);
354 	SV_PutAngle(ANG135);
355 	SV_PutAngle(ANG180);
356 	SV_PutAngle(ANG270);
357 	SV_PutAngle(ANG315);
358 	SV_PutAngle(0 - ANG1);
359 
360 	SV_PutFloat(0.0f);
361 	SV_PutFloat(0.001f);   SV_PutFloat(-0.001f);
362 	SV_PutFloat(0.1f);     SV_PutFloat(-0.1f);
363 	SV_PutFloat(0.25f);    SV_PutFloat(-0.25f);
364 	SV_PutFloat(1.0f);     SV_PutFloat(-1.0f);
365 	SV_PutFloat(2.0f);     SV_PutFloat(-2.0f);
366 	SV_PutFloat(3.1416f);  SV_PutFloat(-3.1416f);
367 	SV_PutFloat(1000.0f);  SV_PutFloat(-1000.0f);
368 	SV_PutFloat(1234567890.0f);
369 	SV_PutFloat(-1234567890.0f);
370 
371 	SV_PutString(NULL);
372 	SV_PutString("");
373 	SV_PutString("A");
374 	SV_PutString("123");
375 	SV_PutString("HELLO world !");
376 
377 	SV_PutMarker("ABCD");
378 	SV_PutMarker("xyz3");
379 
380 	SV_CloseWriteFile();
381 
382 	// ------------------------------------------------------------ //
383 
384 	if (! SV_OpenReadFile("savegame/prim.tst"))
385 		I_Error("SV_MainTestPrimitives: couldn't open input\n");
386 
387 	if (! SV_VerifyHeader(&version))
388 		I_Error("SV_MainTestPrimitives: couldn't open input\n");
389 
390 	L_WriteDebug("TEST HEADER: version=0x%04x\n", version);
391 
392 	for (i=0; i < 4; i++)
393 	{
394 		unsigned int val = SV_GetByte();
395 		L_WriteDebug("TEST BYTE: 0x%02x %d\n", val, (char) val);
396 	}
397 
398 	for (i=0; i < 4; i++)
399 	{
400 		unsigned int val = SV_GetShort();
401 		L_WriteDebug("TEST SHORT: 0x%02x %d\n", val, (short) val);
402 	}
403 
404 	for (i=0; i < 4; i++)
405 	{
406 		unsigned int val = SV_GetInt();
407 		L_WriteDebug("TEST INT: 0x%02x %d\n", val, (int) val);
408 	}
409 
410 	for (i=0; i < 7; i++)
411 	{
412 		angle_t val = SV_GetAngle();
413 		L_WriteDebug("TEST ANGLE: 0x%08x = %1.6f\n", (unsigned int) val,
414 				ANG_2_FLOAT(val));
415 	}
416 
417 	for (i=0; i < 17; i++)
418 	{
419 		float val = SV_GetFloat();
420 		L_WriteDebug("TEST FLOAT: %1.6f\n", val);
421 	}
422 
423 	for (i=0; i < 5; i++)
424 	{
425 		const char *val = SV_GetString();
426 		L_WriteDebug("TEST STRING: [%s]\n", val ? val : "--NULL--");
427 		SV_FreeString(val);
428 	}
429 
430 	for (i=0; i < 2; i++)
431 	{
432 		char val[6];
433 		SV_GetMarker(val);
434 		L_WriteDebug("TEST MARKER: [%s]\n", val);
435 	}
436 
437 	SV_CloseReadFile();
438 }
439 
440 #endif  // TEST CODE
441 
442 
443 //----------------------------------------------------------------------------
444 
SV_SlotName(int slot)445 const char *SV_SlotName(int slot)
446 {
447 	SYS_ASSERT(slot < 1000);
448 
449 	static char buffer[256];
450 
451 	sprintf(buffer, "slot%03d", slot);
452 
453 	return buffer;
454 }
455 
SV_MapName(const mapdef_c * map)456 const char *SV_MapName(const mapdef_c *map)
457 {
458 	// ensure the name is LOWER CASE
459 	static char buffer[256];
460 
461 	strcpy(buffer, map->name.c_str());
462 
463 	for (char *pos = buffer; *pos; pos++)
464 		*pos = tolower(*pos);
465 
466 	return buffer;
467 }
468 
SV_FileName(const char * slot_name,const char * map_name)469 std::string SV_FileName(const char *slot_name, const char *map_name)
470 {
471     std::string temp(epi::STR_Format("%s/%s.%s", slot_name, map_name, SAVEGAMEEXT));
472 
473 	return epi::PATH_Join(save_dir.c_str(), temp.c_str());
474 }
475 
SV_DirName(const char * slot_name)476 std::string SV_DirName(const char *slot_name)
477 {
478 	return epi::PATH_Join(save_dir.c_str(), slot_name);
479 }
480 
SV_ClearSlot(const char * slot_name)481 void SV_ClearSlot(const char *slot_name)
482 {
483 	std::string full_dir = SV_DirName(slot_name);
484 
485 	// make sure the directory exists
486 	epi::FS_MakeDir(full_dir.c_str());
487 
488 	epi::filesystem_dir_c fsd;
489 
490 	if (! FS_ReadDir(&fsd, full_dir.c_str(), "*.esg"))
491 	{
492 		I_Warning("Failed to read directory: %s\n", full_dir.c_str());
493 		return;
494 	}
495 
496 	I_Debugf("SV_ClearSlot: removing %d files\n", fsd.GetSize());
497 
498 	for (int i = 0; i < fsd.GetSize(); i++)
499 	{
500 		epi::filesys_direntry_c *entry = fsd[i];
501 
502 		if (entry->is_dir)
503 			continue;
504 
505 		std::string cur_file = epi::PATH_Join(full_dir.c_str(), entry->name.c_str());
506 
507 		I_Debugf("  Deleting %s\n", cur_file.c_str());
508 
509 		epi::FS_Delete(cur_file.c_str());
510 	}
511 }
512 
SV_CopySlot(const char * src_name,const char * dest_name)513 void SV_CopySlot(const char *src_name, const char *dest_name)
514 {
515 	std::string src_dir  = SV_DirName(src_name);
516 	std::string dest_dir = SV_DirName(dest_name);
517 
518 	epi::filesystem_dir_c fsd;
519 
520 	if (! FS_ReadDir(&fsd, src_dir.c_str(), "*.esg"))
521 	{
522 		I_Error("SV_CopySlot: failed to read dir: %s\n", src_dir.c_str());
523 		return;
524 	}
525 
526 	I_Debugf("SV_CopySlot: copying %d files\n", fsd.GetSize());
527 
528 	for (int i = 0; i < fsd.GetSize(); i++)
529 	{
530 		epi::filesys_direntry_c *entry = fsd[i];
531 
532 		if (entry->is_dir)
533 			continue;
534 
535 		std::string src_file  = epi::PATH_Join( src_dir.c_str(), entry->name.c_str());
536 		std::string dest_file = epi::PATH_Join(dest_dir.c_str(), entry->name.c_str());
537 
538 		I_Debugf("  Copying %s --> %s\n", src_file.c_str(), dest_file.c_str());
539 
540 		if (! epi::FS_Copy(src_file.c_str(), dest_file.c_str()))
541 			I_Error("SV_CopySlot: failed to copy '%s' to '%s'\n",
542 			        src_file.c_str(), dest_file.c_str());
543 	}
544 }
545 
546 //--- editor settings ---
547 // vi:ts=4:sw=4:noexpandtab
548