File: client.html

package info (click to toggle)
openmohaa 0.82.1%2Bdfsg-1
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 34,192 kB
  • sloc: cpp: 315,720; ansic: 275,789; sh: 312; xml: 246; asm: 141; makefile: 7
file content (116 lines) | stat: -rw-r--r-- 6,050 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<!DOCTYPE html><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>__CLIENTBIN__ Emscripten demo</title>
<style>
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: rgb(0, 0, 0); display:flex; align-items: center; justify-content: center; }
canvas { max-width: 100%; max-height: 100%; min-width: 100%; min-height: 100%; object-fit: contain; }
</style>

<canvas id=canvas></canvas>

<script type=module>
// These strings are set in the generated HTML file in the build directory.
let CLIENTBIN = '__CLIENTBIN__';
let BASEGAME = '__BASEGAME__';
let EMSCRIPTEN_PRELOAD_FILE = Number('__EMSCRIPTEN_PRELOAD_FILE__');
// Detect if it's not the generated HTML file.
let clientHtmlFallback = (CLIENTBIN === '\_\_CLIENTBIN\_\_');

// Path or URL containing the client engine .js, .wasm, and possibly .data.
let enginePath = './';
// Path or URL containing fs_game directories.
let dataPath = './';
// Path or URL for config file that specifies the files to load for each fs_game.
let configFilename = `./${CLIENTBIN}-config.json`;

// If displaying the unmodified HTML file, fallback to defaults.
if (clientHtmlFallback) {
    CLIENTBIN='ioquake3';
    BASEGAME='baseq3';
    EMSCRIPTEN_PRELOAD_FILE=0;
    configFilename='./client-config.json';
}

if (window.location.protocol === 'file:') throw new Error(`Unfortunately browser security restrictions prevent loading wasm from a file: URL. This file must be loaded from a web server. The easiest way to do this is probably to use Python\'s built-in web server by running \`python3 -m http.server\` in the top level source directory and then navigate to http://localhost:8000/build/debug-emscripten-wasm32/${CLIENTBIN}.html`);

// First set up the command line arguments and the Emscripten filesystem.
const urlParams = new URLSearchParams(window.location.search);
const com_basegame = urlParams.get('com_basegame') || BASEGAME;
const fs_basegame = urlParams.get('fs_basegame') || '';
const fs_game = urlParams.get('fs_game') || '';
let generatedArguments = `
    +set sv_pure 0
    +set net_enabled 0
    +set r_mode -2
    +set com_basegame "${com_basegame}"
    +set fs_basegame "${fs_basegame}"
    +set fs_game "${fs_game}"
`;
// Note that unfortunately "+" needs to be encoded as "%2b" in URL query strings or it will be stripped by the browser.
const queryArgs = urlParams.get('args');
if (queryArgs) generatedArguments += ` ${queryArgs} `;

// If displaying the unmodified HTML file, the engine and data are probably located in a different directory.
if (clientHtmlFallback) {
    // If buildPath is not specified, try to find a build in one of a few default paths.
    let buildPath = urlParams.get('buildPath');
    if (buildPath && !buildPath.endsWith('/')) buildPath += '/';
    const buildPaths = buildPath ? [buildPath] : ['../../build/debug-emscripten-wasm32/', '../../build/release-emscripten-wasm32/', './'];
    const scriptPaths = buildPaths.map(buildPath => buildPath + `${CLIENTBIN}_opengl2.wasm32.js`);
    const scriptResponses = await Promise.all(scriptPaths.map(p => fetch(p, {method: 'HEAD'})));
    const validBuilds = scriptResponses.filter(r => r.ok).length;
    const goodURL = (newPath) => {
        const url = new URL(window.location);
        url.searchParams.set('buildPath', newPath);
        return url.toString().replace(/%2f/gi, '/');
    };
    if (validBuilds === 0) throw new Error(`Didn't find any wasm builds. Run \`emmake make debug\` to build one, or use the buildPath query parameter to specify a directory containing ${CLIENTBIN}_opengl2.wasm32.[js,wasm,data], e.g. ${goodURL('../../build/debug-emscripten-wasm32/')}`);
    if (validBuilds > 1) throw new Error(`Found multiple valid builds at the following paths: [${buildPaths.filter((path, i)=>scriptResponses[i].ok)}]. Please specify which one to run by adding a buildPath query parameter to the URL, e.g. ${goodURL(buildPaths.filter((path, i)=>scriptResponses[i].ok)[0])}`);
    const buildIndex = scriptResponses.findIndex(r => r.ok);

    enginePath = buildPaths[buildIndex];
    dataPath = buildPaths[buildIndex];
}

const dataURL = new URL(dataPath, location.origin + location.pathname);

const configPromise = ( EMSCRIPTEN_PRELOAD_FILE === 1 ) ? Promise.resolve({[BASEGAME]: {files: []}})
  : fetch(configFilename).then(r => r.ok ? r.json() : { /* empty config */ });

const ioquake3 = (await import(enginePath + `${CLIENTBIN}_opengl2.wasm32.js`)).default;
ioquake3({
    canvas: canvas,
    arguments: generatedArguments.trim().split(/\s+/),
    locateFile: (file) => enginePath + file,
    preRun: [async (module) => {
        module.addRunDependency('setup-ioq3-filesystem');
        try {
            const config = await configPromise;
            const gamedirs = [com_basegame,fs_basegame,fs_game];
            for (let g = 0; g < gamedirs.length; g++) {
                const gamedir = gamedirs[g];
                if (gamedir === '') {
                    continue;
                }
                if (config[gamedir] === null
                 || config[gamedir].files === null) {
                    console.warn(`Game directory '${gamedir}' cannot be used. It must have files listed in ${configFilename}.`);
                    continue;
                }
                const files = config[gamedir].files;
                const fetches = files.map(file => fetch(new URL(file.src, dataURL)));
                for (let i = 0; i < files.length; i++) {
                    const response = await fetches[i];
                    if (!response.ok) continue;
                    const data = await response.arrayBuffer();
                    let name = files[i].src.match(/[^/]+$/)[0];
                    let dir = files[i].dst;
                    module.FS.mkdirTree(dir);
                    module.FS.writeFile(`${dir}/${name}`, new Uint8Array(data));
                }
            }
        } finally {
            module.removeRunDependency('setup-ioq3-filesystem');
        }
    }],
});
</script>