mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-07-03 20:01:34 +00:00
remote loading support
This commit is contained in:
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "diabloweb",
|
"name": "diabloweb",
|
||||||
"version": "1.0.18",
|
"version": "1.0.19",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "diabloweb",
|
"name": "diabloweb",
|
||||||
"version": "1.0.18",
|
"version": "1.0.19",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.4.3",
|
"@babel/core": "7.4.3",
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ class App extends React.Component {
|
|||||||
|
|
||||||
this.setState({loading: true, retail});
|
this.setState({loading: true, retail});
|
||||||
|
|
||||||
load_game(this, file).then(game => {
|
load_game(this, file, !retail).then(game => {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
|
|
||||||
document.addEventListener('mousemove', this.onMouseMove, true);
|
document.addEventListener('mousemove', this.onMouseMove, true);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -7,6 +7,9 @@ import axios from 'axios';
|
|||||||
const DiabloSize = 1316452;
|
const DiabloSize = 1316452;
|
||||||
const SpawnSize = 1196648;
|
const SpawnSize = 1196648;
|
||||||
|
|
||||||
|
const SpawnMpqSize = 50274091;
|
||||||
|
const RetailMpqSize = 517501282;
|
||||||
|
|
||||||
/* eslint-disable-next-line no-restricted-globals */
|
/* eslint-disable-next-line no-restricted-globals */
|
||||||
const worker = self;
|
const worker = self;
|
||||||
|
|
||||||
@@ -17,6 +20,52 @@ let renderBatch = null;
|
|||||||
let drawBelt = null;
|
let drawBelt = null;
|
||||||
let is_spawn = false;
|
let is_spawn = false;
|
||||||
|
|
||||||
|
const ChunkSize = 1 << 20;
|
||||||
|
class RemoteFile {
|
||||||
|
constructor(url, size) {
|
||||||
|
this.url = url;
|
||||||
|
this.byteLength = size;
|
||||||
|
|
||||||
|
this.buffer = new Uint8Array(size);
|
||||||
|
this.chunks = new Uint8Array(((size + ChunkSize - 1) >> 20) | 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
subarray(start, end) {
|
||||||
|
let chunk0 = (start / ChunkSize) | 0;
|
||||||
|
let chunk1 = ((end + ChunkSize - 1) / ChunkSize) | 0;
|
||||||
|
let missing0 = chunk1, missing1 = chunk0;
|
||||||
|
for (let i = chunk0; i < chunk1; ++i) {
|
||||||
|
if (!this.chunks[i]) {
|
||||||
|
missing0 = Math.min(missing0, i);
|
||||||
|
missing1 = Math.max(missing1, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missing0 <= missing1) {
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.open('GET', this.url, false);
|
||||||
|
request.setRequestHeader('Range', `bytes=${missing0 * ChunkSize}-${Math.min(missing1 * ChunkSize + ChunkSize - 1, this.byteLength - 1)}`);
|
||||||
|
request.responseType = 'arraybuffer';
|
||||||
|
request.send();
|
||||||
|
if (request.status < 200 || request.status > 206) {
|
||||||
|
worker.postMessage({action: "error", error: `Failed to load remote file`});
|
||||||
|
} else {
|
||||||
|
const header = request.getResponseHeader('Content-Range');
|
||||||
|
let m, start = 0;
|
||||||
|
if (header && (m = header.match(/bytes (\d+)-(\d+)\/(\d+)/))) {
|
||||||
|
start = parseInt(m[1]);
|
||||||
|
}
|
||||||
|
this.buffer.set(new Uint8Array(request.response), start);
|
||||||
|
chunk0 = ((start + ChunkSize - 1) / ChunkSize) | 0;
|
||||||
|
chunk1 = ((start + request.response.byteLength + ChunkSize - 1) / ChunkSize) | 0;
|
||||||
|
for (let i = chunk0; i < chunk1; ++i) {
|
||||||
|
this.chunks[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.buffer.subarray(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DApi = {
|
const DApi = {
|
||||||
exit_error(error) {
|
exit_error(error) {
|
||||||
worker.postMessage({action: "error", error});
|
worker.postMessage({action: "error", error});
|
||||||
@@ -36,7 +85,7 @@ const DApi = {
|
|||||||
get_file_contents(path, array, offset) {
|
get_file_contents(path, array, offset) {
|
||||||
const data = files.get(path.toLowerCase());
|
const data = files.get(path.toLowerCase());
|
||||||
if (data) {
|
if (data) {
|
||||||
array.set(data.subarray(offset, offset + array.length));
|
array.set(data.subarray(offset, offset + array.byteLength));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
put_file_contents(path, array) {
|
put_file_contents(path, array) {
|
||||||
@@ -240,6 +289,14 @@ async function init_game(mpq, spawn, offscreen) {
|
|||||||
Object.assign(DApi, DApi_renderLegacy);
|
Object.assign(DApi, DApi_renderLegacy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mpq) {
|
||||||
|
const name = (spawn ? 'spawn.mpq' : 'diabdat.mpq');
|
||||||
|
if (!files.has(name)) {
|
||||||
|
// This should never happen, but we do support remote loading
|
||||||
|
files.set(name, new RemoteFile(`${process.env.PUBLIC_URL}/${name}`, spawn ? SpawnMpqSize : RetailMpqSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
progress("Loading...");
|
progress("Loading...");
|
||||||
let mpqLoaded = 0, mpqTotal = (mpq ? mpq.size : 0), wasmLoaded = 0, wasmTotal = (spawn ? SpawnSize : DiabloSize);
|
let mpqLoaded = 0, mpqTotal = (mpq ? mpq.size : 0), wasmLoaded = 0, wasmTotal = (spawn ? SpawnSize : DiabloSize);
|
||||||
const wasmWeight = 5;
|
const wasmWeight = 5;
|
||||||
|
|||||||
@@ -46,15 +46,9 @@ function testOffscreen() {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
async function do_load_game(api, audio, mpq) {
|
async function do_load_game(api, audio, mpq, spawn) {
|
||||||
const fs = await api.fs;
|
const fs = await api.fs;
|
||||||
let spawn = true;
|
if (spawn && !mpq) {
|
||||||
if (mpq) {
|
|
||||||
if (!mpq.name.match(/^spawn\.mpq$/i)) {
|
|
||||||
spawn = false;
|
|
||||||
fs.files.delete('spawn.mpq');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await load_spawn(api, fs);
|
await load_spawn(api, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +118,7 @@ async function do_load_game(api, audio, mpq) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function load_game(api, mpq) {
|
export default function load_game(api, mpq, spawn) {
|
||||||
const audio = init_sound();
|
const audio = init_sound();
|
||||||
return do_load_game(api, audio, mpq);
|
return do_load_game(api, audio, mpq, spawn);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user