@dcl-regenesislabs/bevy-explorer-web 0.1.0-21825038654.commit-36dc06e → 0.1.0-21841328189.commit-726f8ec

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env CHANGED
@@ -1 +1 @@
1
- PUBLIC_URL="https://cdn.decentraland.org/@dcl-regenesislabs/bevy-explorer-web/0.1.0-21825038654.commit-36dc06e"
1
+ PUBLIC_URL="https://cdn.decentraland.org/@dcl-regenesislabs/bevy-explorer-web/0.1.0-21841328189.commit-726f8ec"
package/engine.js ADDED
@@ -0,0 +1,255 @@
1
+ // Engine logic - ES module
2
+ // Handles WASM/WebGPU initialization and game execution
3
+
4
+ import init, { engine_init, engine_run, gpu_cache_hash } from "./pkg/webgpu_build.js";
5
+ import { initGpuCache } from "./gpu_cache.js";
6
+
7
+ // Re-export for main.js
8
+ export { gpu_cache_hash, initGpuCache };
9
+
10
+ /**
11
+ * Fetches a URL with download progress tracking.
12
+ * @param {string} url - URL to fetch
13
+ * @param {function} onProgress - Callback with percentage (0-100)
14
+ * @returns {Promise<ArrayBuffer>}
15
+ */
16
+ async function fetchWithProgress(url, onProgress) {
17
+ const response = await fetch(url);
18
+ const contentLength = response.headers.get('Content-Length');
19
+
20
+ if (!contentLength || !response.body) {
21
+ // Fallback if Content-Length is missing or no streaming support
22
+ const buffer = await response.arrayBuffer();
23
+ onProgress(100);
24
+ return buffer;
25
+ }
26
+
27
+ const total = parseInt(contentLength, 10);
28
+ const reader = response.body.getReader();
29
+ const chunks = [];
30
+ let received = 0;
31
+
32
+ while (true) {
33
+ const { done, value } = await reader.read();
34
+ if (done) break;
35
+
36
+ chunks.push(value);
37
+ received += value.length;
38
+ onProgress((received / total) * 100);
39
+ }
40
+
41
+ // Combine chunks into single ArrayBuffer
42
+ const buffer = new Uint8Array(received);
43
+ let position = 0;
44
+ for (const chunk of chunks) {
45
+ buffer.set(chunk, position);
46
+ position += chunk.length;
47
+ }
48
+
49
+ return buffer.buffer;
50
+ }
51
+
52
+ /**
53
+ * Initializes the WASM engine, shared memory, and worker threads.
54
+ * @returns {Promise<void>}
55
+ */
56
+ export async function initEngine() {
57
+
58
+ const publicUrl = window.PUBLIC_URL || ".";
59
+ const wasmUrl = `${publicUrl}/pkg/webgpu_build_bg.wasm`;
60
+
61
+ // Step 1: Download WASM with progress
62
+ setLoadingStepActive('download');
63
+ const wasmBytes = await fetchWithProgress(wasmUrl, (percent) => {
64
+ setLoadingStepProgress('download', percent);
65
+ });
66
+ setLoadingStepCompleted('download');
67
+
68
+ // Step 2: Compile WASM
69
+ setLoadingStepActive('compile');
70
+ console.time("compileTime")
71
+ const compiledModule = await WebAssembly.compile(wasmBytes);
72
+ console.timeEnd("compileTime") // 70 ms
73
+ setLoadingStepCompleted('compile');
74
+
75
+ const initialMemoryPages = 1280; // setting initial memory high causes malloc failures
76
+ const maximumMemoryPages = 65536;
77
+ const sharedMemory = new WebAssembly.Memory({
78
+ initial: initialMemoryPages,
79
+ maximum: maximumMemoryPages,
80
+ shared: true,
81
+ });
82
+ window.wasm_memory = sharedMemory;
83
+
84
+ // Setup HLS video source callback
85
+ window.setVideoSource = (video, src) => {
86
+ async function isHlsStream(url) {
87
+ try {
88
+ const response = await fetch(url, {
89
+ method: "HEAD",
90
+ mode: "cors",
91
+ });
92
+
93
+ if (!response.ok) {
94
+ return false;
95
+ }
96
+
97
+ const contentType = response.headers.get("Content-Type");
98
+
99
+ if (contentType) {
100
+ return (
101
+ contentType.includes("application/vnd.apple.mpegurl") ||
102
+ contentType.includes("application/x-mpegURL")
103
+ );
104
+ }
105
+
106
+ return false;
107
+ } catch (error) {
108
+ return false;
109
+ }
110
+ }
111
+
112
+ if (video.canPlayType("application/vnd.apple.mpegurl")) {
113
+ video.src = src;
114
+ } else if (Hls.isSupported()) {
115
+ // check if we need hls
116
+ setTimeout(async () => {
117
+ if (await isHlsStream(src)) {
118
+ var hls = new Hls();
119
+ hls.loadSource(src);
120
+ hls.attachMedia(video);
121
+ } else {
122
+ video.src = src;
123
+ }
124
+ }, 0);
125
+ }
126
+ };
127
+
128
+ // Setup sandbox worker spawn callback
129
+ window.spawn_and_init_sandbox = async () => {
130
+ var timeoutId;
131
+ return new Promise((resolve, _reject) => {
132
+ const basePath = window.location.pathname.replace(/\/$/, ''); // removes trailing slash if present
133
+ const sandboxWorkerPath = new URL(`${basePath}/sandbox_worker.js`, window.location.origin);
134
+ var sandboxWorker = new Worker(sandboxWorkerPath, { type: "module" });
135
+
136
+ var timeoutCount = 0;
137
+ let logTimeout = () => {
138
+ console.log(
139
+ "[Main JS] Still waiting for worker to init",
140
+ timeoutCount
141
+ );
142
+ timeoutCount += 1;
143
+ timeoutId = setTimeout(logTimeout, 5000);
144
+ };
145
+ timeoutId = setTimeout(logTimeout, 5000);
146
+
147
+ sandboxWorker.onmessage = (workerEvent) => {
148
+ if (workerEvent.data.type === "READY") {
149
+ sandboxWorker.postMessage({
150
+ type: "INIT_WORKER",
151
+ payload: {
152
+ compiledModule,
153
+ sharedMemory,
154
+ },
155
+ });
156
+ }
157
+ if (workerEvent.data.type === "INIT_COMPLETE") {
158
+ resolve();
159
+ }
160
+ if (workerEvent.data.type === "INIT_FAILED") {
161
+ console.log("[Main JS] Sandbox init failed; retrying");
162
+ sandboxWorker = new Worker(sandboxWorkerPath, { type: "module" });
163
+ }
164
+ };
165
+ }).finally(() => {
166
+ clearTimeout(timeoutId);
167
+ });
168
+ };
169
+
170
+ // Step 3: Initialize engine
171
+ setLoadingStepActive('init');
172
+ await init({ module_or_path: compiledModule, memory: sharedMemory });
173
+ console.log("[Main JS] Main application WebAssembly module initialized.");
174
+
175
+ let res = await engine_init();
176
+ console.log(
177
+ "[Main JS] Main application WebAssembly module custom initialized: ",
178
+ res
179
+ );
180
+ setLoadingStepCompleted('init');
181
+
182
+ // Step 4: Start workers
183
+ setLoadingStepActive('workers');
184
+ setLoadingStepProgress('workers', 0);
185
+
186
+ // start asset loader thread
187
+ await new Promise((resolve, _reject) => {
188
+ const basePath = window.location.pathname.replace(/\/$/, ''); // removes trailing slash if present
189
+ const assetLoaderPath = new URL(`${basePath}/asset_loader.js`, window.location.origin);
190
+
191
+ const assetLoader = new Worker(assetLoaderPath, { type: "module" });
192
+ assetLoader.onmessage = (workerEvent) => {
193
+ if (workerEvent.data.type === "READY") {
194
+ assetLoader.postMessage({
195
+ type: "INIT_ASSET_LOADER",
196
+ payload: {
197
+ compiledModule,
198
+ sharedMemory,
199
+ },
200
+ });
201
+ }
202
+ if (workerEvent.data.type === "INITIALIZED") {
203
+ resolve();
204
+ }
205
+ };
206
+ });
207
+ setLoadingStepProgress('workers', 50);
208
+
209
+ // start asset processor thread
210
+ await new Promise((resolve, _reject) => {
211
+ const basePath = window.location.pathname.replace(/\/$/, ''); // removes trailing slash if present
212
+ const assetProcessorPath = new URL(`${basePath}/asset_processor.js`, window.location.origin);
213
+
214
+ const assetProcessor = new Worker(assetProcessorPath, { type: "module" });
215
+ assetProcessor.onmessage = (workerEvent) => {
216
+ if (workerEvent.data.type === "READY") {
217
+ assetProcessor.postMessage({
218
+ type: "INIT_ASSET_PROCESSOR",
219
+ payload: {
220
+ compiledModule,
221
+ sharedMemory,
222
+ },
223
+ });
224
+ }
225
+ if (workerEvent.data.type === "INITIALIZED") {
226
+ resolve();
227
+ }
228
+ };
229
+ });
230
+ setLoadingStepCompleted('workers');
231
+ }
232
+
233
+ /**
234
+ * Starts the game engine with values from the UI inputs.
235
+ */
236
+ export function start() {
237
+ const realmValue = realmInput.value;
238
+ const positionValue = positionInput.value;
239
+ const systemScene = systemSceneInput.value;
240
+ const preview = previewInput.checked;
241
+ console.log(
242
+ `[Main JS] "Launch" button clicked. Initial Realm: "${realmValue}", Position (coords): "${positionValue}", System Scene: "${systemScene}"`
243
+ );
244
+ hideHeader();
245
+
246
+ const platform = (() => {
247
+ if (navigator.userAgent.includes("Mac")) return "macos";
248
+ if (navigator.userAgent.includes("Win")) return "windows";
249
+ if (navigator.userAgent.includes("Linux")) return "linux";
250
+ return "unknown";
251
+ })();
252
+
253
+ engine_run(platform, realmValue, positionValue, systemScene, true, preview, 1e7);
254
+ setTimeout(showCanvas,200)
255
+ }
Binary file
Binary file
Binary file
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="90"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="90"><svg viewBox="0 0 90 90" width="90" height="90" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M45 89.9999C69.8528 89.9999 89.9999 69.8528 89.9999 45C89.9999 20.1472 69.8528 0 45 0C20.1472 0 0 20.1472 0 45C0 69.8528 20.1472 89.9999 45 89.9999Z" fill="url(#paint0_linear_1_49380)"></path>
3
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M18 80.9996C25.515 86.6471 34.875 89.9996 45 89.9996C55.125 89.9996 64.485 86.6471 72 80.9996H18Z" fill="#FF2D55"></path>
4
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M9.00008 71.9996C11.5651 75.3971 14.6026 78.4346 18.0001 80.9996H72C75.3975 78.4346 78.435 75.3971 81 71.9996H9.00008Z" fill="#FFA25A"></path>
5
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M60.3675 62.9997H3.75757C5.15257 66.2172 6.93007 69.2322 9.00006 71.9997H60.39V62.9997H60.3675Z" fill="#FFC95B"></path>
6
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M31.8826 29.2496V62.9996H60.0075L31.8826 29.2496Z" fill="url(#paint1_linear_1_49380)"></path>
7
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M3.75757 62.9997H31.8826V29.2497L3.75757 62.9997Z" fill="white"></path>
8
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M60.3675 47.25V72H81L60.3675 47.25Z" fill="url(#paint2_linear_1_49380)"></path>
9
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M39.7574 72H60.3674V47.25L39.7574 72Z" fill="white"></path>
10
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M60.3675 40.4997C66.5807 40.4997 71.6175 35.4629 71.6175 29.2497C71.6175 23.0365 66.5807 17.9997 60.3675 17.9997C54.1543 17.9997 49.1175 23.0365 49.1175 29.2497C49.1175 35.4629 54.1543 40.4997 60.3675 40.4997Z" fill="#FFC95B"></path>
11
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M31.8824 22.4997C34.989 22.4997 37.5074 19.9813 37.5074 16.8747C37.5074 13.7681 34.989 11.2497 31.8824 11.2497C28.7758 11.2497 26.2574 13.7681 26.2574 16.8747C26.2574 19.9813 28.7758 22.4997 31.8824 22.4997Z" fill="#FFC95B"></path>
12
+ <defs>
13
+ <linearGradient id="paint0_linear_1_49380" x1="45" y1="-18.6396" x2="-18.6396" y2="45" gradientUnits="userSpaceOnUse">
14
+ <stop stop-color="#FF2D55"></stop>
15
+ <stop offset="1" stop-color="#FFBC5B"></stop>
16
+ </linearGradient>
17
+ <linearGradient id="paint1_linear_1_49380" x1="31.8731" y1="29.2497" x2="31.8731" y2="62.9996" gradientUnits="userSpaceOnUse">
18
+ <stop stop-color="#A524B3"></stop>
19
+ <stop offset="1" stop-color="#FF2D55"></stop>
20
+ </linearGradient>
21
+ <linearGradient id="paint2_linear_1_49380" x1="60.3605" y1="47.25" x2="60.3605" y2="72" gradientUnits="userSpaceOnUse">
22
+ <stop stop-color="#A524B3"></stop>
23
+ <stop offset="1" stop-color="#FF2D55"></stop>
24
+ </linearGradient>
25
+ </defs>
26
+ </svg></svg><style>@media (prefers-color-scheme: light) { :root { filter: none; } }
27
+ @media (prefers-color-scheme: dark) { :root { filter: none; } }
28
+ </style></svg>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "Decentraland (BEVY)",
3
+ "short_name": "BevyDCL",
4
+ "icons": [
5
+ {
6
+ "src": "/favicon/web-app-manifest-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png",
9
+ "purpose": "maskable"
10
+ },
11
+ {
12
+ "src": "/favicon/web-app-manifest-512x512.png",
13
+ "sizes": "512x512",
14
+ "type": "image/png",
15
+ "purpose": "maskable"
16
+ }
17
+ ],
18
+ "theme_color": "#ffffff",
19
+ "background_color": "#ffffff",
20
+ "display": "standalone"
21
+ }