Testing a game exported for the web I noticed its .pck is not cached by a browser. The wasm and other game files are in fact taken from the browser cache, but the largest of them pck is downloaded anew every time, adding tens of seconds to the startup even though it is never changed on the server.
Cannot figure out what is causing this. Have I done something wrong during export? Is server needs to be configured in a special way?
If you are hosting the server yourself, quick solution for this would be to add Cache-Control
header with appropriate value to the response of that resource. I am not exactly sure if something similar can be done when hosting on external platforms like itch.io
I have tried putting Cache-Control header onto the file but it seems to make no difference. Also I have tried a game with a smaller pck and that one is cached alright regardless of the header.
Looks like it has to do with the file size. Though it is counterintuitive that that a browser would not cache a larger file, and I cannot find any documentation on what the actual limits are.
Caching is usually responsibility of the browser (or user agent in general) so it really depends on that. Found an interesting question relating to Firefox’s caching, which might be relevant in your investigation. If you are using an obscure browser, it is also possible that caching requests in some cases are simply ignored by user agent. Might help testing in different browsers and environments to see how it behaves.
Looks like that is the issue here, and there isn’t anything wrong with my export. Default Firefox limits are generous enough that the caching works for me, and fails the same way when the limit is reduced. Though for Chrome (Edge) there is no and won’t be details on what the limits are.
Ended up modifying the default exported javascript to have it explicitly use cache API for the fetched wasm and pck files.
...
function loadFetch(file, tracker, fileSize, raw) {
tracker[file] = {
total: fileSize || 0,
loaded: 0,
done: false,
};
var request = new Request(file);
var fetchPromise = fetchCacheFirst(request);
//return fetch(file).then(function (response) {
return fetchPromise.then(function (response) {
if (!response.ok) {
return Promise.reject(new Error(`Failed loading file '${file}'`));
}
const tr = getTrackedResponse(response, tracker[file]);
if (raw) {
return Promise.resolve(tr);
}
return tr.arrayBuffer();
});
}
var CACHE_NAME = 'my-cache';
function updateCached(request, response) {
return self.caches.open(CACHE_NAME)
.then(cache => cache.put(request, response));
}
function fetchCacheFirst(request) {
// Get file from the cache API, or fetch from server and store for future use
return self.caches.open(CACHE_NAME)
.then(cache => {
var matchPromise = cache.match(request);
return matchPromise;
})
.then(cachedResponse => {
if(cachedResponse) {
return Promise.resolve(cachedResponse);
}
return fetch(request).then(networkResponse => {
if(networkResponse.ok) {
updateCached(request, networkResponse.clone());
}
return Promise.resolve(networkResponse);
});
});
}
...
This may not play well with updating pck on the server though, and the first launch is still slow. I think if the game is large it might be necessary to keep main .pck small and fetch other resources after it is launched.
Can’t you export a project into multiple, smaller pcks? First one with exe, then just packs of levels and assets and contextual logic, like Quake, Unreal, etc. use to pack games, so you could just download the missing custom map to your client.
Might be a good feature request otherwise, not just for web exports.b
That looks totally doable, just unnecessary for my current goals.