Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/web/js/engine/preloader.js
10279 views
1
const Preloader = /** @constructor */ function () { // eslint-disable-line no-unused-vars
2
function getTrackedResponse(response, load_status) {
3
function onloadprogress(reader, controller) {
4
return reader.read().then(function (result) {
5
if (load_status.done) {
6
return Promise.resolve();
7
}
8
if (result.value) {
9
controller.enqueue(result.value);
10
load_status.loaded += result.value.length;
11
}
12
if (!result.done) {
13
return onloadprogress(reader, controller);
14
}
15
load_status.done = true;
16
return Promise.resolve();
17
});
18
}
19
const reader = response.body.getReader();
20
return new Response(new ReadableStream({
21
start: function (controller) {
22
onloadprogress(reader, controller).then(function () {
23
controller.close();
24
});
25
},
26
}), { headers: response.headers });
27
}
28
29
function loadFetch(file, tracker, fileSize, raw) {
30
tracker[file] = {
31
total: fileSize || 0,
32
loaded: 0,
33
done: false,
34
};
35
return fetch(file).then(function (response) {
36
if (!response.ok) {
37
return Promise.reject(new Error(`Failed loading file '${file}'`));
38
}
39
const tr = getTrackedResponse(response, tracker[file]);
40
if (raw) {
41
return Promise.resolve(tr);
42
}
43
return tr.arrayBuffer();
44
});
45
}
46
47
function retry(func, attempts = 1) {
48
function onerror(err) {
49
if (attempts <= 1) {
50
return Promise.reject(err);
51
}
52
return new Promise(function (resolve, reject) {
53
setTimeout(function () {
54
retry(func, attempts - 1).then(resolve).catch(reject);
55
}, 1000);
56
});
57
}
58
return func().catch(onerror);
59
}
60
61
const DOWNLOAD_ATTEMPTS_MAX = 4;
62
const loadingFiles = {};
63
const lastProgress = { loaded: 0, total: 0 };
64
let progressFunc = null;
65
66
const animateProgress = function () {
67
let loaded = 0;
68
let total = 0;
69
let totalIsValid = true;
70
let progressIsFinal = true;
71
72
Object.keys(loadingFiles).forEach(function (file) {
73
const stat = loadingFiles[file];
74
if (!stat.done) {
75
progressIsFinal = false;
76
}
77
if (!totalIsValid || stat.total === 0) {
78
totalIsValid = false;
79
total = 0;
80
} else {
81
total += stat.total;
82
}
83
loaded += stat.loaded;
84
});
85
if (loaded !== lastProgress.loaded || total !== lastProgress.total) {
86
lastProgress.loaded = loaded;
87
lastProgress.total = total;
88
if (typeof progressFunc === 'function') {
89
progressFunc(loaded, total);
90
}
91
}
92
if (!progressIsFinal) {
93
requestAnimationFrame(animateProgress);
94
}
95
};
96
97
this.animateProgress = animateProgress;
98
99
this.setProgressFunc = function (callback) {
100
progressFunc = callback;
101
};
102
103
this.loadPromise = function (file, fileSize, raw = false) {
104
return retry(loadFetch.bind(null, file, loadingFiles, fileSize, raw), DOWNLOAD_ATTEMPTS_MAX);
105
};
106
107
this.preloadedFiles = [];
108
this.preload = function (pathOrBuffer, destPath, fileSize) {
109
let buffer = null;
110
if (typeof pathOrBuffer === 'string') {
111
const me = this;
112
return this.loadPromise(pathOrBuffer, fileSize).then(function (buf) {
113
me.preloadedFiles.push({
114
path: destPath || pathOrBuffer,
115
buffer: buf,
116
});
117
return Promise.resolve();
118
});
119
} else if (pathOrBuffer instanceof ArrayBuffer) {
120
buffer = new Uint8Array(pathOrBuffer);
121
} else if (ArrayBuffer.isView(pathOrBuffer)) {
122
buffer = new Uint8Array(pathOrBuffer.buffer);
123
}
124
if (buffer) {
125
this.preloadedFiles.push({
126
path: destPath,
127
buffer: pathOrBuffer,
128
});
129
return Promise.resolve();
130
}
131
return Promise.reject(new Error('Invalid object for preloading'));
132
};
133
};
134
135