From 6912c4dbfcde8e7310fb1a6088fb22490c845baf Mon Sep 17 00:00:00 2001 From: fechan Date: Wed, 8 Jul 2026 21:07:10 -0700 Subject: [PATCH 1/3] fix indentation --- common/webapp/src/js/map/Map.js | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/common/webapp/src/js/map/Map.js b/common/webapp/src/js/map/Map.js index bc9e3aa94..3e3df5ca6 100644 --- a/common/webapp/src/js/map/Map.js +++ b/common/webapp/src/js/map/Map.js @@ -129,28 +129,28 @@ export class Map { this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); this.hiresTileManager = new TileManager(new TileLoader( - `${this.data.mapDataRoot}/tiles/0/`, - this.hiresMaterial, - this.data.hires, - this.loadBlocker, - revalidatedUrls - ), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); - this.hiresTileManager.scene.matrixWorldAutoUpdate = false; - - this.lowresTileManager = []; - for (let i = 0; i < this.data.lowres.lodCount; i++) { - this.lowresTileManager[i] = new TileManager(new LowresTileLoader( - `${this.data.mapDataRoot}/tiles/`, - this.data.lowres, - i + 1, - lowresVertexShader, - lowresFragmentShader, - uniforms, - async () => {}, - revalidatedUrls - ), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); - this.lowresTileManager[i].scene.matrixWorldAutoUpdate = false; - } + `${this.data.mapDataRoot}/tiles/0/`, + this.hiresMaterial, + this.data.hires, + this.loadBlocker, + revalidatedUrls + ), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); + this.hiresTileManager.scene.matrixWorldAutoUpdate = false; + + this.lowresTileManager = []; + for (let i = 0; i < this.data.lowres.lodCount; i++) { + this.lowresTileManager[i] = new TileManager(new LowresTileLoader( + `${this.data.mapDataRoot}/tiles/`, + this.data.lowres, + i + 1, + lowresVertexShader, + lowresFragmentShader, + uniforms, + async () => {}, + revalidatedUrls + ), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); + this.lowresTileManager[i].scene.matrixWorldAutoUpdate = false; + } alert(this.events, `Map '${this.data.id}' is loaded.`, "fine"); }); From 80c46059bbad2a1dfcea227d758e8e606921ec99 Mon Sep 17 00:00:00 2001 From: fechan Date: Wed, 8 Jul 2026 22:31:13 -0700 Subject: [PATCH 2/3] perform client decompression for textures.json.gz when configured --- common/webapp/src/js/BlueMapApp.js | 4 ++- common/webapp/src/js/map/Map.js | 9 ++++--- .../src/js/util/RevalidatingFileLoader.js | 27 +++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/common/webapp/src/js/BlueMapApp.js b/common/webapp/src/js/BlueMapApp.js index 08a27b8b1..ba3fbc685 100644 --- a/common/webapp/src/js/BlueMapApp.js +++ b/common/webapp/src/js/BlueMapApp.js @@ -76,6 +76,7 @@ export class BlueMapApp { * maps: string[], * scripts: string[], * styles: string[] + * clientDecompression: boolean, * }} **/ this.settings = null; @@ -308,7 +309,7 @@ export class BlueMapApp { // create maps if (settings.maps !== undefined){ let loadingPromises = settings.maps.map(mapId => { - let map = new BlueMapMap(mapId, settings.mapDataRoot + "/" + mapId, settings.liveDataRoot + "/" + mapId, this.loadBlocker, this.mapViewer.events); + let map = new BlueMapMap(mapId, settings.mapDataRoot + "/" + mapId, settings.liveDataRoot + "/" + mapId, this.loadBlocker, this.mapViewer.events, this.settings.clientDecompression); maps.push(map); return map.loadSettings(this.mapViewer.revalidatedUrls) @@ -355,6 +356,7 @@ export class BlueMapApp { ], scripts: [], styles: [], + clientDecompression: false, ...loaded }; } diff --git a/common/webapp/src/js/map/Map.js b/common/webapp/src/js/map/Map.js index 3e3df5ca6..5cc3ba2b7 100644 --- a/common/webapp/src/js/map/Map.js +++ b/common/webapp/src/js/map/Map.js @@ -49,8 +49,9 @@ export class Map { * @param liveDataRoot {string} * @param loadBlocker {function: Promise} * @param events {EventTarget} + * @param clientDecompression {boolean} */ - constructor(id, mapDataRoot, liveDataRoot, loadBlocker, events = null) { + constructor(id, mapDataRoot, liveDataRoot, loadBlocker, events = null, clientDecompression) { Object.defineProperty( this, 'isMap', { value: true } ); this.loadBlocker = loadBlocker; @@ -62,7 +63,7 @@ export class Map { mapDataRoot: mapDataRoot, liveDataRoot: liveDataRoot, settingsUrl: mapDataRoot + "/settings.json", - texturesUrl: mapDataRoot + "/textures.json", + texturesUrl: mapDataRoot + (clientDecompression ? "/textures.json.gz" : "/textures.json"), name: id, startPos: {x: 0, z: 0}, skyColor: new Color(), @@ -133,7 +134,8 @@ export class Map { this.hiresMaterial, this.data.hires, this.loadBlocker, - revalidatedUrls + revalidatedUrls, + this.data.clientDecompression ), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); this.hiresTileManager.scene.matrixWorldAutoUpdate = false; @@ -285,6 +287,7 @@ export class Map { let loader = new RevalidatingFileLoader(); loader.setRevalidatedUrls(revalidatedUrls); loader.setResponseType("json"); + loader.setClientDecompression(this.data.clientDecompression); loader.load(this.data.texturesUrl, resolve, () => {}, diff --git a/common/webapp/src/js/util/RevalidatingFileLoader.js b/common/webapp/src/js/util/RevalidatingFileLoader.js index ae64163bb..46048d646 100644 --- a/common/webapp/src/js/util/RevalidatingFileLoader.js +++ b/common/webapp/src/js/util/RevalidatingFileLoader.js @@ -55,6 +55,14 @@ export class RevalidatingFileLoader extends Loader { */ this.responseType = ""; + /** + * Whether client-side decompression is required. + * + * @type {boolean} + * @default false; + */ + this.clientDecompression = false; + /** * Used for aborting requests. * @@ -246,6 +254,15 @@ export class RevalidatingFileLoader extends Loader { ); } }) + .then(async (response) => { + if (this.clientDecompression) { + const ds = new DecompressionStream("gzip"); + const decompressedStream = (await response.blob()).stream().pipeThrough(ds); + const decompressedResponse = new Response(decompressedStream); + return decompressedResponse; + } + return response; + }) .then((response) => { switch (responseType) { case "arraybuffer": @@ -344,6 +361,16 @@ export class RevalidatingFileLoader extends Loader { return this; } + /** + * Sets whether client-side decompression is required. + * @param {boolean} value - True if the client must decompress the loaded file + * @returns {FileLoader} A reference to this file loader. + */ + setClientDecompression(value) { + this.clientDecompression = value; + return this; + } + /** * Aborts ongoing fetch requests. * From 20d435c587cda11f1edeed5a8bfc0f2b3ad34816 Mon Sep 17 00:00:00 2001 From: fechan Date: Wed, 8 Jul 2026 23:46:15 -0700 Subject: [PATCH 3/3] request and decompress gzipped prbms when clientDecompression enabled --- common/webapp/src/js/map/Map.js | 3 ++- common/webapp/src/js/map/TileLoader.js | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/common/webapp/src/js/map/Map.js b/common/webapp/src/js/map/Map.js index 5cc3ba2b7..e96aeeec0 100644 --- a/common/webapp/src/js/map/Map.js +++ b/common/webapp/src/js/map/Map.js @@ -83,7 +83,8 @@ export class Map { perspectiveView: false, flatView: false, freeFlightView: false, - views: ["perspective", "flat", "free"] + views: ["perspective", "flat", "free"], + clientDecompression: clientDecompression }); this.raycaster = new Raycaster(); diff --git a/common/webapp/src/js/map/TileLoader.js b/common/webapp/src/js/map/TileLoader.js index 9aadafada..7fedf0047 100644 --- a/common/webapp/src/js/map/TileLoader.js +++ b/common/webapp/src/js/map/TileLoader.js @@ -39,8 +39,9 @@ export class TileLoader { * }} * @param loadBlocker {function: Promise} * @param revalidatedUrls {Set | undefined} + * @param clientDecompression {boolean} */ - constructor(tilePath, material, tileSettings, loadBlocker = () => Promise.resolve(), revalidatedUrls) { + constructor(tilePath, material, tileSettings, loadBlocker = () => Promise.resolve(), revalidatedUrls, clientDecompression) { Object.defineProperty( this, 'isTileLoader', { value: true } ); this.tilePath = tilePath; @@ -54,12 +55,17 @@ export class TileLoader { this.fileLoader = new RevalidatingFileLoader(); this.fileLoader.setResponseType('arraybuffer'); this.fileLoader.setRevalidatedUrls(this.revalidatedUrls); + this.fileLoader.setClientDecompression(clientDecompression); + this.clientDecompression = clientDecompression; this.bufferGeometryLoader = new PRBMLoader(); } load = (tileX, tileZ, cancelCheck = () => false) => { let tileUrl = this.tilePath + pathFromCoords(tileX, tileZ) + '.prbm'; + if (this.clientDecompression) { + tileUrl += '.gz'; + } return new Promise((resolve, reject) => { this.fileLoader.setRevalidatedUrls(this.revalidatedUrls);