diff options
-rw-r--r-- | craftmine.php | 3 | ||||
-rw-r--r-- | inc/Item.inc | 4 | ||||
-rw-r--r-- | inc/messages.inc | 3 | ||||
-rw-r--r-- | inc/savegame.inc | 80 | ||||
-rw-r--r-- | index.xhtml | 15 | ||||
-rw-r--r-- | js/craftmine.js | 8 | ||||
-rw-r--r-- | js/gui.js | 6 | ||||
-rw-r--r-- | js/savegame.js | 42 |
8 files changed, 130 insertions, 31 deletions
diff --git a/craftmine.php b/craftmine.php index ac187cc..9a5d3d7 100644 --- a/craftmine.php +++ b/craftmine.php @@ -49,6 +49,9 @@ switch($op) { case "buyItem": buyItem(); break; case "saveGame": saveGame(); break; case "downSave": downSave(); break; + case "listSaves": listSaves(); break; + case "loadSave": loadSave(); break; + case "deleteSave": deleteSave(); break; default: reportBadRequest(); } diff --git a/inc/Item.inc b/inc/Item.inc index bef6d00..8e90998 100644 --- a/inc/Item.inc +++ b/inc/Item.inc @@ -20,6 +20,10 @@ class Item { $item->addChild("icon", $this->icon); $item->addChild("desc", $this->desc); } + + public static function fromXML($xml) { + return new static((string)$xml->name, +(string)$xml->cost /* convert to number */, (string)$xml->icon, (string)$xml->desc); + } } ?> diff --git a/inc/messages.inc b/inc/messages.inc index 9f3a09d..4938fa1 100644 --- a/inc/messages.inc +++ b/inc/messages.inc @@ -9,6 +9,9 @@ $messages = array( "gamesave_ok" => "Game saved.", "gamesave_error" => "An error occured when trying to save the game.", + "gamesave_not_found" => "Couldn't find the specified save file.", + "gamesave_delete_fail" => "Couldn't delete the specified save file.", + "gamesave_delete_success" => "Game save successfully removed from server", ); function sendMessage($type, $msg) { diff --git a/inc/savegame.inc b/inc/savegame.inc index f3b6da6..1fa95b0 100644 --- a/inc/savegame.inc +++ b/inc/savegame.inc @@ -4,23 +4,22 @@ require_once("inc/messages.inc"); define("SAVEDIR", "data/save"); -function genXML($v, $k, $xml) { - if(is_object($v)) - { - if(is_callable(array($v, "addToXML"))) - $v->addToXML($xml->addChild($k)); +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); } - else - $xml->addChild($k, $v); } function genSave() { - header("Content-Type: application/xml"); $save = new SimpleXMLElement("<save/>"); - - array_walk_recursive($_SESSION, "genXML", $save); + genXML($_SESSION, $save); return $save; - echo $save->asXML(); } function genFilename() { @@ -34,11 +33,60 @@ function saveGame() { } function downSave() { - $save = genSave(); - header("Content-Type: application/xml"); - header("Content-Disposition: attachment; filename=".genFilename()); - header("Pragma: no-cache"); - echo $save->asXML(); + $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) 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); +} ?> diff --git a/index.xhtml b/index.xhtml index d12585f..6627ec5 100644 --- a/index.xhtml +++ b/index.xhtml @@ -15,6 +15,7 @@ <script type="text/javascript" charset="utf-8" src="js/guild.js"></script> <script type="text/javascript" charset="utf-8" src="js/shop.js"></script> <script type="text/javascript" charset="utf-8" src="js/gui.js"></script> + <script type="text/javascript" charset="utf-8" src="js/savegame.js"></script> </head> <body onload="init()" onhashchange="changeTab()"> <div class="container-fluid"> @@ -64,6 +65,7 @@ <li role="presentation"><a href="#tab2" data-toggle="tab">Shop</a></li> <li role="presentation"><a href="#tab3" data-toggle="tab">Inventory</a></li> <li role="presentation"><a href="#tab4" data-toggle="tab">Dungeon</a></li> + <li role="presentation" class="pull-right"><a href="#tab5" data-toggle="tab" onclick="listSaves()">Save</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="tab1"> @@ -82,11 +84,18 @@ <div class="tab-pane" id="tab4"> <h4>Look at how poor you are! You can't access the dungeon, it is only for the elite.</h4> </div> + <div class="tab-pane" id="tab5"> + <h4>Saved games:</h4> + <div class="form" id="listsaves"> + </div> + <ul class="list-inline"> + <li><button class="btn btn-default" type="button" onclick="loadSave()">Load</button></li> + <li><button class="btn btn-default" type="button" onclick="downloadSave()">Download</button></li> + <li><button class="btn btn-default" type="button" onclick="deleteSave()">Delete</button></li> + </ul> + </div> </div> </div> - - - </div> </div> </div> diff --git a/js/craftmine.js b/js/craftmine.js index d649305..43c4870 100644 --- a/js/craftmine.js +++ b/js/craftmine.js @@ -64,14 +64,6 @@ function updateMine() { updateData("mine"); } -function saveGame() { - sendRequest("craftmine.php", "op=saveGame"); -} - -function downGame() { - window.open("craftmine.php?op=downGame", "_blank"); -} - function init() { initCraftMine(); changeTab(); @@ -6,10 +6,8 @@ function changeTab() { var id = window.location.hash.substr(4); var tabs = document.querySelectorAll("#tabs-panel > ul > li"); for(var i=0; i < tabs.length; i++) { - if(i == id-1) - tabs[i].className = "active"; - else - tabs[i].className = ""; + if(i == id-1) tabs[i].classList.add("active"); // Doesn't work with IE < 10 (and Opera Mini), but who cares? + else tabs[i].classList.remove("active"); } } diff --git a/js/savegame.js b/js/savegame.js new file mode 100644 index 0000000..4a08f91 --- /dev/null +++ b/js/savegame.js @@ -0,0 +1,42 @@ +function listSaves() { + sendRequest("craftmine.php", "op=listSaves", function(ret) { + var tmphtml="" + for(var i=0; i<ret.length; i++) { + tmphtml += "<label class=\"radio\"><input name=\"saveRadio\" value=\"" + i + "\" type=\"radio\" />" + ret[i] + "</label>\n"; + } + console.log(tmphtml); + document.getElementById("listsaves").innerHTML = tmphtml; + }); +} + +function getCheckedSave() { + var radios = document.getElementsByName('saveRadio'); + for (var i = 0, length = radios.length; i < length; i++) { + if (radios[i].checked) return radios[i].parentNode.textContent; + } + return -1; +} + +function loadSave() { + sendRequest("craftmine.php", "op=loadSave&filename="+getCheckedSave(), function(ret) { + initCraftMine(); + }); +} + +function downloadSave() { + window.open("craftmine.php?op=downSave&filename="+getCheckedSave(), "_blank"); +} + +function deleteSave() { + sendRequest("craftmine.php", "op=deleteSave&filename="+getCheckedSave(), function(ret) { + listSaves(); + }); +} + +function saveGame() { + sendRequest("craftmine.php", "op=saveGame"); +} + +function downGame() { + window.open("craftmine.php?op=downSave", "_blank"); +} |