mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-07-03 11:51:35 +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",
|
"name": "diabloweb",
|
||||||
"version": "1.0.25",
|
"version": "1.0.27",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1386,6 +1386,11 @@
|
|||||||
"@types/istanbul-lib-report": "*"
|
"@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": {
|
"@types/q": {
|
||||||
"version": "1.5.2",
|
"version": "1.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
|
"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": {
|
"@types/yargs": {
|
||||||
"version": "12.0.12",
|
"version": "12.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz",
|
"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",
|
"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=="
|
"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": {
|
"babel-preset-jest": {
|
||||||
"version": "24.6.0",
|
"version": "24.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
"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": {
|
"end-of-stream": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||||
@@ -7333,6 +7373,11 @@
|
|||||||
"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
|
"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
|
||||||
"dev": true
|
"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": {
|
"js-levenshtein": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
||||||
@@ -8226,6 +8271,15 @@
|
|||||||
"lower-case": "^1.1.1"
|
"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": {
|
"node-forge": {
|
||||||
"version": "0.7.5",
|
"version": "0.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
|
||||||
@@ -8653,6 +8707,110 @@
|
|||||||
"mimic-fn": "^1.0.0"
|
"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": {
|
"opn": {
|
||||||
"version": "5.4.0",
|
"version": "5.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
|
||||||
@@ -8937,6 +9095,21 @@
|
|||||||
"sha.js": "^2.4.8"
|
"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": {
|
"performance-now": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||||
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
|
"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": {
|
"remove-trailing-separator": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||||
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
|
"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": {
|
"run-async": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
|
||||||
@@ -10679,6 +10867,11 @@
|
|||||||
"aproba": "^1.1.1"
|
"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": {
|
"rxjs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz",
|
"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": {
|
"select-hose": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
"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": {
|
"websocket-driver": {
|
||||||
"version": "0.7.3",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "diabloweb",
|
"name": "diabloweb",
|
||||||
"version": "1.0.25",
|
"version": "1.0.27",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.4.3",
|
"@babel/core": "7.4.3",
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
"jest-watch-typeahead": "0.3.0",
|
"jest-watch-typeahead": "0.3.0",
|
||||||
"mini-css-extract-plugin": "0.5.0",
|
"mini-css-extract-plugin": "0.5.0",
|
||||||
"optimize-css-assets-webpack-plugin": "5.0.1",
|
"optimize-css-assets-webpack-plugin": "5.0.1",
|
||||||
|
"peerjs": "^1.0.2",
|
||||||
"pnp-webpack-plugin": "1.2.1",
|
"pnp-webpack-plugin": "1.2.1",
|
||||||
"postcss-flexbugs-fixes": "4.1.0",
|
"postcss-flexbugs-fixes": "4.1.0",
|
||||||
"postcss-loader": "3.0.0",
|
"postcss-loader": "3.0.0",
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import create_fs from './fs';
|
|||||||
import load_game from './api/loader';
|
import load_game from './api/loader';
|
||||||
import { SpawnSizes } from './api/load_spawn';
|
import { SpawnSizes } from './api/load_spawn';
|
||||||
|
|
||||||
|
import Peer from 'peerjs';
|
||||||
|
|
||||||
|
window.Peer = Peer;
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
ReactGA.initialize('UA-43123589-6');
|
ReactGA.initialize('UA-43123589-6');
|
||||||
ReactGA.pageview('/');
|
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 SpawnBinary from './DiabloSpawn.wasm';
|
||||||
import SpawnModule from './DiabloSpawn.jscc';
|
import SpawnModule from './DiabloSpawn.jscc';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import websocket_open from './websocket';
|
|
||||||
|
|
||||||
const DiabloSize = 1316452;
|
const DiabloSize = 1316452;
|
||||||
const SpawnSize = 1196648;
|
const SpawnSize = 1196648;
|
||||||
@@ -17,7 +16,6 @@ let files = null;
|
|||||||
let renderBatch = null;
|
let renderBatch = null;
|
||||||
let drawBelt = null;
|
let drawBelt = null;
|
||||||
let is_spawn = false;
|
let is_spawn = false;
|
||||||
let websocket = null;
|
|
||||||
|
|
||||||
const ChunkSize = 1 << 20;
|
const ChunkSize = 1 << 20;
|
||||||
class RemoteFile {
|
class RemoteFile {
|
||||||
@@ -118,13 +116,8 @@ const DApi = {
|
|||||||
worker.postMessage({action: "keyboard", rect: null});
|
worker.postMessage({action: "keyboard", rect: null});
|
||||||
},
|
},
|
||||||
|
|
||||||
websocket_send(data) {
|
|
||||||
if (websocket) {
|
|
||||||
websocket.send(data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
websocket_closed() {
|
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;
|
worker.DApi = DApi;
|
||||||
|
|
||||||
let wasm = null;
|
let wasm = null;
|
||||||
|
|
||||||
function call_api(func, ...params) {
|
function try_api(func) {
|
||||||
try {
|
try {
|
||||||
audioBatch = [];
|
func();
|
||||||
audioTransfer = [];
|
|
||||||
wasm["_" + func](...params);
|
|
||||||
if (audioBatch.length) {
|
|
||||||
maxSoundId = maxBatchId;
|
|
||||||
worker.postMessage({action: "audioBatch", batch: audioBatch}, audioTransfer);
|
|
||||||
audioBatch = null;
|
|
||||||
audioTransfer = null;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof e === "string") {
|
if (typeof e === "string") {
|
||||||
worker.postMessage({action: ""})
|
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) {
|
function progress(text, loaded, total) {
|
||||||
worker.postMessage({action: "progress", text, loaded, total});
|
worker.postMessage({action: "progress", text, loaded, total});
|
||||||
}
|
}
|
||||||
@@ -293,7 +306,7 @@ async function initWasm(spawn, progress) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function init_game(mpq, spawn, offscreen, serverUrl) {
|
async function init_game(mpq, spawn, offscreen) {
|
||||||
is_spawn = spawn;
|
is_spawn = spawn;
|
||||||
if (offscreen) {
|
if (offscreen) {
|
||||||
canvas = new OffscreenCanvas(640, 480);
|
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...");
|
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;
|
||||||
@@ -346,9 +349,7 @@ async function init_game(mpq, spawn, offscreen, serverUrl) {
|
|||||||
|
|
||||||
const vers = process.env.VERSION.match(/(\d+)\.(\d+)\.(\d+)/);
|
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]));
|
wasm._DApi_Init(Math.floor(performance.now()), offscreen ? 1 : 0, parseInt(vers[1]), parseInt(vers[2]), parseInt(vers[3]));
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@@ -360,13 +361,27 @@ worker.addEventListener("message", ({data}) => {
|
|||||||
switch (data.action) {
|
switch (data.action) {
|
||||||
case "init":
|
case "init":
|
||||||
files = data.files;
|
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"}),
|
() => worker.postMessage({action: "loaded"}),
|
||||||
e => worker.postMessage({action: "failed", error: e.toString(), stack: e.stack}));
|
e => worker.postMessage({action: "failed", error: e.toString(), stack: e.stack}));
|
||||||
break;
|
break;
|
||||||
case "event":
|
case "event":
|
||||||
call_api(data.func, ...data.params);
|
call_api(data.func, ...data.params);
|
||||||
break;
|
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:
|
default:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Worker from './game.worker.js';
|
import Worker from './game.worker.js';
|
||||||
import init_sound from './sound';
|
import init_sound from './sound';
|
||||||
import load_spawn from './load_spawn';
|
import load_spawn from './load_spawn';
|
||||||
|
import webrtc_open from './webrtc';
|
||||||
|
|
||||||
function onRender(api, ctx, {bitmap, images, text, clip, belt}) {
|
function onRender(api, ctx, {bitmap, images, text, clip, belt}) {
|
||||||
if (bitmap) {
|
if (bitmap) {
|
||||||
@@ -65,6 +66,12 @@ async function do_load_game(api, audio, mpq, spawn) {
|
|||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const worker = new Worker();
|
const worker = new Worker();
|
||||||
|
|
||||||
|
let packetQueue = [];
|
||||||
|
const webrtc = webrtc_open(data => {
|
||||||
|
packetQueue.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
worker.addEventListener("message", ({data}) => {
|
worker.addEventListener("message", ({data}) => {
|
||||||
switch (data.action) {
|
switch (data.action) {
|
||||||
case "loaded":
|
case "loaded":
|
||||||
@@ -106,14 +113,28 @@ async function do_load_game(api, audio, mpq, spawn) {
|
|||||||
case "current_save":
|
case "current_save":
|
||||||
api.setCurrentSave(data.name);
|
api.setCurrentSave(data.name);
|
||||||
break;
|
break;
|
||||||
|
case "packet":
|
||||||
|
webrtc.send(data.buffer);
|
||||||
|
break;
|
||||||
|
case "packetBatch":
|
||||||
|
for (let packet of data.batch) {
|
||||||
|
webrtc.send(packet);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const transfer= [];
|
const transfer= [];
|
||||||
for (let [, file] of fs.files) {
|
for (let [, file] of fs.files) {
|
||||||
transfer.push(file.buffer);
|
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;
|
delete fs.files;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ function decodeAudioData(context, buffer) {
|
|||||||
|
|
||||||
export default function init_sound() {
|
export default function init_sound() {
|
||||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
const StereoPannerNode = window.StereoPannerNode || window.webkitAudioPannerNode;
|
||||||
if (!AudioContext) {
|
if (!AudioContext) {
|
||||||
return no_sound();
|
return no_sound();
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ export default function init_sound() {
|
|||||||
sounds.set(id, {
|
sounds.set(id, {
|
||||||
buffer: Promise.resolve(buffer),
|
buffer: Promise.resolve(buffer),
|
||||||
gain: context.createGain(),
|
gain: context.createGain(),
|
||||||
panner: new StereoPannerNode(context, {pan: 0}),
|
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
create_sound(id, data) {
|
create_sound(id, data) {
|
||||||
@@ -51,7 +52,7 @@ export default function init_sound() {
|
|||||||
sounds.set(id, {
|
sounds.set(id, {
|
||||||
buffer,
|
buffer,
|
||||||
gain: context.createGain(),
|
gain: context.createGain(),
|
||||||
panner: new StereoPannerNode(context, {pan: 0}),
|
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
duplicate_sound(id, srcId) {
|
duplicate_sound(id, srcId) {
|
||||||
@@ -65,7 +66,7 @@ export default function init_sound() {
|
|||||||
sounds.set(id, {
|
sounds.set(id, {
|
||||||
buffer: src.buffer,
|
buffer: src.buffer,
|
||||||
gain: context.createGain(),
|
gain: context.createGain(),
|
||||||
panner: new StereoPannerNode(context, {pan: 0}),
|
panner: StereoPannerNode && new StereoPannerNode(context, {pan: 0}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
play_sound(id, volume, pan, loop) {
|
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);
|
src.gain.gain.value = Math.pow(2.0, volume / 1000.0);
|
||||||
const relVolume = Math.pow(2.0, pan / 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 => {
|
src.source = src.buffer.then(buffer => {
|
||||||
const source = context.createBufferSource();
|
const source = context.createBufferSource();
|
||||||
source.buffer = buffer;
|
source.buffer = buffer;
|
||||||
source.loop = !!loop;
|
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();
|
source.start();
|
||||||
return source;
|
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