Multiple preload-adjustments

pull/1445/head
tobspr 2 years ago
parent e870317a4f
commit 7c77944d43

@ -5,7 +5,32 @@
// Catch load errors // Catch load errors
function errorHandler(event, source, lineno, colno, error) { function errorHandler(event, source, lineno, colno, error) {
console.error("👀 Init Error:", event, source, lineno, colno, error); if (("" + event).indexOf("Script error.") >= 0) {
console.warn("Thirdparty script error:", event);
return;
}
if (("" + event).indexOf("NS_ERROR_FAILURE") >= 0) {
console.warn("Firefox NS_ERROR_FAILURE error:", event);
return;
}
if (("" + event).indexOf("Cannot read property 'postMessage' of null") >= 0) {
console.warn("Safari can not read post message error:", event);
return;
}
if (("" + event).indexOf("Possible side-effect in debug-evaluate") >= 0) {
console.warn("Chrome debug-evaluate error:", event);
return;
}
if (("" + source).indexOf("shapez.io") < 0) {
console.warn("Thirdparty error:", event);
return;
}
console.error("👀 App Error:", event, source, lineno, colno, error);
var element = document.createElement("div"); var element = document.createElement("div");
element.id = "ll_preload_error"; element.id = "ll_preload_error";
@ -38,9 +63,11 @@
} }
document.documentElement.appendChild(element); document.documentElement.appendChild(element);
window.APP_ERROR_OCCURED = true;
} }
window.addEventListener("error", errorHandler); window.onerror = errorHandler;
function expectJsParsed() { function expectJsParsed() {
if (!callbackDone) { if (!callbackDone) {
@ -81,10 +108,10 @@
xhr.responseType = "arraybuffer"; xhr.responseType = "arraybuffer";
xhr.onprogress = function (ev) { xhr.onprogress = function (ev) {
if (ev.lengthComputable) { if (ev.lengthComputable) {
console.log(ev.total);
progressHandler(ev.loaded / ev.total); progressHandler(ev.loaded / ev.total);
} else { } else {
progressHandler(Math.min(1, ev.loaded / 1250000)); // Hardcoded length
progressHandler(Math.min(1, ev.loaded / 2349009));
} }
}; };

@ -33,6 +33,12 @@ const INGAME_ASSETS = {
const LOADER_TIMEOUT_PER_RESOURCE = 180000; const LOADER_TIMEOUT_PER_RESOURCE = 180000;
// Cloudflare does not send content-length headers with brotli compression,
// so store the actual (compressed) file sizes so we can show a progress bar.
const HARDCODED_FILE_SIZES = {
"async-resources.css": 2216145,
};
export class BackgroundResourcesLoader { export class BackgroundResourcesLoader {
/** /**
* *
@ -135,25 +141,24 @@ export class BackgroundResourcesLoader {
let progress = 0; let progress = 0;
this.resourceStateChangedSignal.dispatch({ progress }); this.resourceStateChangedSignal.dispatch({ progress });
let promises = []; let promises = [];
for (let i = 0; i < promiseFunctions.length; i++) { for (let i = 0; i < promiseFunctions.length; i++) {
let lastIndividualProgress = 0; let lastIndividualProgress = 0;
const progressHandler = individualProgress => { const progressHandler = individualProgress => {
const delta = clamp(individualProgress) - lastIndividualProgress; const delta = clamp(individualProgress) - lastIndividualProgress;
lastIndividualProgress = individualProgress; lastIndividualProgress = clamp(individualProgress);
progress += delta / originalAmount; progress += delta / originalAmount;
this.resourceStateChangedSignal.dispatch({ progress }); this.resourceStateChangedSignal.dispatch({ progress });
}; };
promises.push( promises.push(
promiseFunctions promiseFunctions[i](progressHandler).then(() => {
.shift()(progressHandler) progressHandler(1);
.then(() => { })
progressHandler(1);
})
); );
} }
await Promise.all(promises); await Promise.all(promises);
logger.log("⏰ Preloaded assets in", Math.round((performance.now() - start) / 1000.0), "ms"); logger.log("⏰ Preloaded assets in", Math.round(performance.now() - start), "ms");
} }
/** /**
@ -189,23 +194,32 @@ export class BackgroundResourcesLoader {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
let notifiedNotComputable = false; let notifiedNotComputable = false;
xhr.open("GET", src, true); const fullUrl = cachebust(src);
xhr.open("GET", fullUrl, true);
xhr.responseType = "arraybuffer"; xhr.responseType = "arraybuffer";
xhr.onprogress = function (ev) { xhr.onprogress = function (ev) {
if (ev.lengthComputable) { if (ev.lengthComputable) {
progressHandler(ev.loaded / ev.total); progressHandler(ev.loaded / ev.total);
} else { } else {
if (!notifiedNotComputable) { if (window.location.search.includes("alwaysLogFileSize")) {
notifiedNotComputable = true; console.warn("Progress:", src, ev.loaded);
console.warn("Progress not computable:", src, ev); }
progressHandler(0);
if (HARDCODED_FILE_SIZES[src]) {
progressHandler(clamp(ev.loaded / HARDCODED_FILE_SIZES[src]));
} else {
if (!notifiedNotComputable) {
notifiedNotComputable = true;
console.warn("Progress not computable:", src, ev.loaded);
progressHandler(0);
}
} }
} }
}; };
xhr.onloadend = function () { xhr.onloadend = function () {
if (!xhr.status.toString().match(/^2/)) { if (!xhr.status.toString().match(/^2/)) {
reject(src + ": " + xhr.status + " " + xhr.statusText); reject(fullUrl + ": " + xhr.status + " " + xhr.statusText);
} else { } else {
if (!notifiedNotComputable) { if (!notifiedNotComputable) {
progressHandler(1); progressHandler(1);
@ -226,7 +240,7 @@ export class BackgroundResourcesLoader {
} }
internalPreloadCss(src, progressHandler) { internalPreloadCss(src, progressHandler) {
return this.preloadWithProgress(cachebust(src), progressHandler).then(blobSrc => { return this.preloadWithProgress(src, progressHandler).then(blobSrc => {
var styleElement = document.createElement("link"); var styleElement = document.createElement("link");
styleElement.href = blobSrc; styleElement.href = blobSrc;
styleElement.rel = "stylesheet"; styleElement.rel = "stylesheet";

@ -1,16 +0,0 @@
export let APPLICATION_ERROR_OCCURED = false;
/**
*
* @param {Event|string} message
* @param {string} source
* @param {number} lineno
* @param {number} colno
* @param {Error} source
*/
function catchErrors(message, source, lineno, colno, error) {
APPLICATION_ERROR_OCCURED = true;
console.error(message, source, lineno, colno, error);
}
window.addEventListener("error", catchErrors);

@ -80,15 +80,13 @@ class LoaderImpl {
* @returns {Promise<HTMLImageElement|null>} * @returns {Promise<HTMLImageElement|null>}
*/ */
internalPreloadImage(key, progressHandler) { internalPreloadImage(key, progressHandler) {
const url = cachebust("res/" + key);
const image = new Image();
return this.app.backgroundResourceLoader return this.app.backgroundResourceLoader
.preloadWithProgress(url, progress => { .preloadWithProgress("res/" + key, progress => {
progressHandler(progress); progressHandler(progress);
}) })
.then(url => { .then(url => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener("load", () => resolve(image)); image.addEventListener("load", () => resolve(image));
image.addEventListener("error", err => image.addEventListener("error", err =>
reject("Failed to load sprite " + key + ": " + err) reject("Failed to load sprite " + key + ": " + err)

@ -4,7 +4,6 @@ import { Application } from "../application";
import { GameState } from "./game_state"; import { GameState } from "./game_state";
import { createLogger } from "./logging"; import { createLogger } from "./logging";
import { APPLICATION_ERROR_OCCURED } from "./error_handler";
import { waitNextFrame, removeAllChildren } from "./utils"; import { waitNextFrame, removeAllChildren } from "./utils";
import { MOD_SIGNALS } from "../mods/mod_signals"; import { MOD_SIGNALS } from "../mods/mod_signals";
@ -56,7 +55,7 @@ export class StateManager {
* @param {string} key State Key * @param {string} key State Key
*/ */
moveToState(key, payload = {}) { moveToState(key, payload = {}) {
if (APPLICATION_ERROR_OCCURED) { if (window.APP_ERROR_OCCURED) {
console.warn("Skipping state transition because of application crash"); console.warn("Skipping state transition because of application crash");
return; return;
} }

@ -100,6 +100,8 @@ declare interface Window {
shapez: any; shapez: any;
APP_ERROR_OCCURED?: boolean;
webkitRequestAnimationFrame(); webkitRequestAnimationFrame();
assert(condition: boolean, failureMessage: string); assert(condition: boolean, failureMessage: string);

@ -1,6 +1,5 @@
import "./core/polyfills"; import "./core/polyfills";
import "./core/assert"; import "./core/assert";
import "./core/error_handler";
import "./mods/modloader"; import "./mods/modloader";

@ -1,4 +1,3 @@
import { APPLICATION_ERROR_OCCURED } from "../core/error_handler";
import { GameState } from "../core/game_state"; import { GameState } from "../core/game_state";
import { logSection, createLogger } from "../core/logging"; import { logSection, createLogger } from "../core/logging";
import { waitNextFrame } from "../core/utils"; import { waitNextFrame } from "../core/utils";
@ -419,7 +418,7 @@ export class InGameState extends GameState {
* @param {number} dt * @param {number} dt
*/ */
onRender(dt) { onRender(dt) {
if (APPLICATION_ERROR_OCCURED) { if (window.APP_ERROR_OCCURED) {
// Application somehow crashed, do not do anything // Application somehow crashed, do not do anything
return; return;
} }
@ -465,7 +464,7 @@ export class InGameState extends GameState {
return Promise.resolve(); return Promise.resolve();
} }
if (APPLICATION_ERROR_OCCURED) { if (window.APP_ERROR_OCCURED) {
logger.warn("skipping save because application crashed"); logger.warn("skipping save because application crashed");
return Promise.resolve(); return Promise.resolve();
} }

Loading…
Cancel
Save