I Need Professional Help With This One!

This is the last major issue I'm trying to resolve before uploading my Map Demo 2.0. This involves KV's Grid Image library with accompanying js script, which together display image files for each room on the map.

In short, when restoring a saved game, it takes way too long, depending on how much of the explored map is being restored. If only a quarter of the map has been explored, reloading is pretty fast. If half of the map needs to be reloaded, it takes several seconds. But if the whole map needs to be reloaded, it takes up to a minute and a half! So reloading time is exponential, not linear!

The entire map is about 400 rooms, each with its own grid image. I'm pretty sure that the problem lies in the accumulating image files that have to be reloaded. But because of the exponential reloading time, it's possible that image files are somehow being "cached" unnecessarily -- this was, in fact, an issue that had occurred before that KV tried to fix, but it's possible that he only partially fixed it (I have indicated, under "GridImageLib.js (js script)", the lines of code where he addressed this).

To be sure, I have reduced all of the image file sizes. Strangely, this seems to make no difference in reloading time.

KV's grid image code consists of 2 parts: GridImageLib.aslx (library), and GridImageLib.js (js script). The library also modifies the built-in Grid_DrawRoom function. Loading the grid images starts with calling the SetupGridImages function (located near the bottom of the library), which is done once in the Start tab in a new game, and once in the InitUI tab in a restored game (so only once in either a new or restored game).

GridImageLib.aslx (library)
	<function name="SetGridImgPath" parameters="filename">
		JS.setImagePath (GetFileUrl("_FILENAME_"))
	<function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
		if (room.grid_render) {
		  if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
			if (room.parent <> null) {
			  Grid_DrawRoom (room.parent, redraw, playerobject)

// +++++++++++++++ THE ONLY CHANGES KV MADE TO GRID_DRAWROOM START HERE +++++++++++++++++
			gridx = Grid_GetGridCoordinateForPlayer(game.pov, room, "x")
			gridy = Grid_GetGridCoordinateForPlayer(game.pov, room, "y")
			JS.Grid_DrawBox (gridx, gridy, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
			if (HasString(room, "grid_image")) {
			  imgfile = false
			  imgexts = Split(".png;.jpeg;.gif;.jpg;svg",";")
			  room.imageid = room.name+"-grid-image"
			  JS.eval ("var roomImageId = '"+room.imageid+"';var gridX = '"+gridx+"';var gridY = '"+gridy+"';var roomGridWidth = '"+room.grid_width+"';var roomGridHeight = '"+room.grid_length+"';customDrawImage('"+room.grid_image+"');")
// +++++++++++++++ THE ONLY CHANGES KV MADE TO GRID_DRAWROOM END HERE +++++++++++++++++

			if (LengthOf(room.grid_label) > 0) {
			  label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
			  label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
			  JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label, room.grid_label_colour)
			foreach (exit, AllExits()) {
			  if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
				Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
			Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
  <function name="FinishTurn">
    if (HasAttribute(game,"runturnscripts")) {
      if (GetBoolean(game,"runturnscripts")) {
	    if (not GetBoolean(game, "suppressturnscripts")) {
		  game.runturnscripts = false
	else {
	  if (not GetBoolean(game, "suppressturnscripts")) {
	game.suppressturnscripts = false
  <function name="AslSet" parameters="data">
    //game.suppressturnscripts = true
    data = Split(data,"||")

    foreach (bit, data) {
      stuff = Split(bit,"=")
      obj_attr = stuff[0]
      obj_attr = Split(obj_attr,".")
	  if (ListCount(obj_attr)>2){
	    exclude = obj_attr[ListCount(obj_attr)-1]
	    obj = Join(ListExclude(obj_attr,exclude),".")
		obj_attr = NewStringList()
		list add (obj_attr, obj)
		list add (obj_attr, exclude)
	  else {
        obj = obj_attr[0]
      obj = GetObject(obj)
      attr = obj_attr[1]
      val = stuff[1]
      if (EndsWith(val,"_toInt")) {
        val = ToInt(Replace(val,"_toInt",""))
        val = true
      else if(LCase(val)="false"){
        val = false
      else if (EndsWith(val,"_toDouble")) {
        val = ToDouble(Replace(val,"_toDouble",""))
      set (obj, attr, val)
// +++++++++++++++ THIS IS WHERE THE LOADING OF IMAGE FILES STARTS +++++++++++++++++
  <function name="SetupGridImages"><![CDATA[
	  foreach (room, AllObjects()) {
		if (HasAttribute(room,"grid_image")) {
		  JS.eval ("imagesToCheck.push('"+room.grid_image+"');checkImages();")

<javascript src="GridImageLib.js" />
GridImageLib.js (js script)
var questImagePath = "";

setImagePath = function(path) {
  questImagePath = path;

getFileUrlJS = function(filename){
  if(filename.indexOf("://") > 0) {
	return (filename);
  } else {
	return questImagePath.replace("_FILENAME_", filename);
var imagesToCheck = [];

function checkImages(){

var failedImgs = [];

function imgFail(imgFailed){

// The function below was updated by KV to clear out image elements that were caching and slowing a restored game.
function isFileGood(url){
    imgFile = getFileUrlJS(url);
    $('body').append("<img style='display:none' onload='$(this).remove();' onerror='imgFail(this);$(this).remove();' src='"+imgFile+"'/>");

customDrawImage = function(url){
	var imgFile = getFileUrlJS(url);
	var failnumber = failedImgs.indexOf(imgFile);
	if(failnumber === -1){
		ASLEvent('AslSet', roomImageId.replace("-",".").replace("grid-image","grid_image")+"="+imgFile);
		gridApi.drawCustomLayerImage(roomImageId, imgFile, parseFloat(gridX), parseFloat(gridY), parseInt(roomGridWidth), parseInt(roomGridHeight));

So is there anywhere in the code where image files are being inefficiently or unnecessarily "cached", thus increasing reload time?

Other than further reducing the image files, is there any way to make the game reload faster? (I have eliminated most exits in the game and each room is fairly bare bones, so those things should not be issues.)

I can provide all the files for inspection if that helps. Thank you.

This code near the bottom of GridImageLib.js may be at the crux of the issue:

function isFileGood(url){
    imgFile = getFileUrlJS(url);
    $('body').append("<img style='display:none' onload='$(this).remove();' onerror='imgFail(this);$(this).remove();' src='"+imgFile+"'/>");


I'm neither a professional nor one who knows much about the grid.
Hope you'll get help from someone who knows how too!
Looking forward to see what you've accomplished.

While it's loading, what do you get if you enter $('body > img'); in your browser's javascript console?

Thanks for the encouragement. I look forward to seeing your game too.

Actually, I've only run this demo offline. Haven't even uploaded it yet.

Not sure if you can get at the console in the offline version; but would be interesting to know if the slowdown is within Quest itself, or in the browser.

How would I get at the console in the offline version?

I haven't tried it, but there's a chance Ctrl+Shift+J or Ctrl+Shift+I might bring up developer tools.
But this could be one of the places where desktop and online behave completely differently, because I believe data between the frontend and backend is synchronised differently.

Ctrl+Shift+J or I doesn't do anything in-game or in the editor (desktop mode). However, I'm looking at HTML tools in-game to see if I can get a clue about anything (don't understand most of this stuff though).

When in-game, under the "HTML Tools" menu button, under the "Profiles" tab, there is a radio button set to "Collect Javascript CPU Profile". Near the bottom, I pressed on the "Start" button, which causes a "Profile 1" to be recorded in the background. When you press "Stop", the profile stops recording and you can see any error messages, as well as a table of resource allocations.

So I started a new game in desktop. Before doing any commands, I started a new "Profile 1" recording and then stopped it after several seconds, still without running any commands (just idling). These 2 error messages came up:

Failed to clear temp storage: It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources. SecurityError

Failed to create temp file 2 : It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.

I restarted the recording again (now in "Profile 2") and moved the player around, running other commands, etc. Then I stopped recording "Profile 2" and looked at the error messages. The only thing added was a repeat of the second error message:

Failed to create temp file 2 : It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.

This will continue ad nauseum each time you restart the recording, do stuff, and stop it again; i.e., another copy of the second error message will appear each time. Other than that, there were no other messages.

This sounds pertinent, but I have no idea what, if anything, can be done about it. Any ideas? Thanks.

Log in to post a reply.