mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-06-03 21:41:38 +00:00
multiplayer rtc
This commit is contained in:
209
package-lock.json
generated
209
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "diabloweb",
|
||||
"version": "1.0.25",
|
||||
"version": "1.0.27",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1386,6 +1386,11 @@
|
||||
"@types/istanbul-lib-report": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "10.14.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.15.tgz",
|
||||
"integrity": "sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g=="
|
||||
},
|
||||
"@types/q": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
|
||||
@@ -1396,6 +1401,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
|
||||
},
|
||||
"@types/webrtc": {
|
||||
"version": "0.0.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/webrtc/-/webrtc-0.0.25.tgz",
|
||||
"integrity": "sha512-ep/e+p2uUKV1h96GBgRhwomrBch/bPDHPOKbCHODLGRUDuuKe2s7sErlFVKw+5BYUzvpxSmUNqoadaZ44MePoQ=="
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "12.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz",
|
||||
@@ -2183,6 +2193,28 @@
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz",
|
||||
"integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA=="
|
||||
},
|
||||
"babel-polyfill": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz",
|
||||
"integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=",
|
||||
"requires": {
|
||||
"babel-runtime": "^6.22.0",
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
|
||||
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A=="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-preset-jest": {
|
||||
"version": "24.6.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz",
|
||||
@@ -3978,6 +4010,14 @@
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
|
||||
"requires": {
|
||||
"iconv-lite": "~0.4.13"
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||
@@ -7333,6 +7373,11 @@
|
||||
"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
|
||||
"dev": true
|
||||
},
|
||||
"js-binarypack": {
|
||||
"version": "0.0.9",
|
||||
"resolved": "https://registry.npmjs.org/js-binarypack/-/js-binarypack-0.0.9.tgz",
|
||||
"integrity": "sha1-RUJD094hKWHMFRSi8Rnewvr2QDU="
|
||||
},
|
||||
"js-levenshtein": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
||||
@@ -8226,6 +8271,15 @@
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz",
|
||||
"integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=",
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
|
||||
@@ -8653,6 +8707,110 @@
|
||||
"mimic-fn": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"opencollective": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz",
|
||||
"integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=",
|
||||
"requires": {
|
||||
"babel-polyfill": "6.23.0",
|
||||
"chalk": "1.1.3",
|
||||
"inquirer": "3.0.6",
|
||||
"minimist": "1.2.0",
|
||||
"node-fetch": "1.6.3",
|
||||
"opn": "4.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-escapes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
|
||||
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4="
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"chardet": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
|
||||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
|
||||
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
|
||||
"requires": {
|
||||
"chardet": "^0.4.0",
|
||||
"iconv-lite": "^0.4.17",
|
||||
"tmp": "^0.0.33"
|
||||
}
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz",
|
||||
"integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=",
|
||||
"requires": {
|
||||
"ansi-escapes": "^1.1.0",
|
||||
"chalk": "^1.0.0",
|
||||
"cli-cursor": "^2.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^2.0.1",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.3.0",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rx": "^4.1.0",
|
||||
"string-width": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"through": "^2.3.6"
|
||||
}
|
||||
},
|
||||
"opn": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
|
||||
"integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
|
||||
"requires": {
|
||||
"object-assign": "^4.0.1",
|
||||
"pinkie-promise": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||
}
|
||||
}
|
||||
},
|
||||
"opencollective-postinstall": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz",
|
||||
"integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw=="
|
||||
},
|
||||
"opn": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
|
||||
@@ -8937,6 +9095,21 @@
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"peerjs": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.0.2.tgz",
|
||||
"integrity": "sha512-lVXh+R7KnrVt3WBhP+QNO8dhdezmhEF+wwJdVfxlayRG7jgi7D3vx+9UoW2wv5OlVzuAVL+NGJeYGQR9VrMhbQ==",
|
||||
"requires": {
|
||||
"@types/node": "^10.14.12",
|
||||
"@types/webrtc": "^0.0.25",
|
||||
"eventemitter3": "^3.1.2",
|
||||
"js-binarypack": "0.0.9",
|
||||
"opencollective": "^1.0.3",
|
||||
"opencollective-postinstall": "^2.0.0",
|
||||
"reliable": "git+https://github.com/michelle/reliable.git",
|
||||
"webrtc-adapter": "^7.2.6"
|
||||
}
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
@@ -10439,6 +10612,13 @@
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
|
||||
},
|
||||
"reliable": {
|
||||
"version": "git+https://github.com/michelle/reliable.git#70604f577ae55a2eb015c17d73cc8d9dce5f9ec4",
|
||||
"from": "git+https://github.com/michelle/reliable.git",
|
||||
"requires": {
|
||||
"js-binarypack": "0.0.9"
|
||||
}
|
||||
},
|
||||
"remove-trailing-separator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||
@@ -10663,6 +10843,14 @@
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
|
||||
},
|
||||
"rtcpeerconnection-shim": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
|
||||
"integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
|
||||
"requires": {
|
||||
"sdp": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"run-async": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
||||
@@ -10679,6 +10867,11 @@
|
||||
"aproba": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"rx": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz",
|
||||
"integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I="
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz",
|
||||
@@ -11061,6 +11254,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sdp": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.10.0.tgz",
|
||||
"integrity": "sha512-H+VjfyQpRz9GezhshJmkXTtCAT9/2g9az3GFDPYfGOz0eAOQU1fCrL3S9Dq/eUT9FtOyLi/czdR9PzK3fKUYOQ=="
|
||||
},
|
||||
"select-hose": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
||||
@@ -12697,6 +12895,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"webrtc-adapter": {
|
||||
"version": "7.2.9",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.2.9.tgz",
|
||||
"integrity": "sha512-98rcdbSqUBR+L+erotCFWgiPyYjCEq6NJYN/1Bl6cRl2CxSU3wanJlc4YdfWzaTGaK13ZVmHay2mlW4aOWXh0A==",
|
||||
"requires": {
|
||||
"rtcpeerconnection-shim": "^1.2.15",
|
||||
"sdp": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "diabloweb",
|
||||
"version": "1.0.25",
|
||||
"version": "1.0.27",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "7.4.3",
|
||||
@@ -39,6 +39,7 @@
|
||||
"jest-watch-typeahead": "0.3.0",
|
||||
"mini-css-extract-plugin": "0.5.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
||||
"peerjs": "^1.0.2",
|
||||
"pnp-webpack-plugin": "1.2.1",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
"postcss-loader": "3.0.0",
|
||||
|
||||
@@ -7,6 +7,10 @@ import create_fs from './fs';
|
||||
import load_game from './api/loader';
|
||||
import { SpawnSizes } from './api/load_spawn';
|
||||
|
||||
import Peer from 'peerjs';
|
||||
|
||||
window.Peer = Peer;
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
ReactGA.initialize('UA-43123589-6');
|
||||
ReactGA.pageview('/');
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -3,7 +3,6 @@ import DiabloModule from './Diablo.jscc';
|
||||
import SpawnBinary from './DiabloSpawn.wasm';
|
||||
import SpawnModule from './DiabloSpawn.jscc';
|
||||
import axios from 'axios';
|
||||
import websocket_open from './websocket';
|
||||
|
||||
const DiabloSize = 1316452;
|
||||
const SpawnSize = 1196648;
|
||||
@@ -17,7 +16,6 @@ let files = null;
|
||||
let renderBatch = null;
|
||||
let drawBelt = null;
|
||||
let is_spawn = false;
|
||||
let websocket = null;
|
||||
|
||||
const ChunkSize = 1 << 20;
|
||||
class RemoteFile {
|
||||
@@ -118,13 +116,8 @@ const DApi = {
|
||||
worker.postMessage({action: "keyboard", rect: null});
|
||||
},
|
||||
|
||||
websocket_send(data) {
|
||||
if (websocket) {
|
||||
websocket.send(data);
|
||||
}
|
||||
},
|
||||
websocket_closed() {
|
||||
return !websocket || websocket.readyState !== WebSocket.OPEN;
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -239,21 +232,22 @@ let maxSoundId = 0, maxBatchId = 0;
|
||||
}
|
||||
});
|
||||
|
||||
let packetBatch = null;
|
||||
DApi.websocket_send = function(data) {
|
||||
if (packetBatch) {
|
||||
packetBatch.push(data.slice().buffer);
|
||||
} else {
|
||||
worker.postMessage({action: "packet", buffer: data});
|
||||
}
|
||||
};
|
||||
|
||||
worker.DApi = DApi;
|
||||
|
||||
let wasm = null;
|
||||
|
||||
function call_api(func, ...params) {
|
||||
function try_api(func) {
|
||||
try {
|
||||
audioBatch = [];
|
||||
audioTransfer = [];
|
||||
wasm["_" + func](...params);
|
||||
if (audioBatch.length) {
|
||||
maxSoundId = maxBatchId;
|
||||
worker.postMessage({action: "audioBatch", batch: audioBatch}, audioTransfer);
|
||||
audioBatch = null;
|
||||
audioTransfer = null;
|
||||
}
|
||||
func();
|
||||
} catch (e) {
|
||||
if (typeof e === "string") {
|
||||
worker.postMessage({action: ""})
|
||||
@@ -262,6 +256,25 @@ function call_api(func, ...params) {
|
||||
}
|
||||
}
|
||||
|
||||
function call_api(func, ...params) {
|
||||
try_api(() => {
|
||||
audioBatch = [];
|
||||
audioTransfer = [];
|
||||
packetBatch = [];
|
||||
wasm["_" + func](...params);
|
||||
if (audioBatch.length) {
|
||||
maxSoundId = maxBatchId;
|
||||
worker.postMessage({action: "audioBatch", batch: audioBatch}, audioTransfer);
|
||||
}
|
||||
if (packetBatch.length) {
|
||||
worker.postMessage({action: "packetBatch", batch: packetBatch}, packetBatch);
|
||||
}
|
||||
audioBatch = null;
|
||||
audioTransfer = null;
|
||||
packetBatch = null;
|
||||
});
|
||||
}
|
||||
|
||||
function progress(text, loaded, total) {
|
||||
worker.postMessage({action: "progress", text, loaded, total});
|
||||
}
|
||||
@@ -293,7 +306,7 @@ async function initWasm(spawn, progress) {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function init_game(mpq, spawn, offscreen, serverUrl) {
|
||||
async function init_game(mpq, spawn, offscreen) {
|
||||
is_spawn = spawn;
|
||||
if (offscreen) {
|
||||
canvas = new OffscreenCanvas(640, 480);
|
||||
@@ -312,16 +325,6 @@ async function init_game(mpq, spawn, offscreen, serverUrl) {
|
||||
}
|
||||
}
|
||||
|
||||
if (serverUrl) {
|
||||
progress("Connecting...");
|
||||
websocket = await websocket_open(serverUrl, data => {
|
||||
if (wasm) {
|
||||
const ptr = wasm._DApi_AllocPacket(data.byteLength);
|
||||
wasm.HEAPU8.set(new Uint8Array(data), ptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
progress("Loading...");
|
||||
let mpqLoaded = 0, mpqTotal = (mpq ? mpq.size : 0), wasmLoaded = 0, wasmTotal = (spawn ? SpawnSize : DiabloSize);
|
||||
const wasmWeight = 5;
|
||||
@@ -346,9 +349,7 @@ async function init_game(mpq, spawn, offscreen, serverUrl) {
|
||||
|
||||
const vers = process.env.VERSION.match(/(\d+)\.(\d+)\.(\d+)/);
|
||||
|
||||
if (websocket) {
|
||||
wasm._SNet_InitWebsocket();
|
||||
}
|
||||
wasm._SNet_InitWebsocket();
|
||||
wasm._DApi_Init(Math.floor(performance.now()), offscreen ? 1 : 0, parseInt(vers[1]), parseInt(vers[2]), parseInt(vers[3]));
|
||||
|
||||
setInterval(() => {
|
||||
@@ -360,13 +361,27 @@ worker.addEventListener("message", ({data}) => {
|
||||
switch (data.action) {
|
||||
case "init":
|
||||
files = data.files;
|
||||
init_game(data.mpq, data.spawn, data.offscreen, data.websocket).then(
|
||||
init_game(data.mpq, data.spawn, data.offscreen).then(
|
||||
() => worker.postMessage({action: "loaded"}),
|
||||
e => worker.postMessage({action: "failed", error: e.toString(), stack: e.stack}));
|
||||
break;
|
||||
case "event":
|
||||
call_api(data.func, ...data.params);
|
||||
break;
|
||||
case "packet":
|
||||
try_api(() => {
|
||||
const ptr = wasm._DApi_AllocPacket(data.buffer.byteLength);
|
||||
wasm.HEAPU8.set(new Uint8Array(data.buffer), ptr);
|
||||
});
|
||||
break;
|
||||
case "packetBatch":
|
||||
try_api(() => {
|
||||
for (let packet of data.batch) {
|
||||
const ptr = wasm._DApi_AllocPacket(packet.byteLength);
|
||||
wasm.HEAPU8.set(new Uint8Array(packet), ptr);
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Worker from './game.worker.js';
|
||||
import init_sound from './sound';
|
||||
import load_spawn from './load_spawn';
|
||||
import webrtc_open from './webrtc';
|
||||
|
||||
function onRender(api, ctx, {bitmap, images, text, clip, belt}) {
|
||||
if (bitmap) {
|
||||
@@ -65,6 +66,12 @@ async function do_load_game(api, audio, mpq, spawn) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
try {
|
||||
const worker = new Worker();
|
||||
|
||||
let packetQueue = [];
|
||||
const webrtc = webrtc_open(data => {
|
||||
packetQueue.push(data);
|
||||
});
|
||||
|
||||
worker.addEventListener("message", ({data}) => {
|
||||
switch (data.action) {
|
||||
case "loaded":
|
||||
@@ -106,14 +113,28 @@ async function do_load_game(api, audio, mpq, spawn) {
|
||||
case "current_save":
|
||||
api.setCurrentSave(data.name);
|
||||
break;
|
||||
case "packet":
|
||||
webrtc.send(data.buffer);
|
||||
break;
|
||||
case "packetBatch":
|
||||
for (let packet of data.batch) {
|
||||
webrtc.send(packet);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
});
|
||||
const transfer= [];
|
||||
for (let [, file] of fs.files) {
|
||||
transfer.push(file.buffer);
|
||||
}
|
||||
worker.postMessage({action: "init", files: fs.files, mpq, spawn, offscreen, websocket: window.gameServer}, transfer);
|
||||
worker.postMessage({action: "init", files: fs.files, mpq, spawn, offscreen}, transfer);
|
||||
setInterval(() => {
|
||||
if (packetQueue.length) {
|
||||
worker.postMessage({action: "packetBatch", batch: packetQueue}, packetQueue);
|
||||
packetQueue.length = 0;
|
||||
}
|
||||
}, 20);
|
||||
delete fs.files;
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
|
||||
@@ -17,6 +17,7 @@ function decodeAudioData(context, buffer) {
|
||||
|
||||
export default function init_sound() {
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
const StereoPannerNode = window.StereoPannerNode || window.webkitAudioPannerNode;
|
||||
if (!AudioContext) {
|
||||
return no_sound();
|
||||
}
|
||||
@@ -40,7 +41,7 @@ export default function init_sound() {
|
||||
sounds.set(id, {
|
||||
buffer: Promise.resolve(buffer),
|
||||
gain: context.createGain(),
|
||||
panner: new StereoPannerNode(context, {pan: 0}),
|
||||
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||
});
|
||||
},
|
||||
create_sound(id, data) {
|
||||
@@ -51,7 +52,7 @@ export default function init_sound() {
|
||||
sounds.set(id, {
|
||||
buffer,
|
||||
gain: context.createGain(),
|
||||
panner: new StereoPannerNode(context, {pan: 0}),
|
||||
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||
});
|
||||
},
|
||||
duplicate_sound(id, srcId) {
|
||||
@@ -65,7 +66,7 @@ export default function init_sound() {
|
||||
sounds.set(id, {
|
||||
buffer: src.buffer,
|
||||
gain: context.createGain(),
|
||||
panner: new StereoPannerNode(context, {pan: 0}),
|
||||
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||
});
|
||||
},
|
||||
play_sound(id, volume, pan, loop) {
|
||||
@@ -76,12 +77,18 @@ export default function init_sound() {
|
||||
}
|
||||
src.gain.gain.value = Math.pow(2.0, volume / 1000.0);
|
||||
const relVolume = Math.pow(2.0, pan / 1000.0);
|
||||
src.panner.pan.value = 1.0 - 2.0 / (1.0 + relVolume);
|
||||
if (src.panner) {
|
||||
src.panner.pan.value = 1.0 - 2.0 / (1.0 + relVolume);
|
||||
}
|
||||
src.source = src.buffer.then(buffer => {
|
||||
const source = context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.loop = !!loop;
|
||||
source.connect(src.gain).connect(src.panner).connect(context.destination);
|
||||
let node = source.connect(src.gain);
|
||||
if (src.panner) {
|
||||
node = node.connect(src.panner);
|
||||
}
|
||||
node.connect(context.destination);
|
||||
source.start();
|
||||
return source;
|
||||
});
|
||||
|
||||
469
src/api/webrtc.js
Normal file
469
src/api/webrtc.js
Normal file
@@ -0,0 +1,469 @@
|
||||
import Peer from 'peerjs';
|
||||
|
||||
class buffer_reader {
|
||||
constructor(buffer) {
|
||||
this.buffer = (buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer));
|
||||
this.pos = 0;
|
||||
}
|
||||
done() {
|
||||
return this.pos === this.buffer.byteLength;
|
||||
}
|
||||
read8() {
|
||||
if (this.pos >= this.buffer.byteLength) {
|
||||
throw Error('packet too small');
|
||||
}
|
||||
return this.buffer[this.pos++];
|
||||
}
|
||||
read16() {
|
||||
const {pos, buffer} = this;
|
||||
if (pos + 2 > buffer.byteLength) {
|
||||
throw Error('packet too small');
|
||||
}
|
||||
const result = buffer[pos] | (buffer[pos + 1] << 8);
|
||||
this.pos += 2;
|
||||
return result;
|
||||
}
|
||||
read32() {
|
||||
const {pos, buffer} = this;
|
||||
if (pos + 4 > buffer.byteLength) {
|
||||
throw Error('packet too small');
|
||||
}
|
||||
const result = buffer[pos] | (buffer[pos + 1] << 8) | (buffer[pos + 2] << 16) | (buffer[pos + 3] << 24);
|
||||
this.pos += 4;
|
||||
return result;
|
||||
}
|
||||
read_str() {
|
||||
const length = this.read8();
|
||||
const {pos, buffer} = this;
|
||||
if (pos + length > buffer.byteLength) {
|
||||
throw Error('packet too small');
|
||||
}
|
||||
const result = String.fromCharCode(...buffer.subarray(pos, pos + length));
|
||||
this.pos += length;
|
||||
return result;
|
||||
}
|
||||
rest() {
|
||||
const result = this.buffer.subarray(this.pos);
|
||||
this.pos = this.buffer.length;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
class buffer_writer {
|
||||
constructor(length) {
|
||||
this.buffer = new Uint8Array(length);
|
||||
this.pos = 0;
|
||||
}
|
||||
get result() {
|
||||
return this.buffer.buffer;
|
||||
}
|
||||
write8(value) {
|
||||
this.buffer[this.pos++] = value;
|
||||
return this;
|
||||
}
|
||||
write16(value) {
|
||||
const {pos, buffer} = this;
|
||||
buffer[pos] = value;
|
||||
buffer[pos + 1] = value >> 8;
|
||||
this.pos += 2;
|
||||
return this;
|
||||
}
|
||||
write32(value) {
|
||||
const {pos, buffer} = this;
|
||||
buffer[pos] = value;
|
||||
buffer[pos + 1] = value >> 8;
|
||||
buffer[pos + 2] = value >> 16;
|
||||
buffer[pos + 3] = value >> 24;
|
||||
this.pos += 4;
|
||||
return this;
|
||||
}
|
||||
write_str(value) {
|
||||
const length = value.length;
|
||||
this.write8(length);
|
||||
const {pos, buffer} = this;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
buffer[pos + i] = value.charCodeAt(i);
|
||||
}
|
||||
this.pos += length;
|
||||
return this;
|
||||
}
|
||||
rest(value) {
|
||||
this.buffer.set(value, this.pos);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
const RejectionReason = {
|
||||
JOIN_SUCCESS: 0x00,
|
||||
JOIN_ALREADY_IN_GAME: 0x01,
|
||||
JOIN_GAME_NOT_FOUND: 0x02,
|
||||
JOIN_INCORRECT_PASSWORD: 0x03,
|
||||
JOIN_VERSION_MISMATCH: 0x04,
|
||||
JOIN_GAME_FULL: 0x05,
|
||||
CREATE_GAME_EXISTS: 0x06,
|
||||
};
|
||||
|
||||
const server_info_packet = {
|
||||
code: 0x32,
|
||||
read: reader => ({version: reader.read32()}),
|
||||
write: ({version}) => new buffer_writer(5).write8(server_info_packet.code).write32(version).result,
|
||||
};
|
||||
const server_game_list_packet = {
|
||||
code: 0x21,
|
||||
read: reader => {
|
||||
const count = reader.read8();
|
||||
const games = [];
|
||||
for (let i = 0; i < count; ++i) {
|
||||
games.push({type: reader.read32(), name: reader.read_str()});
|
||||
}
|
||||
return {games};
|
||||
},
|
||||
write: ({games}) => {
|
||||
const writer = new buffer_writer(games.reduce((sum, {name}) => sum + 5 + name.length, 2));
|
||||
writer.write8(server_game_list_packet.code);
|
||||
writer.write8(games.length);
|
||||
for (let {code, name} of games) {
|
||||
writer.write32(code);
|
||||
writer.write_str(name);
|
||||
}
|
||||
return writer.result;
|
||||
},
|
||||
};
|
||||
const server_join_accept_packet = {
|
||||
code: 0x12,
|
||||
read: reader => ({cookie: reader.read32(), index: reader.read8(), seed: reader.read32(), difficulty: reader.read32()}),
|
||||
write: ({cookie, index, seed, difficulty}) => new buffer_writer(14).write8(server_join_accept_packet.code).write32(cookie).write8(index).write32(seed).write32(difficulty).result,
|
||||
};
|
||||
const server_join_reject_packet = {
|
||||
code: 0x15,
|
||||
read: reader => ({cookie: reader.read32(), reason: reader.read8()}),
|
||||
write: ({cookie, reason}) => new buffer_writer(6).write8(server_join_reject_packet.code).write32(cookie).write8(reason).result,
|
||||
};
|
||||
const server_connect_packet = {
|
||||
code: 0x13,
|
||||
read: reader => ({id: reader.read8()}),
|
||||
write: ({id}) => new buffer_writer(2).write8(server_connect_packet.code).write8(id).result,
|
||||
};
|
||||
const server_disconnect_packet = {
|
||||
code: 0x14,
|
||||
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
||||
write: ({id, reason}) => new buffer_writer(6).write8(server_disconnect_packet.code).write8(id).write32(reason).result,
|
||||
};
|
||||
const server_message_packet = {
|
||||
code: 0x01,
|
||||
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
||||
write: ({id, payload}) => new buffer_writer(2 + payload.byteLength).write8(server_message_packet.code).write8(id).rest(payload).result,
|
||||
};
|
||||
const server_turn_packet = {
|
||||
code: 0x02,
|
||||
read: reader => ({id: reader.read8(), turn: reader.read32()}),
|
||||
write: ({id, turn}) => new buffer_writer(6).write8(server_turn_packet.code).write8(id).write32(turn).result,
|
||||
};
|
||||
|
||||
const client_info_packet = {
|
||||
code: 0x31,
|
||||
read: reader => ({version: reader.read32()}),
|
||||
write: ({version}) => new buffer_writer(5).write8(client_info_packet.code).write32(version).result,
|
||||
};
|
||||
const client_game_list_packet = {
|
||||
code: 0x21,
|
||||
read: () => ({}),
|
||||
write: () => new buffer_writer(1).write8(client_game_list_packet.code).result,
|
||||
};
|
||||
const client_create_game_packet = {
|
||||
code: 0x22,
|
||||
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str(), difficulty: reader.read32()}),
|
||||
write: ({cookie, name, password, difficulty}) => new buffer_writer(11 + name.length + password.length)
|
||||
.write8(client_create_game_packet.code).write32(cookie).write_str(name).write_str(password).write32(difficulty).result,
|
||||
};
|
||||
const client_join_game_packet = {
|
||||
code: 0x23,
|
||||
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str()}),
|
||||
write: ({cookie, name, password}) => new buffer_writer(7 + name.length + password.length)
|
||||
.write8(client_join_game_packet.code).write32(cookie).write_str(name).write_str(password).result,
|
||||
};
|
||||
const client_leave_game_packet = {
|
||||
code: 0x24,
|
||||
read: () => ({}),
|
||||
write: () => new buffer_writer(1).write8(client_leave_game_packet.code).result,
|
||||
};
|
||||
const client_drop_player_packet = {
|
||||
code: 0x03,
|
||||
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
||||
write: ({id, reason}) => new buffer_writer(6).write8(client_drop_player_packet.code).write8(id).write32(reason).result,
|
||||
};
|
||||
const client_message_packet = {
|
||||
code: 0x01,
|
||||
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
||||
write: ({id, payload}) => new buffer_writer(2 + payload.byteLength).write8(client_message_packet.code).write8(id).rest(payload).result,
|
||||
};
|
||||
const client_turn_packet = {
|
||||
code: 0x02,
|
||||
read: reader => ({turn: reader.read32()}),
|
||||
write: ({turn}) => new buffer_writer(5).write8(client_turn_packet.code).write32(turn).result,
|
||||
};
|
||||
|
||||
const PeerID = name => `diabloweb_${name}`;
|
||||
const MAX_PLRS = 4;
|
||||
|
||||
class webrtc_server {
|
||||
constructor(version, {cookie, name, password, difficulty}, onMessage, onClose) {
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.difficulty = difficulty;
|
||||
this.onMessage = onMessage;
|
||||
this.onClose = onClose;
|
||||
|
||||
this.peer = new Peer(PeerID(name));
|
||||
this.peer.on('connection', conn => this.onConnect(conn));
|
||||
this.players = [];
|
||||
this.myplr = 0;
|
||||
|
||||
this.seed = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
|
||||
const onError = () => {
|
||||
onMessage(server_join_reject_packet.write({cookie, reason: RejectionReason.CREATE_GAME_EXISTS}));
|
||||
onClose();
|
||||
this.peer.off('error', onError);
|
||||
this.peer.off('open', onOpen);
|
||||
};
|
||||
const onOpen = () => {
|
||||
onMessage(server_join_accept_packet.write({cookie, index: 0, seed: this.seed, difficulty}));
|
||||
onMessage(server_connect_packet.write({id: 0}));
|
||||
this.peer.off('error', onError);
|
||||
this.peer.off('open', onOpen);
|
||||
};
|
||||
this.peer.on('error', onError);
|
||||
this.peer.on('open', onOpen);
|
||||
}
|
||||
|
||||
onConnect(conn) {
|
||||
const peer = {conn};
|
||||
conn.on('data', packet => {
|
||||
const reader = new buffer_reader(packet);
|
||||
const code = reader.read8();
|
||||
let pkt;
|
||||
switch (code) {
|
||||
case client_info_packet.code:
|
||||
pkt = client_info_packet.read(reader);
|
||||
peer.version = pkt.version;
|
||||
break;
|
||||
case client_join_game_packet.code:
|
||||
pkt = client_join_game_packet.read(reader);
|
||||
if (peer.version !== this.version) {
|
||||
conn.send(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_VERSION_MISMATCH}));
|
||||
} else if (pkt.name !== this.name) {
|
||||
conn.send(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_GAME_NOT_FOUND}));
|
||||
} else if (pkt.password !== this.password) {
|
||||
conn.send(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_INCORRECT_PASSWORD}));
|
||||
} else {
|
||||
let i = 1;
|
||||
while (i < MAX_PLRS && this.players[i]) {
|
||||
++i;
|
||||
}
|
||||
if (i >= MAX_PLRS) {
|
||||
conn.send(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_GAME_FULL}));
|
||||
} else {
|
||||
this.players[i] = peer;
|
||||
peer.id = i;
|
||||
conn.send(server_join_accept_packet.write({cookie: pkt.cookie, index: i, seed: this.seed, difficulty: this.difficulty}));
|
||||
this.send(0xFF, server_connect_packet.write({id: i}));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (peer.id != null) {
|
||||
this.handle(peer.id, code, reader);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!reader.done()) {
|
||||
throw Error('packet too large');
|
||||
}
|
||||
});
|
||||
conn.on('close', () => {
|
||||
if (peer.id != null) {
|
||||
this.drop(peer.id, 0x40000006);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
send(mask, pkt) {
|
||||
for (let i = 1; i < MAX_PLRS; ++i) {
|
||||
if ((mask & (1 << i)) && this.players[i]) {
|
||||
if (this.players[i].conn) {
|
||||
this.players[i].conn.send(pkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
// self last since it will destroy the buffer
|
||||
if (mask & 1) {
|
||||
this.onMessage(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
drop(id, reason) {
|
||||
if (id === 0) {
|
||||
for (let i = 1; i < MAX_PLRS; ++i) {
|
||||
this.drop(i, 0x40000006);
|
||||
}
|
||||
this.onMessage(server_disconnect_packet.write({id, reason}));
|
||||
this.peer.destroy();
|
||||
this.onClose();
|
||||
} else if (this.players[id]) {
|
||||
this.send(0xFF, server_disconnect_packet.write({id, reason}));
|
||||
this.players[id].id = null;
|
||||
if (this.players[id].conn) {
|
||||
this.players[id].conn.close();
|
||||
}
|
||||
this.players[id] = null;
|
||||
}
|
||||
}
|
||||
|
||||
handle(id, code, reader) {
|
||||
let pkt;
|
||||
switch (code) {
|
||||
case client_leave_game_packet.code:
|
||||
pkt = client_leave_game_packet.read(reader);
|
||||
this.drop(id, 3);
|
||||
break;
|
||||
case client_drop_player_packet.code:
|
||||
pkt = client_drop_player_packet.read(reader);
|
||||
this.drop(pkt.id, pkt.reason);
|
||||
break;
|
||||
case client_message_packet.code:
|
||||
pkt = client_message_packet.read(reader);
|
||||
this.send(pkt.id === 0xFF ? ~(1 << id) : (1 << pkt.id), server_message_packet.write({id, payload: pkt.payload}));
|
||||
break;
|
||||
case client_turn_packet.code:
|
||||
pkt = client_turn_packet.read(reader);
|
||||
this.send(~(1 << id), server_turn_packet.write({id, turn: pkt.turn}));
|
||||
break;
|
||||
default:
|
||||
throw Error(`invalid packet ${code}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class webrtc_client {
|
||||
pending = [];
|
||||
|
||||
constructor(version, {cookie, name, password}, onMessage, onClose) {
|
||||
this.peer = new Peer();
|
||||
this.conn = this.peer.connect(PeerID(name));
|
||||
|
||||
const unreg = () => {
|
||||
this.peer.off('error', onError);
|
||||
this.conn.off('error', onError);
|
||||
this.conn.off('open', onOpen);
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
const onError = () => {
|
||||
onMessage(server_join_reject_packet.write({cookie, reason: RejectionReason.JOIN_GAME_NOT_FOUND}));
|
||||
onClose();
|
||||
unreg();
|
||||
};
|
||||
const onOpen = () => {
|
||||
unreg();
|
||||
this.conn.send(client_info_packet.write({version}));
|
||||
this.conn.send(client_join_game_packet.write({cookie, name, password}));
|
||||
for (let pkt of this.pending) {
|
||||
this.conn.send(pkt);
|
||||
}
|
||||
this.pending = null;
|
||||
};
|
||||
const timeout = setTimeout(onError, 5000);
|
||||
this.peer.on('error', onError);
|
||||
this.conn.on('error', onError);
|
||||
this.conn.on('open', onOpen);
|
||||
|
||||
this.conn.on('data', data => {
|
||||
const reader = new buffer_reader(data);
|
||||
const code = reader.read8();
|
||||
let pkt;
|
||||
switch (code) {
|
||||
case server_join_accept_packet.code:
|
||||
pkt = server_join_accept_packet.read(reader);
|
||||
this.myplr = pkt.index;
|
||||
break;
|
||||
case server_join_reject_packet.code:
|
||||
onClose();
|
||||
break;
|
||||
case server_disconnect_packet.code:
|
||||
pkt = server_disconnect_packet.read(reader);
|
||||
if (pkt.id === 'myplr') {
|
||||
onClose();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
onMessage(data);
|
||||
});
|
||||
this.conn.on('close', data => {
|
||||
onClose();
|
||||
});
|
||||
}
|
||||
|
||||
send(packet) {
|
||||
if (this.pending) {
|
||||
this.pending.push(packet);
|
||||
} else {
|
||||
this.conn.send(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function webrtc_open(onMessage) {
|
||||
let server = null, client = null;
|
||||
|
||||
let version = 0;
|
||||
|
||||
return {
|
||||
send: function(packet) {
|
||||
const reader = new buffer_reader(packet);
|
||||
const code = reader.read8();
|
||||
let pkt;
|
||||
switch (code) {
|
||||
case client_info_packet.code:
|
||||
pkt = client_info_packet.read(reader);
|
||||
version = pkt.version;
|
||||
break;
|
||||
case client_create_game_packet.code:
|
||||
pkt = client_create_game_packet.read(reader);
|
||||
if (server || client) {
|
||||
onMessage(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
||||
} else {
|
||||
server = new webrtc_server(version, pkt, onMessage, () => server = null);
|
||||
}
|
||||
break;
|
||||
case client_join_game_packet.code:
|
||||
pkt = client_join_game_packet.read(reader);
|
||||
if (server || client) {
|
||||
onMessage(server_join_reject_packet.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
||||
} else {
|
||||
client = new webrtc_client(version, pkt, onMessage, () => client = null);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (server) {
|
||||
server.handle(0, code, reader);
|
||||
if (pkt === client_leave_game_packet.code) {
|
||||
server = null;
|
||||
}
|
||||
} else if (client) {
|
||||
client.send(packet);
|
||||
if (pkt === client_leave_game_packet.code) {
|
||||
client = null;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
throw Error(`invalid packet ${code}`);
|
||||
}
|
||||
}
|
||||
if (!reader.done()) {
|
||||
throw Error('packet too large');
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user