今天来实现一个简单的多人联机在线对战的小游戏

index.js

const http = require("http");
const app = require("express")();
app.get("/", (req,res)=> res.sendFile(__dirname + "/index.html"))app.listen(9091, ()=>console.log("Listening on http port 9091"))
const websocketServer = require("websocket").server
const httpServer = http.createServer();
httpServer.listen(9090, () => console.log("Listening.. on 9090"))
//hashmap clients
const clients = {};
const games = {};const wsServer = new websocketServer({"httpServer": httpServer
})
wsServer.on("request", request => {//connectconst connection = request.accept(null, request.origin);connection.on("open", () => console.log("opened!"))connection.on("close", () => console.log("closed!"))connection.on("message", message => {const result = JSON.parse(message.utf8Data)//I have received a message from the client//a user want to create a new gameif (result.method === "create") {const clientId = result.clientId;const gameId = guid();games[gameId] = {"id": gameId,"balls": 20,"clients": []}const payLoad = {"method": "create","game" : games[gameId]}const con = clients[clientId].connection;con.send(JSON.stringify(payLoad));}//a client want to joinif (result.method === "join") {const clientId = result.clientId;const gameId = result.gameId;const game = games[gameId];if (game.clients.length >= 3){//sorry max players reachreturn;}const color =  {"0": "Red", "1": "Green", "2": "Blue"}[game.clients.length]game.clients.push({"clientId": clientId,"color": color})//start the gameif (game.clients.length === 3) updateGameState();const payLoad = {"method": "join","game": game}//loop through all clients and tell them that people has joinedgame.clients.forEach(c => {clients[c.clientId].connection.send(JSON.stringify(payLoad))})}//a user playsif (result.method === "play") {const gameId = result.gameId;const ballId = result.ballId;const color = result.color;let state = games[gameId].state;if (!state)state = {}state[ballId] = color;games[gameId].state = state;}})//generate a new clientIdconst clientId = guid();clients[clientId] = {"connection":  connection}const payLoad = {"method": "connect","clientId": clientId}//send back the client connectconnection.send(JSON.stringify(payLoad))})function updateGameState(){//{"gameid", fasdfsf}for (const g of Object.keys(games)) {const game = games[g]const payLoad = {"method": "update","game": game}game.clients.forEach(c=> {clients[c.clientId].connection.send(JSON.stringify(payLoad))})}setTimeout(updateGameState, 500);
}function S4() {return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}// then to call it, plus stitch in '4' in the third group
const guid = () => (S4() + S4() + "-" + S4() + "-4" + S4().substr(0,3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase();

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>
<h1>Ball Game</h1>
<button id = 'btnCreate'>New Game</button>
<button id = 'btnJoin'>Join Game</button>
<input type = 'text' id = 'txtGameId'>
<div id  = 'divPlayers'></div>
<div id  = 'divBoard'></div><script>//HTML elementslet clientId = null;let gameId = null;let playerColor = null;let ws = new WebSocket("ws://localhost:9090")const btnCreate = document.getElementById("btnCreate");const btnJoin = document.getElementById("btnJoin");const txtGameId = document.getElementById("txtGameId");const divPlayers = document.getElementById("divPlayers");const divBoard = document.getElementById("divBoard");//wiring eventsbtnJoin.addEventListener("click", e => {if (gameId === null)gameId = txtGameId.value;const payLoad = {"method": "join","clientId": clientId,"gameId": gameId}ws.send(JSON.stringify(payLoad));})btnCreate.addEventListener("click", e => {const payLoad = {"method": "create","clientId": clientId}ws.send(JSON.stringify(payLoad));})ws.onmessage = message => {//message.dataconst response = JSON.parse(message.data);//connectif (response.method === "connect"){clientId = response.clientId;console.log("Client id Set successfully " + clientId)}//createif (response.method === "create"){gameId = response.game.id;console.log("game successfully created with id " + response.game.id + " with " + response.game.balls + " balls")}//updateif (response.method === "update"){//{1: "red", 1}if (!response.game.state) return;for(const b of Object.keys(response.game.state)){const color = response.game.state[b];const ballObject = document.getElementById("ball" + b);ballObject.style.backgroundColor = color}}//joinif (response.method === "join"){const game = response.game;while(divPlayers.firstChild)divPlayers.removeChild (divPlayers.firstChild)game.clients.forEach (c => {const d = document.createElement("div");d.style.width = "200px";d.style.background = c.colord.textContent = c.clientId;divPlayers.appendChild(d);if (c.clientId === clientId) playerColor = c.color;})while(divBoard.firstChild)divBoard.removeChild (divBoard.firstChild)for (let i = 0; i < game.balls; i++){const b = document.createElement("button");b.id = "ball" + (i +1);b.tag = i+1b.textContent = i+1b.style.width = "150px"b.style.height = "150px"b.addEventListener("click", e => {b.style.background = playerColorconst payLoad = {"method": "play","clientId": clientId,"gameId": gameId,"ballId": b.tag,"color": playerColor}ws.send(JSON.stringify(payLoad))})divBoard.appendChild(b);}}}
</script>
</body>
</html>

package.json

{"name": "websocket-cell-game","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies": {"express": "^4.17.3","websocket": "^1.0.31"}
}

 package-lock.json

{"name": "websocket-cell-game","version": "1.0.0","lockfileVersion": 2,"requires": true,"packages": {"": {"name": "websocket-cell-game","version": "1.0.0","license": "ISC","dependencies": {"express": "^4.17.3","websocket": "^1.0.31"}},"node_modules/accepts": {"version": "1.3.8","resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz","integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==","dependencies": {"mime-types": "~2.1.34","negotiator": "0.6.3"},"engines": {"node": ">= 0.6"}},"node_modules/array-flatten": {"version": "1.1.1","resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz","integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="},"node_modules/body-parser": {"version": "1.19.2","resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz","integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==","dependencies": {"bytes": "3.1.2","content-type": "~1.0.4","debug": "2.6.9","depd": "~1.1.2","http-errors": "1.8.1","iconv-lite": "0.4.24","on-finished": "~2.3.0","qs": "6.9.7","raw-body": "2.4.3","type-is": "~1.6.18"},"engines": {"node": ">= 0.8"}},"node_modules/bytes": {"version": "3.1.2","resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz","integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==","engines": {"node": ">= 0.8"}},"node_modules/content-disposition": {"version": "0.5.4","resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz","integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==","dependencies": {"safe-buffer": "5.2.1"},"engines": {"node": ">= 0.6"}},"node_modules/content-type": {"version": "1.0.4","resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz","integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==","engines": {"node": ">= 0.6"}},"node_modules/cookie": {"version": "0.4.2","resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz","integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==","engines": {"node": ">= 0.6"}},"node_modules/cookie-signature": {"version": "1.0.6","resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz","integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="},"node_modules/d": {"version": "1.0.1","resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz","integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==","dependencies": {"es5-ext": "^0.10.50","type": "^1.0.1"}},"node_modules/debug": {"version": "2.6.9","resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","dependencies": {"ms": "2.0.0"}},"node_modules/depd": {"version": "1.1.2","resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz","integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=","engines": {"node": ">= 0.6"}},"node_modules/destroy": {"version": "1.0.4","resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz","integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="},"node_modules/ee-first": {"version": "1.1.1","resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz","integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="},"node_modules/encodeurl": {"version": "1.0.2","resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz","integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=","engines": {"node": ">= 0.8"}},"node_modules/es5-ext": {"version": "0.10.53","resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz","integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==","dependencies": {"es6-iterator": "~2.0.3","es6-symbol": "~3.1.3","next-tick": "~1.0.0"}},"node_modules/es6-iterator": {"version": "2.0.3","resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz","integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=","dependencies": {"d": "1","es5-ext": "^0.10.35","es6-symbol": "^3.1.1"}},"node_modules/es6-symbol": {"version": "3.1.3","resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz","integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==","dependencies": {"d": "^1.0.1","ext": "^1.1.2"}},"node_modules/escape-html": {"version": "1.0.3","resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz","integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="},"node_modules/etag": {"version": "1.8.1","resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz","integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=","engines": {"node": ">= 0.6"}},"node_modules/express": {"version": "4.17.3","resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz","integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==","dependencies": {"accepts": "~1.3.8","array-flatten": "1.1.1","body-parser": "1.19.2","content-disposition": "0.5.4","content-type": "~1.0.4","cookie": "0.4.2","cookie-signature": "1.0.6","debug": "2.6.9","depd": "~1.1.2","encodeurl": "~1.0.2","escape-html": "~1.0.3","etag": "~1.8.1","finalhandler": "~1.1.2","fresh": "0.5.2","merge-descriptors": "1.0.1","methods": "~1.1.2","on-finished": "~2.3.0","parseurl": "~1.3.3","path-to-regexp": "0.1.7","proxy-addr": "~2.0.7","qs": "6.9.7","range-parser": "~1.2.1","safe-buffer": "5.2.1","send": "0.17.2","serve-static": "1.14.2","setprototypeof": "1.2.0","statuses": "~1.5.0","type-is": "~1.6.18","utils-merge": "1.0.1","vary": "~1.1.2"},"engines": {"node": ">= 0.10.0"}},"node_modules/ext": {"version": "1.4.0","resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz","integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==","dependencies": {"type": "^2.0.0"}},"node_modules/ext/node_modules/type": {"version": "2.0.0","resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz","integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="},"node_modules/finalhandler": {"version": "1.1.2","resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz","integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==","dependencies": {"debug": "2.6.9","encodeurl": "~1.0.2","escape-html": "~1.0.3","on-finished": "~2.3.0","parseurl": "~1.3.3","statuses": "~1.5.0","unpipe": "~1.0.0"},"engines": {"node": ">= 0.8"}},"node_modules/forwarded": {"version": "0.2.0","resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz","integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==","engines": {"node": ">= 0.6"}},"node_modules/fresh": {"version": "0.5.2","resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz","integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=","engines": {"node": ">= 0.6"}},"node_modules/http-errors": {"version": "1.8.1","resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz","integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==","dependencies": {"depd": "~1.1.2","inherits": "2.0.4","setprototypeof": "1.2.0","statuses": ">= 1.5.0 < 2","toidentifier": "1.0.1"},"engines": {"node": ">= 0.6"}},"node_modules/iconv-lite": {"version": "0.4.24","resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz","integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==","dependencies": {"safer-buffer": ">= 2.1.2 < 3"},"engines": {"node": ">=0.10.0"}},"node_modules/inherits": {"version": "2.0.4","resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz","integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="},"node_modules/ipaddr.js": {"version": "1.9.1","resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz","integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==","engines": {"node": ">= 0.10"}},"node_modules/is-typedarray": {"version": "1.0.0","resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz","integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="},"node_modules/media-typer": {"version": "0.3.0","resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz","integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=","engines": {"node": ">= 0.6"}},"node_modules/merge-descriptors": {"version": "1.0.1","resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz","integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="},"node_modules/methods": {"version": "1.1.2","resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz","integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=","engines": {"node": ">= 0.6"}},"node_modules/mime": {"version": "1.6.0","resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz","integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==","bin": {"mime": "cli.js"},"engines": {"node": ">=4"}},"node_modules/mime-db": {"version": "1.51.0","resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz","integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==","engines": {"node": ">= 0.6"}},"node_modules/mime-types": {"version": "2.1.34","resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz","integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==","dependencies": {"mime-db": "1.51.0"},"engines": {"node": ">= 0.6"}},"node_modules/ms": {"version": "2.0.0","resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="},"node_modules/nan": {"version": "2.14.0","resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz","integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="},"node_modules/negotiator": {"version": "0.6.3","resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz","integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==","engines": {"node": ">= 0.6"}},"node_modules/next-tick": {"version": "1.0.0","resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz","integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="},"node_modules/on-finished": {"version": "2.3.0","resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz","integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=","dependencies": {"ee-first": "1.1.1"},"engines": {"node": ">= 0.8"}},"node_modules/parseurl": {"version": "1.3.3","resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz","integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==","engines": {"node": ">= 0.8"}},"node_modules/path-to-regexp": {"version": "0.1.7","resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz","integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="},"node_modules/proxy-addr": {"version": "2.0.7","resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz","integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==","dependencies": {"forwarded": "0.2.0","ipaddr.js": "1.9.1"},"engines": {"node": ">= 0.10"}},"node_modules/qs": {"version": "6.9.7","resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz","integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==","engines": {"node": ">=0.6"},"funding": {"url": "https://github.com/sponsors/ljharb"}},"node_modules/range-parser": {"version": "1.2.1","resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz","integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==","engines": {"node": ">= 0.6"}},"node_modules/raw-body": {"version": "2.4.3","resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz","integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==","dependencies": {"bytes": "3.1.2","http-errors": "1.8.1","iconv-lite": "0.4.24","unpipe": "1.0.0"},"engines": {"node": ">= 0.8"}},"node_modules/safe-buffer": {"version": "5.2.1","resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz","integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==","funding": [{"type": "github","url": "https://github.com/sponsors/feross"},{"type": "patreon","url": "https://www.patreon.com/feross"},{"type": "consulting","url": "https://feross.org/support"}]},"node_modules/safer-buffer": {"version": "2.1.2","resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz","integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="},"node_modules/send": {"version": "0.17.2","resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz","integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==","dependencies": {"debug": "2.6.9","depd": "~1.1.2","destroy": "~1.0.4","encodeurl": "~1.0.2","escape-html": "~1.0.3","etag": "~1.8.1","fresh": "0.5.2","http-errors": "1.8.1","mime": "1.6.0","ms": "2.1.3","on-finished": "~2.3.0","range-parser": "~1.2.1","statuses": "~1.5.0"},"engines": {"node": ">= 0.8.0"}},"node_modules/send/node_modules/ms": {"version": "2.1.3","resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz","integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="},"node_modules/serve-static": {"version": "1.14.2","resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz","integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==","dependencies": {"encodeurl": "~1.0.2","escape-html": "~1.0.3","parseurl": "~1.3.3","send": "0.17.2"},"engines": {"node": ">= 0.8.0"}},"node_modules/setprototypeof": {"version": "1.2.0","resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz","integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="},"node_modules/statuses": {"version": "1.5.0","resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz","integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=","engines": {"node": ">= 0.6"}},"node_modules/toidentifier": {"version": "1.0.1","resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz","integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==","engines": {"node": ">=0.6"}},"node_modules/type": {"version": "1.2.0","resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz","integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="},"node_modules/type-is": {"version": "1.6.18","resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz","integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==","dependencies": {"media-typer": "0.3.0","mime-types": "~2.1.24"},"engines": {"node": ">= 0.6"}},"node_modules/typedarray-to-buffer": {"version": "3.1.5","resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz","integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==","dependencies": {"is-typedarray": "^1.0.0"}},"node_modules/unpipe": {"version": "1.0.0","resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz","integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=","engines": {"node": ">= 0.8"}},"node_modules/utils-merge": {"version": "1.0.1","resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz","integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=","engines": {"node": ">= 0.4.0"}},"node_modules/vary": {"version": "1.1.2","resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz","integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=","engines": {"node": ">= 0.8"}},"node_modules/websocket": {"version": "1.0.31","resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz","integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==","hasInstallScript": true,"dependencies": {"debug": "^2.2.0","es5-ext": "^0.10.50","nan": "^2.14.0","typedarray-to-buffer": "^3.1.5","yaeti": "^0.0.6"},"engines": {"node": ">=0.10.0"}},"node_modules/yaeti": {"version": "0.0.6","resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz","integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=","engines": {"node": ">=0.10.32"}}},"dependencies": {"accepts": {"version": "1.3.8","resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz","integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==","requires": {"mime-types": "~2.1.34","negotiator": "0.6.3"}},"array-flatten": {"version": "1.1.1","resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz","integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="},"body-parser": {"version": "1.19.2","resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz","integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==","requires": {"bytes": "3.1.2","content-type": "~1.0.4","debug": "2.6.9","depd": "~1.1.2","http-errors": "1.8.1","iconv-lite": "0.4.24","on-finished": "~2.3.0","qs": "6.9.7","raw-body": "2.4.3","type-is": "~1.6.18"}},"bytes": {"version": "3.1.2","resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz","integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="},"content-disposition": {"version": "0.5.4","resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz","integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==","requires": {"safe-buffer": "5.2.1"}},"content-type": {"version": "1.0.4","resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz","integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="},"cookie": {"version": "0.4.2","resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz","integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="},"cookie-signature": {"version": "1.0.6","resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz","integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="},"d": {"version": "1.0.1","resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz","integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==","requires": {"es5-ext": "^0.10.50","type": "^1.0.1"}},"debug": {"version": "2.6.9","resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz","integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==","requires": {"ms": "2.0.0"}},"depd": {"version": "1.1.2","resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz","integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="},"destroy": {"version": "1.0.4","resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz","integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="},"ee-first": {"version": "1.1.1","resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz","integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="},"encodeurl": {"version": "1.0.2","resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz","integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="},"es5-ext": {"version": "0.10.53","resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz","integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==","requires": {"es6-iterator": "~2.0.3","es6-symbol": "~3.1.3","next-tick": "~1.0.0"}},"es6-iterator": {"version": "2.0.3","resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz","integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=","requires": {"d": "1","es5-ext": "^0.10.35","es6-symbol": "^3.1.1"}},"es6-symbol": {"version": "3.1.3","resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz","integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==","requires": {"d": "^1.0.1","ext": "^1.1.2"}},"escape-html": {"version": "1.0.3","resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz","integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="},"etag": {"version": "1.8.1","resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz","integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="},"express": {"version": "4.17.3","resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz","integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==","requires": {"accepts": "~1.3.8","array-flatten": "1.1.1","body-parser": "1.19.2","content-disposition": "0.5.4","content-type": "~1.0.4","cookie": "0.4.2","cookie-signature": "1.0.6","debug": "2.6.9","depd": "~1.1.2","encodeurl": "~1.0.2","escape-html": "~1.0.3","etag": "~1.8.1","finalhandler": "~1.1.2","fresh": "0.5.2","merge-descriptors": "1.0.1","methods": "~1.1.2","on-finished": "~2.3.0","parseurl": "~1.3.3","path-to-regexp": "0.1.7","proxy-addr": "~2.0.7","qs": "6.9.7","range-parser": "~1.2.1","safe-buffer": "5.2.1","send": "0.17.2","serve-static": "1.14.2","setprototypeof": "1.2.0","statuses": "~1.5.0","type-is": "~1.6.18","utils-merge": "1.0.1","vary": "~1.1.2"}},"ext": {"version": "1.4.0","resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz","integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==","requires": {"type": "^2.0.0"},"dependencies": {"type": {"version": "2.0.0","resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz","integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow=="}}},"finalhandler": {"version": "1.1.2","resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz","integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==","requires": {"debug": "2.6.9","encodeurl": "~1.0.2","escape-html": "~1.0.3","on-finished": "~2.3.0","parseurl": "~1.3.3","statuses": "~1.5.0","unpipe": "~1.0.0"}},"forwarded": {"version": "0.2.0","resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz","integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="},"fresh": {"version": "0.5.2","resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz","integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="},"http-errors": {"version": "1.8.1","resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz","integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==","requires": {"depd": "~1.1.2","inherits": "2.0.4","setprototypeof": "1.2.0","statuses": ">= 1.5.0 < 2","toidentifier": "1.0.1"}},"iconv-lite": {"version": "0.4.24","resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz","integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==","requires": {"safer-buffer": ">= 2.1.2 < 3"}},"inherits": {"version": "2.0.4","resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz","integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="},"ipaddr.js": {"version": "1.9.1","resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz","integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="},"is-typedarray": {"version": "1.0.0","resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz","integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="},"media-typer": {"version": "0.3.0","resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz","integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="},"merge-descriptors": {"version": "1.0.1","resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz","integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="},"methods": {"version": "1.1.2","resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz","integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="},"mime": {"version": "1.6.0","resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz","integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="},"mime-db": {"version": "1.51.0","resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz","integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="},"mime-types": {"version": "2.1.34","resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz","integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==","requires": {"mime-db": "1.51.0"}},"ms": {"version": "2.0.0","resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz","integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="},"nan": {"version": "2.14.0","resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz","integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="},"negotiator": {"version": "0.6.3","resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz","integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="},"next-tick": {"version": "1.0.0","resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz","integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="},"on-finished": {"version": "2.3.0","resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz","integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=","requires": {"ee-first": "1.1.1"}},"parseurl": {"version": "1.3.3","resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz","integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="},"path-to-regexp": {"version": "0.1.7","resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz","integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="},"proxy-addr": {"version": "2.0.7","resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz","integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==","requires": {"forwarded": "0.2.0","ipaddr.js": "1.9.1"}},"qs": {"version": "6.9.7","resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz","integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw=="},"range-parser": {"version": "1.2.1","resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz","integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="},"raw-body": {"version": "2.4.3","resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz","integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==","requires": {"bytes": "3.1.2","http-errors": "1.8.1","iconv-lite": "0.4.24","unpipe": "1.0.0"}},"safe-buffer": {"version": "5.2.1","resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz","integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="},"safer-buffer": {"version": "2.1.2","resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz","integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="},"send": {"version": "0.17.2","resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz","integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==","requires": {"debug": "2.6.9","depd": "~1.1.2","destroy": "~1.0.4","encodeurl": "~1.0.2","escape-html": "~1.0.3","etag": "~1.8.1","fresh": "0.5.2","http-errors": "1.8.1","mime": "1.6.0","ms": "2.1.3","on-finished": "~2.3.0","range-parser": "~1.2.1","statuses": "~1.5.0"},"dependencies": {"ms": {"version": "2.1.3","resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz","integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="}}},"serve-static": {"version": "1.14.2","resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz","integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==","requires": {"encodeurl": "~1.0.2","escape-html": "~1.0.3","parseurl": "~1.3.3","send": "0.17.2"}},"setprototypeof": {"version": "1.2.0","resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz","integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="},"statuses": {"version": "1.5.0","resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz","integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="},"toidentifier": {"version": "1.0.1","resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz","integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="},"type": {"version": "1.2.0","resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz","integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="},"type-is": {"version": "1.6.18","resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz","integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==","requires": {"media-typer": "0.3.0","mime-types": "~2.1.24"}},"typedarray-to-buffer": {"version": "3.1.5","resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz","integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==","requires": {"is-typedarray": "^1.0.0"}},"unpipe": {"version": "1.0.0","resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz","integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="},"utils-merge": {"version": "1.0.1","resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz","integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="},"vary": {"version": "1.1.2","resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz","integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="},"websocket": {"version": "1.0.31","resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz","integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==","requires": {"debug": "^2.2.0","es5-ext": "^0.10.50","nan": "^2.14.0","typedarray-to-buffer": "^3.1.5","yaeti": "^0.0.6"}},"yaeti": {"version": "0.0.6","resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz","integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc="}}
}

最后一步,在项目目录右击在命令行输入 node index.js

要是报错可以看下有什么express之类的需要下载

浏览器打开输入

http://localhost:9091/

f12进入无敌模式 点击console,选中框内的,也就是相当于房间号

打开另一个浏览器, 输入方便号直接开始游玩

简单的抢地盘js小游戏实战篇(多人在线对战)相关推荐

  1. html转盘游戏,使用Javascript和CSS3实现一个转盘小游戏(实战篇)

    作者:徐小夕 来源:趣谈前端 本文主要介绍如何使用原生javascript和Css3来实现一个在各大移动应用中经常出现的转盘游戏,由于该实现可以有不同方式,如果熟悉canvas的话也可以用canvas ...

  2. 【微信小游戏实战】零基础制作《欢乐停车场》三、游戏场景制作

    1.游戏立项 微信小游戏中有一款<欢乐停车场Plus>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各 ...

  3. 是男人就要坚持30秒:原生JS小游戏

    在继之前完成的数个JavaScript demo后,我发现我还没有写过JS小游戏,这次呢,我就来分享一个,非常经典的"是男人就要坚持30s"的小游戏.当然我肯定 is a man, ...

  4. 100行JS代码实现❤坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript )

    坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript ) HTML5坦克大战网页小游戏,完美还原小霸王学习机效果,以坦克战斗及保卫基地为主题,属于策略型类游戏. ...

  5. 【微信小游戏实战】零基础制作《欢乐停车场》一、游戏设计

    1.游戏立项 微信小游戏中有一款<欢乐停车场>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各颜色的小 ...

  6. js小游戏之经典炸弹人(2)--玩家的移动

    在js小游戏之经典炸弹人(1)--地图实现这篇文章中,我们已经实现了地图的绘制,接下来就来谈谈玩家是如何移动的呢? 实现玩家的移动主要依靠的是键盘事件onkeypress,我们要通过操作键盘控制玩家的 ...

  7. 祖玛弹珠js小游戏代码

    下载地址 简单的祖玛弹珠js小游戏代码,原生JavaScript带实现的祖玛游戏. dd:

  8. 用Unity3D实现简单的井字棋小游戏

    用Unity3D实现简单的井字棋小游戏 项目地址 井字棋小游戏 完成效果图 实现思路 首先定义游戏的数据部分: /* 井字棋中每一个棋格中的逻辑控制常量,代表这个棋格的状态 */ private co ...

  9. 【微信小游戏实战】零基础制作《欢乐停车场》二、关卡设计

    1.游戏立项 微信小游戏中有一款<欢乐停车场Plus>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各 ...

  10. C语言简单的键盘玩扫雷小游戏(完结)

    1:这次我们会将前面的代码进行整合,和整理,最终使我们的程序可以有效的运行起来. [1]初始化函数. void GameInit() {     //随机数种子     srand((unsigned ...

最新文章

  1. 驼峰设计 PPT设计网站
  2. 2021牛客多校2 - WeChat Walk(分块)
  3. Jmeter笔记(Ⅱ)使用Jmeter实现轻量级的接口自动化测试
  4. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 19丨最后一个能进入电梯的人【难度中等】​
  5. 【Elasticsearch】如何在 Elasticsearch 中查找并移除重复文档
  6. 企业如何选择数据分析架构?——谈谈3种架构的利弊
  7. git 本地与远程仓库出现代码冲突解决方法
  8. android蓝牙历史
  9. flowable 查询完成的流程_中注协正在调试注册会计师成绩查询系统?
  10. 优化理论07-----拟牛顿法、拟牛顿方程、对称秩二更新公式、BFGS、DFS、Broyden族、Huang’s Family
  11. java 中的通讯之HTTP协议
  12. go模块的使用,调用第三方模块方法---go模块的复用方法
  13. Android keeps stopping
  14. 06-SparkSQL
  15. 《STL源码剖析》RB-tree中increment 和 decrement 的作用
  16. kubernetes dashboard
  17. 何水无鱼?何山无石?何人无父?何女无夫?何树无枝?何城无市?
  18. 计算机的组成及其功能
  19. 北京理工大学 计算机学院 书院,书院交流 | 北京理工大学睿信书院来我院调研交流...
  20. 电子商务中的大数据分析——数据平台和人工智能

热门文章

  1. 请使用hive udf或者spark udf实现父子关系树图分析,列举出所有的路径
  2. MonoGRNet: A Geometric Reasoning Network for Monocular 3D Object Localization
  3. Discriminative Reasoning for Document-level Relation Extraction
  4. QFile读取移动硬盘文件卡死问题
  5. 深入理解LCD之寄存器配置
  6. 2104.10729阅读笔记
  7. linux字体不识别不了怎么办,Docker容器不识别宋体等字体的解决方案
  8. meta标签http-equiv属性的作用
  9. 信息技术与计算机课程标准,再谈新课程标准下的信息技术教学
  10. Android系统开发——WiFi Hotspot限速2M每秒