Hello,

I'm working on a multiplayer social game based on an old french flash game that will be ONLY available on WEB. This game has lot of assets so game size is so big that the game takes sometimes more than 1 minute to be loaded ... So i made the decision to divide game assets by using http request and it work well : game is now loaded in 5 seconds on a fiber connection.

Now i want to reduce again the size : i have exported some scenes in .pck file but i don't know how to load them by using http request, i know for png you have a method "load_png_from_buffer" but there is any method for .pck file ? Its like documentation is not completed about web export, i mean there is no example to load a .pck file for WEB export ...

first you have to load the pck file as a resource

ProjectSettings.load_resource_pack("res://extentions/newlevels/" + modName + ".pck")

then the normal scene .tscn into it:

var scene = load("res://modScene.tscn")

@"K-Storm-Studio Ltd" said: first you have to load the pck file as a resource

ProjectSettings.load_resource_pack("res://extentions/newlevels/" + modName + ".pck")

then the normal scene .tscn into it:

var scene = load("res://modScene.tscn")

Yeah you are right but that only works for Windows/Linux/Mac export ... That's doesn't work for HTML5 so i'm looking for a solution using http request

@ChapatizRetro said:

@"K-Storm-Studio Ltd" said: first you have to load the pck file as a resource

ProjectSettings.load_resource_pack("res://extentions/newlevels/" + modName + ".pck")

then the normal scene .tscn into it:

var scene = load("res://modScene.tscn")

Yeah you are right but that only works for Windows/Linux/Mac export ... That's doesn't work for HTML5 so i'm looking for a solution using http request

mmmmhh... ok but this is about the Godot core engine so it shouldn't be related to the platform. When you compiling for HTML5 do you have the .PCK file?

@"K-Storm-Studio Ltd" said:

@ChapatizRetro said:

@"K-Storm-Studio Ltd" said: first you have to load the pck file as a resource

ProjectSettings.load_resource_pack("res://extentions/newlevels/" + modName + ".pck")

then the normal scene .tscn into it:

var scene = load("res://modScene.tscn")

Yeah you are right but that only works for Windows/Linux/Mac export ... That's doesn't work for HTML5 so i'm looking for a solution using http request

mmmmhh... ok but this is about the Godot core engine so it shouldn't be related to the platform. When you compiling for HTML5 do you have the .PCK file?

Yeah but i want to load another .pck file when user make an action and that's can't be done right now... Only option i have is using preloadFile() on HTML export but it sucks because i want to load another .pck file after user action.

Ok found the solution : 1. You need to use engine.preloadFile('path to your .pck file') on the html5 export page (before the function engine.startGame()) 2. Inside your project, you need to use the function ProjectSettings.load_resource_pack('res://name of your pck')

Documentation doesn't mention it anywhere, i hope it will help people that want to do a big game on HTML5

(Changed to a question and marked the answer so it's hopefully easier to find for anyone who has this problem in the future :smile: )

8 days later

Because using preloadFile make your browser download ALL your .pck file at the same time, i was looking for another solution.

I've found another solution to download .pck file only when you need it:

    func _ready():
    var client = HTTPRequest.new()
    client.connect('request_completed', self, '_request_completed')
    add_child(client)
    client.download_file = "res://name of your pck file.pck"
    client.request("http://link to your pck file")
    
    func _request_completed(result, response_code, headers, body):
    	if response_code == 200:
    		ProjectSettings.load_resource_pack("res://name of your pck file.pck")
    		get_tree().change_scene("res://name of your scene inside .pck file")

That's awesome but again it's a shame that these informations are not in the documentation

Don't forget to add : client.download_chunk_size = 65536 (it will speed up download on larger file)

7 months later
  1. You need to use engine.preloadFile('path to your .pck file') on the html5 export page (before the function engine.startGame())
  2. Inside your project, you need to use the function ProjectSettings.load_resource_pack('res://name of your pck')

can you give an example of the above?

You need to use engine.preloadFile('path to your .pck file') on the html5 export page (before the function engine.startGame())

any example ? I what path shall i add res:// or user://? Seems does not work in my case. please help

4 months later

This is one example

<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' lang='' xml:lang=''>
<head>
	
</head>
<body>
	<canvas id='canvas'>
		HTML5 canvas appears to be unsupported in the current browser.<br />
		Please try updating or use a different browser.
	</canvas>
	<div id='status'>
		<div id='status-progress' style='display: none;' oncontextmenu='event.preventDefault();'><div id ='status-progress-inner'></div></div>
		<div id='status-indeterminate' style='display: none;' oncontextmenu='event.preventDefault();'>
			<div></div>
			<div></div>
			<div></div>
			<div></div>
			<div></div>
			<div></div>
			<div></div>
			<div></div>
		</div>
		<div id='status-notice' class='godot' style='display: none;'></div>
	</div>

	<script type='text/javascript' src='PRCuoreLogin.js'></script>
	<script type='text/javascript'>//<![CDATA[

		const GODOT_CONFIG = {"args":[],"canvasResizePolicy":2,"executable":"PRCuoreLogin","experimentalVK":false,"fileSizes":{"PRCuoreLogin.pck":523424000,"PRCuoreLogin.wasm":23477599},"gdnativeLibs":[]};
		var engine = new Engine(GODOT_CONFIG);

		(function() {
			const INDETERMINATE_STATUS_STEP_MS = 100;
			var statusProgress = document.getElementById('status-progress');
			var statusProgressInner = document.getElementById('status-progress-inner');
			var statusIndeterminate = document.getElementById('status-indeterminate');
			var statusNotice = document.getElementById('status-notice');

			var initializing = true;
			var statusMode = 'hidden';

			var animationCallbacks = [];
			function animate(time) {
				animationCallbacks.forEach(callback => callback(time));
				requestAnimationFrame(animate);
			}
			requestAnimationFrame(animate);

			function setStatusMode(mode) {

				if (statusMode === mode || !initializing)
					return;
				[statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
					elem.style.display = 'none';
				});
				animationCallbacks = animationCallbacks.filter(function(value) {
					return (value != animateStatusIndeterminate);
				});
				switch (mode) {
					case 'progress':
						statusProgress.style.display = 'block';
						break;
					case 'indeterminate':
						statusIndeterminate.style.display = 'block';
						animationCallbacks.push(animateStatusIndeterminate);
						break;
					case 'notice':
						statusNotice.style.display = 'block';
						break;
					case 'hidden':
						break;
					default:
						throw new Error('Invalid status mode');
				}
				statusMode = mode;
			}

			function animateStatusIndeterminate(ms) {
				var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
				if (statusIndeterminate.children[i].style.borderTopColor == '') {
					Array.prototype.slice.call(statusIndeterminate.children).forEach(child => {
						child.style.borderTopColor = '';
					});
					statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
				}
			}

			function setStatusNotice(text) {
				while (statusNotice.lastChild) {
					statusNotice.removeChild(statusNotice.lastChild);
				}
				var lines = text.split('\n');
				lines.forEach((line) => {
					statusNotice.appendChild(document.createTextNode(line));
					statusNotice.appendChild(document.createElement('br'));
				});
			};

			function displayFailureNotice(err) {
				var msg = err.message || err;
				console.error(msg);
				setStatusNotice(msg);
				setStatusMode('notice');
				initializing = false;
			};

			if (!Engine.isWebGLAvailable()) {
				displayFailureNotice('WebGL not available');
			} else {
				setStatusMode('indeterminate');
				engine.preloadFile('main.pck').then(() => {
 
				engine.startGame({
					'onProgress': function (current, total) {
						if (total > 0) {
							statusProgressInner.style.width = current/total * 100 + '%';
							setStatusMode('progress');
							if (current === total) {
								// wait for progress bar animation
								setTimeout(() => {
									setStatusMode('indeterminate');
								}, 500);
							}
						} else {
							setStatusMode('indeterminate');
						}
					},
				}).then(() => {
					setStatusMode('hidden');
					initializing = false;
				}, displayFailureNotice);
				
				});
			}
			
		})();
	//]]></script>
</body>
</html>
a year later