mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Support for loading games in Javascript puzzles.
This is done by showing a dialog containing an <input type="file"> through which the user can 'upload' a save file - though, of course, the 'upload' doesn't go to any HTTP server, but only into the mind of the Javascript running in the same browser. It would be even nicer to support drag-and-drop as an alternative UI for getting the save file into the browser, but that isn't critical to getting the first version of this feature out of the door.
This commit is contained in:
38
emcc.c
38
emcc.c
@ -766,9 +766,9 @@ struct savefile_write_ctx {
|
|||||||
size_t pos;
|
size_t pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void savefile_write(void *wctx, void *buf, int len)
|
static void savefile_write(void *vctx, void *buf, int len)
|
||||||
{
|
{
|
||||||
struct savefile_write_ctx *ctx = (struct savefile_write_ctx *)wctx;
|
struct savefile_write_ctx *ctx = (struct savefile_write_ctx *)vctx;
|
||||||
if (ctx->buffer)
|
if (ctx->buffer)
|
||||||
memcpy(ctx->buffer + ctx->pos, buf, len);
|
memcpy(ctx->buffer + ctx->pos, buf, len);
|
||||||
ctx->pos += len;
|
ctx->pos += len;
|
||||||
@ -799,6 +799,40 @@ void free_save_file(char *buffer)
|
|||||||
sfree(buffer);
|
sfree(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct savefile_read_ctx {
|
||||||
|
const char *buffer;
|
||||||
|
int len_remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int savefile_read(void *vctx, void *buf, int len)
|
||||||
|
{
|
||||||
|
struct savefile_read_ctx *ctx = (struct savefile_read_ctx *)vctx;
|
||||||
|
if (ctx->len_remaining < len)
|
||||||
|
return FALSE;
|
||||||
|
memcpy(buf, ctx->buffer, len);
|
||||||
|
ctx->len_remaining -= len;
|
||||||
|
ctx->buffer += len;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_game(const char *buffer, int len)
|
||||||
|
{
|
||||||
|
struct savefile_read_ctx ctx;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
ctx.buffer = buffer;
|
||||||
|
ctx.len_remaining = len;
|
||||||
|
err = midend_deserialise(me, savefile_read, &ctx);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
js_error_box(err);
|
||||||
|
} else {
|
||||||
|
select_appropriate_preset();
|
||||||
|
resize();
|
||||||
|
midend_redraw(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Setup function called at page load time. It's called main() because
|
* Setup function called at page load time. It's called main() because
|
||||||
* that's the most convenient thing in Emscripten, but it's not main()
|
* that's the most convenient thing in Emscripten, but it's not main()
|
||||||
|
26
emccpre.js
26
emccpre.js
@ -299,6 +299,7 @@ function initPuzzle() {
|
|||||||
// 'number' is used for C pointers
|
// 'number' is used for C pointers
|
||||||
get_save_file = Module.cwrap('get_save_file', 'number', []);
|
get_save_file = Module.cwrap('get_save_file', 'number', []);
|
||||||
free_save_file = Module.cwrap('free_save_file', 'void', ['number']);
|
free_save_file = Module.cwrap('free_save_file', 'void', ['number']);
|
||||||
|
load_game = Module.cwrap('load_game', 'void', ['string', 'number']);
|
||||||
|
|
||||||
document.getElementById("save").onclick = function(event) {
|
document.getElementById("save").onclick = function(event) {
|
||||||
if (dlg_dimmer === null) {
|
if (dlg_dimmer === null) {
|
||||||
@ -322,6 +323,31 @@ function initPuzzle() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.getElementById("load").onclick = function(event) {
|
||||||
|
if (dlg_dimmer === null) {
|
||||||
|
dialog_init("Upload saved-game file");
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.multiple = false;
|
||||||
|
dlg_form.appendChild(input);
|
||||||
|
dlg_form.appendChild(document.createElement("br"));
|
||||||
|
dialog_launch(function(event) {
|
||||||
|
if (input.files.length == 1) {
|
||||||
|
var file = input.files.item(0);
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.addEventListener("loadend", function() {
|
||||||
|
var string = reader.result;
|
||||||
|
load_game(string, string.length);
|
||||||
|
});
|
||||||
|
reader.readAsBinaryString(file);
|
||||||
|
}
|
||||||
|
dialog_cleanup();
|
||||||
|
}, function(event) {
|
||||||
|
dialog_cleanup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
gametypelist = document.getElementById("gametype");
|
gametypelist = document.getElementById("gametype");
|
||||||
gametypesubmenus.push(gametypelist);
|
gametypesubmenus.push(gametypelist);
|
||||||
|
|
||||||
|
@ -18,9 +18,10 @@
|
|||||||
'_timer_callback',
|
'_timer_callback',
|
||||||
// Callback from button presses in the UI outside the canvas
|
// Callback from button presses in the UI outside the canvas
|
||||||
'_command',
|
'_command',
|
||||||
// Game-saving functions
|
// Game-saving and game-loading functions
|
||||||
'_get_save_file',
|
'_get_save_file',
|
||||||
'_free_save_file',
|
'_free_save_file',
|
||||||
|
'_load_game',
|
||||||
// Callbacks to return values from dialog boxes
|
// Callbacks to return values from dialog boxes
|
||||||
'_dlg_return_sval',
|
'_dlg_return_sval',
|
||||||
'_dlg_return_ival',
|
'_dlg_return_ival',
|
||||||
|
@ -210,6 +210,7 @@ ${unfinishedpara}
|
|||||||
><li id="specific">Enter game ID</li
|
><li id="specific">Enter game ID</li
|
||||||
><li id="random">Enter random seed</li
|
><li id="random">Enter random seed</li
|
||||||
><li id="save">Download save file</li
|
><li id="save">Download save file</li
|
||||||
|
><li id="load">Upload save file</li
|
||||||
></ul></li
|
></ul></li
|
||||||
><li>Type...<ul id="gametype"></ul></li
|
><li>Type...<ul id="gametype"></ul></li
|
||||||
><li class="separator"></li
|
><li class="separator"></li
|
||||||
|
Reference in New Issue
Block a user