aboutsummaryrefslogtreecommitdiffstats
path: root/inc/savegame.inc
blob: 6d92af2c53246716e33f2855198eb11af4126069 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php

require_once("inc/messages.inc");
require_once("inc/Inventory.inc");
require_once("inc/Item.inc");

define("SAVEDIR", "data/save");

function genXML($table, $xml) {
	foreach($table as $k => $v) {
		if(is_object($v)) { // Object: either Item or Inventory
			if(is_callable(array($v, "addToXML"))) // Check if the object has a addToXML method
				$v->addToXML($xml->addChild($k));
		} elseif(is_array($v)) // Nested array
			genXML($v, $xml->addChild($k));
		else // Single value (numeric or string)
			$xml->addChild($k, $v);
	}
}

function genSave() {
	$save = new SimpleXMLElement("<save/>");
	genXML($_SESSION, $save);
	return $save;
}

function genFilename() {
	return "craftmine-".date("d-m-Y_H-i-s").".save.xml";
}

function saveGame() {
	$save = genSave();
	if($save->asXML(SAVEDIR."/".genFilename())) sendInfo("gamesave_ok");
	else sendError("gamesave_error");
}

function downSave() {
	$save = "";
	$filename = "";

	if(empty($_GET["filename"])) {
		$filename = genFilename();
		$save = genSave()->asXML(); // Send current game save file if no file specified
	} else {
		$filename = $_GET["filename"];
		$save = file_get_contents(SAVEDIR . "/" . $filename);
		if(empty($save)) return; // Probably file not found
	}

	header("Content-Type: application/xml"); // Force browser to intepret the file as XML
	header("Content-Disposition: attachment; filename=".$filename); // Force download with specific filename
	header("Cache-Control: no-cache"); // Avoid storing save file in proxy/browser cache
	echo $save;
}

function listSaves() {
	chdir(SAVEDIR); // Go to SAVEDIR folder, avoiding leading folder name in file list
	echo json_encode(glob("*.save.xml"));
}

function parseSave($xml, &$table) { // Passing $table by reference
	foreach($xml as $k => $v) {
		if($v->count() == 0) { // No child, treat as string
			$v = (string)$v;
			if(is_numeric($v)) $v = +$v; // If it is in fact a number, treat it that way using PHP unary '+' coercion
			$table[$k] = $v;
		} elseif($k == "inventory") { // Special case for inventory: objects need to be created
			foreach($v as $item) {
				for($i=0; $i<+$item->count; $i++) // Add the right count of items to Inventory
					Inventory::addItem(Item::fromXML($item));
			}
		} else { // If nested array
			$table[$k] = array();
			parseSave($v, $table[$k]);
		} // Other types unsupported (unused)
	}
}

function deleteSave() {
	if(empty($_POST["filename"])) return;
	$path = SAVEDIR . "/" . basename($_POST["filename"]); // remove any leading directory
	if(file_exists($path) && unlink($path))
		sendInfo("gamesave_delete_success");
	else sendError("gamesave_delete_fail");
}

function loadSave() {
	if(empty($_POST["filename"])) return;
	$xml = simplexml_load_file(SAVEDIR . "/" . $_POST["filename"]);
	if(empty($xml)) {
		sendError("gamesave_not_found");
		return;
	}
	$_SESSION = array(); // drop current game
	parseSave($xml, $_SESSION);
}

function uploadSave() {
	$fname = basename($_FILES['savefile']['name']);
	$src = $_FILES['savefile']['tmp_name'];

	libxml_use_internal_errors(true); // Ignore errors when loading the received file
	$xml = simplexml_load_file($src);
	libxml_use_internal_errors(false);
	if(!$xml) {
		sendError("upload_fail");
		return;
	}
	$table = array();
	parseSave($xml, $table); // Parse received file

	$save = new SimpleXMLElement("<save/>");
	genXML($table, $save); // Regenerate it
	if($save->asXML(SAVEDIR."/".$fname)) sendInfo("upload_success", array($fname));
	else sendError("upload_error");
}
?>