Basic multiplayer stuff
This commit is contained in:
parent
e754b01dca
commit
5d2b8ecef9
10 changed files with 876 additions and 185 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "alkatest-common"]
|
||||
path = src/alkatest-common
|
||||
url = https://github.com/thepaperpilot/alkatest-common
|
371
package-lock.json
generated
371
package-lock.json
generated
|
@ -19,6 +19,9 @@
|
|||
"is-plain-object": "^5.0.0",
|
||||
"lz-string": "^1.4.4",
|
||||
"nanoevents": "^6.0.2",
|
||||
"semver": "^7.3.7",
|
||||
"socket.io-client": "^4.5.2",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"vite": "^2.9.12",
|
||||
"vite-plugin-pwa": "^0.12.0",
|
||||
"vite-tsconfig-paths": "^3.5.0",
|
||||
|
@ -34,6 +37,7 @@
|
|||
"@ivanv/vue-collapse-transition": "^1.0.2",
|
||||
"@rushstack/eslint-patch": "^1.1.0",
|
||||
"@types/lz-string": "^1.3.34",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"eslint": "^8.6.0",
|
||||
|
@ -107,6 +111,14 @@
|
|||
"url": "https://opencollective.com/babel"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.18.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz",
|
||||
|
@ -173,6 +185,14 @@
|
|||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz",
|
||||
|
@ -224,6 +244,14 @@
|
|||
"@babel/core": "^7.4.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
|
||||
|
@ -1525,6 +1553,14 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-modules": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
|
||||
|
@ -2058,6 +2094,11 @@
|
|||
"integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
},
|
||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
|
@ -2134,6 +2175,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz",
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
||||
|
@ -2172,21 +2219,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.1.tgz",
|
||||
|
@ -2297,21 +2329,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.33.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.1.tgz",
|
||||
|
@ -2754,6 +2771,14 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs3": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz",
|
||||
|
@ -3240,6 +3265,46 @@
|
|||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.225.tgz",
|
||||
"integrity": "sha512-ICHvGaCIQR3P88uK8aRtx8gmejbVJyC6bB4LEC3anzBrIzdzC7aiZHY4iFfXhN4st6I7lMO0x4sgBHf/7kBvRw=="
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
|
||||
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/node_modules/ws": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
|
||||
|
@ -3847,22 +3912,6 @@
|
|||
"eslint": "^6.2.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
|
@ -5261,7 +5310,6 @@
|
|||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
|
@ -5967,11 +6015,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
|
@ -6024,6 +6078,32 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.2.tgz",
|
||||
"integrity": "sha512-naqYfFu7CLDiQ1B7AlLhRXKX3gdeaIMfgigwavDzgJoIUYulc1qHH5+2XflTsXTPY7BlPH5rppJyUjhjrKQKLg==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.2.1",
|
||||
"socket.io-parser": "~4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz",
|
||||
"integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sortablejs": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||
|
@ -6428,6 +6508,14 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/unique-names-generator": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/unique-names-generator/-/unique-names-generator-4.7.1.tgz",
|
||||
"integrity": "sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/unique-string": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
|
||||
|
@ -6698,21 +6786,6 @@
|
|||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-eslint-parser/node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-next-select": {
|
||||
"version": "2.10.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-next-select/-/vue-next-select-2.10.4.tgz",
|
||||
|
@ -7211,11 +7284,18 @@
|
|||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
|
@ -7273,6 +7353,13 @@
|
|||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.1",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
|
@ -7323,6 +7410,13 @@
|
|||
"@babel/helper-validator-option": "^7.18.6",
|
||||
"browserslist": "^4.20.2",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-create-class-features-plugin": {
|
||||
|
@ -7359,6 +7453,13 @@
|
|||
"lodash.debounce": "^4.0.8",
|
||||
"resolve": "^1.14.2",
|
||||
"semver": "^6.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-environment-visitor": {
|
||||
|
@ -8213,6 +8314,13 @@
|
|||
"babel-plugin-polyfill-regenerator": "^0.4.0",
|
||||
"core-js-compat": "^3.22.1",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/preset-modules": {
|
||||
|
@ -8609,6 +8717,11 @@
|
|||
"integrity": "sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==",
|
||||
"dev": true
|
||||
},
|
||||
"@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
},
|
||||
"@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
|
@ -8682,6 +8795,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz",
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/trusted-types": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
||||
|
@ -8702,17 +8821,6 @@
|
|||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
|
@ -8767,17 +8875,6 @@
|
|||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
|
@ -9140,6 +9237,13 @@
|
|||
"@babel/compat-data": "^7.17.7",
|
||||
"@babel/helper-define-polyfill-provider": "^0.3.2",
|
||||
"semver": "^6.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-polyfill-corejs3": {
|
||||
|
@ -9499,6 +9603,31 @@
|
|||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.225.tgz",
|
||||
"integrity": "sha512-ICHvGaCIQR3P88uK8aRtx8gmejbVJyC6bB4LEC3anzBrIzdzC7aiZHY4iFfXhN4st6I7lMO0x4sgBHf/7kBvRw=="
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
|
||||
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
|
||||
},
|
||||
"entities": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz",
|
||||
|
@ -9927,18 +10056,6 @@
|
|||
"postcss-selector-parser": "^6.0.9",
|
||||
"semver": "^7.3.5",
|
||||
"vue-eslint-parser": "^8.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
|
@ -10866,7 +10983,6 @@
|
|||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
|
@ -11357,9 +11473,12 @@
|
|||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "4.0.0",
|
||||
|
@ -11399,6 +11518,26 @@
|
|||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.2.tgz",
|
||||
"integrity": "sha512-naqYfFu7CLDiQ1B7AlLhRXKX3gdeaIMfgigwavDzgJoIUYulc1qHH5+2XflTsXTPY7BlPH5rppJyUjhjrKQKLg==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.2.1",
|
||||
"socket.io-parser": "~4.2.0"
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz",
|
||||
"integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||
|
@ -11685,6 +11824,11 @@
|
|||
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz",
|
||||
"integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ=="
|
||||
},
|
||||
"unique-names-generator": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/unique-names-generator/-/unique-names-generator-4.7.1.tgz",
|
||||
"integrity": "sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow=="
|
||||
},
|
||||
"unique-string": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
|
||||
|
@ -11847,15 +11991,6 @@
|
|||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -12279,11 +12414,15 @@
|
|||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"dev": true
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
"is-plain-object": "^5.0.0",
|
||||
"lz-string": "^1.4.4",
|
||||
"nanoevents": "^6.0.2",
|
||||
"semver": "^7.3.7",
|
||||
"socket.io-client": "^4.5.2",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"vite": "^2.9.12",
|
||||
"vite-plugin-pwa": "^0.12.0",
|
||||
"vite-tsconfig-paths": "^3.5.0",
|
||||
|
@ -38,6 +41,7 @@
|
|||
"@ivanv/vue-collapse-transition": "^1.0.2",
|
||||
"@rushstack/eslint-patch": "^1.1.0",
|
||||
"@types/lz-string": "^1.3.34",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"eslint": "^8.6.0",
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
<span class="material-icons">library_books</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div @click="roomsDialog?.open()">
|
||||
<Tooltip display="Multiplayer" :direction="Direction.Down" xoffset="-20px">
|
||||
<span class="material-icons">group</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div @click="options?.open()">
|
||||
<Tooltip display="Options" :direction="Direction.Down" xoffset="-66px">
|
||||
<span class="material-icons">settings</span>
|
||||
|
@ -58,6 +63,11 @@
|
|||
<span class="material-icons">library_books</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div @click="roomsDialog?.open()">
|
||||
<Tooltip display="Multiplayer" :direction="Direction.Right">
|
||||
<span class="material-icons">group</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div @click="options?.open()">
|
||||
<Tooltip display="Options" :direction="Direction.Right">
|
||||
<span class="material-icons">settings</span>
|
||||
|
@ -96,12 +106,15 @@
|
|||
<SavesManager ref="savesManager" />
|
||||
<Options ref="options" />
|
||||
<Changelog ref="changelog" />
|
||||
<RoomsDialog ref="roomsDialog" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Changelog from "data/Changelog.vue";
|
||||
import projInfo from "data/projInfo.json";
|
||||
import RoomsDialog from "data/RoomsDialog.vue";
|
||||
import Tooltip from "features/tooltips/Tooltip.vue";
|
||||
import { globalBus } from "game/events";
|
||||
import { Direction } from "util/common";
|
||||
import type { ComponentPublicInstance } from "vue";
|
||||
import { ref } from "vue";
|
||||
|
@ -115,6 +128,9 @@ const options = ref<ComponentPublicInstance<typeof Options> | null>(null);
|
|||
// For some reason Info won't accept the changelog unless I do this:
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const changelog = ref<ComponentPublicInstance<any> | null>(null);
|
||||
const roomsDialog = ref<ComponentPublicInstance<typeof RoomsDialog> | null>(null);
|
||||
|
||||
globalBus.on("openMultiplayer", () => roomsDialog.value?.open());
|
||||
|
||||
const { useHeader, banner, title, discordName, discordLink, versionNumber } = projInfo;
|
||||
|
||||
|
@ -205,8 +221,8 @@ function openDiscord() {
|
|||
position: fixed;
|
||||
top: 45px;
|
||||
padding: 20px;
|
||||
right: -280px;
|
||||
width: 200px;
|
||||
right: -340px;
|
||||
width: 300px;
|
||||
transition: right 0.25s ease;
|
||||
background: var(--raised-background);
|
||||
z-index: 10;
|
||||
|
|
154
src/data/Room.vue
Normal file
154
src/data/Room.vue
Normal file
|
@ -0,0 +1,154 @@
|
|||
<template>
|
||||
<div class="room">
|
||||
<div class="actions" v-if="enteringPassword">
|
||||
<button @pointerdown="submitPassword" class="button">
|
||||
<Tooltip display="Join" :direction="Direction.Left" class="info">
|
||||
<span class="material-icons">check</span>
|
||||
</Tooltip>
|
||||
</button>
|
||||
<button @pointerdown="enteringPassword = !enteringPassword" class="button">
|
||||
<Tooltip display="Cancel" :direction="Direction.Left" class="info">
|
||||
<span class="material-icons">close</span>
|
||||
</Tooltip>
|
||||
</button>
|
||||
</div>
|
||||
<div class="details" v-if="!enteringPassword">
|
||||
<span class="material-icons" v-if="room.hasPassword">lock</span>
|
||||
<span class="material-icons" v-if="isPrivate">visibility_off</span>
|
||||
<button class="button open" @click="startConnecting">
|
||||
<h3>{{ room.name }}</h3>
|
||||
</button>
|
||||
<span class="room-host">Hosted by {{ room.host }}</span
|
||||
><br />
|
||||
<div>{{ room.numContentPacks }} active content packs</div>
|
||||
</div>
|
||||
<div v-else class="details" style="display: flex">
|
||||
<span>Password:</span>
|
||||
<Text
|
||||
v-model="password"
|
||||
class="editname"
|
||||
@submit="submitPassword"
|
||||
@cancel="enteringPassword = !enteringPassword"
|
||||
:submitOnBlur="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, toRefs, watch } from "vue";
|
||||
import Text from "components/fields/Text.vue";
|
||||
import { Direction } from "util/common";
|
||||
import Tooltip from "features/tooltips/Tooltip.vue";
|
||||
|
||||
const _props = defineProps<{
|
||||
isPrivate: boolean;
|
||||
room: ClientRoomData;
|
||||
}>();
|
||||
const { room } = toRefs(_props);
|
||||
const emit = defineEmits<{
|
||||
(e: "connect", password?: string): void;
|
||||
}>();
|
||||
|
||||
const enteringPassword = ref(false);
|
||||
const password = ref("");
|
||||
|
||||
watch(enteringPassword, enteringPassword => {
|
||||
if (enteringPassword) {
|
||||
password.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
function startConnecting() {
|
||||
if (room.value.hasPassword) {
|
||||
enteringPassword.value = true;
|
||||
} else {
|
||||
emit("connect");
|
||||
}
|
||||
}
|
||||
|
||||
function submitPassword() {
|
||||
emit("connect", password.value);
|
||||
enteringPassword.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.room {
|
||||
position: relative;
|
||||
border: solid 4px var(--outline);
|
||||
padding: 4px;
|
||||
background: var(--raised-background);
|
||||
margin: var(--feature-margin);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.room.active {
|
||||
border-color: var(--bought);
|
||||
}
|
||||
|
||||
.open {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
margin-right: 80px;
|
||||
}
|
||||
|
||||
.details .material-icons {
|
||||
font-size: 20px;
|
||||
margin-right: 4px;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.room-host {
|
||||
margin-left: 4px;
|
||||
font-size: 0.7em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 4px;
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.editname {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.room button {
|
||||
transition-duration: 0s;
|
||||
}
|
||||
|
||||
.room .actions button {
|
||||
display: flex;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.room .actions button .material-icons {
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
.room .button.danger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.room .field {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
234
src/data/RoomsDialog.vue
Normal file
234
src/data/RoomsDialog.vue
Normal file
|
@ -0,0 +1,234 @@
|
|||
<template>
|
||||
<Modal v-model="isOpen" ref="modal">
|
||||
<template v-slot:header>
|
||||
<h2>Multiplayer</h2>
|
||||
</template>
|
||||
<template #body="{ shown }">
|
||||
<template v-if="shown">
|
||||
<template v-if="connected">
|
||||
<template v-if="currentRoom">
|
||||
<div style="text-align: center">
|
||||
<h3>Connected to {{ currentRoom }}</h3>
|
||||
</div>
|
||||
<br />
|
||||
<h4>Connected Players</h4>
|
||||
<ul class="players-list">
|
||||
<div v-for="(nickname, i) in nicknames" :key="i" style="display: flex">
|
||||
<span>{{ nickname }}</span>
|
||||
<span
|
||||
v-if="nickname === settings.nickname"
|
||||
style="font-size: small; color: grey; margin-left: 10px"
|
||||
>(YOU)</span
|
||||
>
|
||||
<div style="flex-grow: 1"></div>
|
||||
<button
|
||||
v-if="isHosting && nickname !== settings.nickname"
|
||||
class="button"
|
||||
style="color: red; display: inline"
|
||||
@click="emitToServer('kick user', nickname)"
|
||||
>
|
||||
KICK
|
||||
</button>
|
||||
</div>
|
||||
</ul>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Room
|
||||
v-for="(room, i) in rooms ?? []"
|
||||
:key="i"
|
||||
:room="room"
|
||||
:isPrivate="false"
|
||||
@connect="password => join(room.name, password)"
|
||||
/>
|
||||
<div v-if="rooms != null && rooms.length === 0" style="text-align: center">
|
||||
No public rooms found
|
||||
</div>
|
||||
<div v-if="rooms == null" style="text-align: center">
|
||||
Loading public rooms list...
|
||||
</div>
|
||||
<br />
|
||||
<button
|
||||
class="button"
|
||||
style="float: right; display: inline-block"
|
||||
@click="refresh()"
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
<div v-else>
|
||||
Not connected to a server. Please set up networking in the options modal.
|
||||
<br />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-slot:footer>
|
||||
<div class="modal-footer">
|
||||
<div v-if="connected && !currentRoom">
|
||||
<br />
|
||||
<hr />
|
||||
<div style="margin-top: 10px; margin-bottom: -10px">Direct Connect</div>
|
||||
<div class="direct-connect field">
|
||||
<Text v-model="directRoomName" placeholder="Room Name" />
|
||||
<Text v-model="directRoomPassword" placeholder="Room Password" />
|
||||
<div class="field-buttons">
|
||||
<button
|
||||
class="button"
|
||||
@click="join(directRoomName, directRoomPassword)"
|
||||
>
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 10px; margin-bottom: -10px">Host current world</div>
|
||||
<div class="direct-connect field">
|
||||
<Text v-model="hostRoomName" placeholder="Room Name" />
|
||||
<Text v-model="hostRoomPassword" placeholder="Room Password" />
|
||||
<Toggle
|
||||
v-model="hostPrivate"
|
||||
title="Private"
|
||||
style="width: 320px; margin-right: 10px"
|
||||
/>
|
||||
<div class="field-buttons">
|
||||
<button
|
||||
class="button"
|
||||
@click="host(hostRoomName, hostRoomPassword, hostPrivate)"
|
||||
>
|
||||
Host
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div style="flex-grow: 1"></div>
|
||||
<button
|
||||
v-if="currentRoom"
|
||||
class="button modal-default-button"
|
||||
@click="emitToServer('leave room')"
|
||||
>
|
||||
Leave room
|
||||
</button>
|
||||
<button class="button modal-default-button" @click="isOpen = false">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Text from "components/fields/Text.vue";
|
||||
import Toggle from "components/fields/Toggle.vue";
|
||||
import Modal from "components/Modal.vue";
|
||||
import {
|
||||
connected,
|
||||
emit as emitToServer,
|
||||
getGameState,
|
||||
isHosting,
|
||||
nicknames,
|
||||
room as currentRoom
|
||||
} from "data/socket";
|
||||
import { globalBus } from "game/events";
|
||||
import { PlayerData } from "game/player";
|
||||
import settings from "game/settings";
|
||||
import type { ComponentPublicInstance } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { main } from "./projEntry";
|
||||
import Room from "./Room.vue";
|
||||
|
||||
export type LoadablePlayerData = Omit<Partial<PlayerData>, "id"> & { id: string; error?: unknown };
|
||||
|
||||
const isOpen = ref(false);
|
||||
const modal = ref<ComponentPublicInstance<typeof Modal> | null>(null);
|
||||
|
||||
defineExpose({
|
||||
open() {
|
||||
isOpen.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
const rooms = ref<ClientRoomData[] | null>(null);
|
||||
const directRoomName = ref("");
|
||||
const directRoomPassword = ref("");
|
||||
const hostRoomName = ref("");
|
||||
const hostRoomPassword = ref("");
|
||||
const hostPrivate = ref<boolean>(false);
|
||||
|
||||
watch(isOpen, isOpen => {
|
||||
if (isOpen) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
watch(currentRoom, room => {
|
||||
if (!room) {
|
||||
directRoomName.value = "";
|
||||
directRoomPassword.value = "";
|
||||
hostRoomName.value = "";
|
||||
hostRoomPassword.value = "";
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
globalBus.on("setRooms", r => (rooms.value = r));
|
||||
globalBus.on("serverSentInfo", () => {
|
||||
if (isOpen.value) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
function refresh() {
|
||||
rooms.value = null;
|
||||
emitToServer("get rooms");
|
||||
}
|
||||
|
||||
function join(room: string, password?: string) {
|
||||
emitToServer("connect to room", room, password, settings.nickname);
|
||||
}
|
||||
|
||||
function host(room: string, password?: string, privateRoom?: boolean) {
|
||||
emitToServer("create room", {
|
||||
name: room,
|
||||
password,
|
||||
nickname: settings.nickname,
|
||||
contentPacks: main.contentPacks.value,
|
||||
privateRoom: privateRoom === true,
|
||||
state: getGameState()
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field form,
|
||||
.field .field-title,
|
||||
.field .field-buttons {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.field-buttons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.field-buttons .field {
|
||||
margin: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.field-title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.direct-connect :deep(input[type="text"]) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
|
@ -1,75 +1,25 @@
|
|||
import Spacer from "components/layout/Spacer.vue";
|
||||
import { jsx } from "features/feature";
|
||||
import { createResource, trackBest, trackOOMPS, trackTotal } from "features/resources/resource";
|
||||
import type { GenericTree } from "features/trees/tree";
|
||||
import { branchedResetPropagation, createTree } from "features/trees/tree";
|
||||
import { globalBus } from "game/events";
|
||||
import type { BaseLayer, GenericLayer } from "game/layers";
|
||||
import { createLayer } from "game/layers";
|
||||
import { persistent } from "game/persistence";
|
||||
import type { PlayerData } from "game/player";
|
||||
import player from "game/player";
|
||||
import type { DecimalSource } from "util/bignum";
|
||||
import Decimal, { format, formatTime } from "util/bignum";
|
||||
import { render } from "util/vue";
|
||||
import { computed, toRaw } from "vue";
|
||||
import prestige from "./layers/prestige";
|
||||
import { computed } from "vue";
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export const main = createLayer("main", function (this: BaseLayer) {
|
||||
const points = createResource<DecimalSource>(10);
|
||||
const best = trackBest(points);
|
||||
const total = trackTotal(points);
|
||||
|
||||
const pointGain = computed(() => {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let gain = new Decimal(1);
|
||||
return gain;
|
||||
});
|
||||
globalBus.on("update", diff => {
|
||||
points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff));
|
||||
});
|
||||
const oomps = trackOOMPS(points, pointGain);
|
||||
|
||||
const tree = createTree(() => ({
|
||||
nodes: [[prestige.treeNode]],
|
||||
branches: [],
|
||||
onReset() {
|
||||
points.value = toRaw(this.resettingNode.value) === toRaw(prestige.treeNode) ? 0 : 10;
|
||||
best.value = points.value;
|
||||
total.value = points.value;
|
||||
},
|
||||
resetPropagation: branchedResetPropagation
|
||||
})) as GenericTree;
|
||||
const contentPacks = persistent<(ContentPack | string)[]>(["core"]);
|
||||
|
||||
return {
|
||||
name: "Tree",
|
||||
links: tree.links,
|
||||
name: "Main",
|
||||
minimizable: false,
|
||||
contentPacks,
|
||||
display: jsx(() => (
|
||||
<>
|
||||
{player.devSpeed === 0 ? <div>Game Paused</div> : null}
|
||||
{player.devSpeed && player.devSpeed !== 1 ? (
|
||||
<div>Dev Speed: {format(player.devSpeed)}x</div>
|
||||
) : null}
|
||||
{player.offlineTime ? (
|
||||
<div>Offline Time: {formatTime(player.offlineTime)}</div>
|
||||
) : null}
|
||||
<div>
|
||||
{Decimal.lt(points.value, "1e1000") ? <span>You have </span> : null}
|
||||
<h2>{format(points.value)}</h2>
|
||||
{Decimal.lt(points.value, "1e1e6") ? <span> points</span> : null}
|
||||
</div>
|
||||
{Decimal.gt(pointGain.value, 0) ? <div>({oomps.value})</div> : null}
|
||||
<Spacer />
|
||||
{render(tree)}
|
||||
<div>placeholder</div>
|
||||
</>
|
||||
)),
|
||||
points,
|
||||
best,
|
||||
total,
|
||||
oomps,
|
||||
tree
|
||||
))
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -80,7 +30,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
|
|||
export const getInitialLayers = (
|
||||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||
player: Partial<PlayerData>
|
||||
): Array<GenericLayer> => [main, prestige];
|
||||
): Array<GenericLayer> => [main];
|
||||
|
||||
/**
|
||||
* A computed ref whose value is true whenever the game is over.
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"title": "Profectus",
|
||||
"description": "A project made in Profectus",
|
||||
"id": "",
|
||||
"author": "",
|
||||
"title": "Alkatest",
|
||||
"description": "A test",
|
||||
"id": "alkatest",
|
||||
"author": "thepaperpilot",
|
||||
"discordName": "",
|
||||
"discordLink": "",
|
||||
|
||||
"versionNumber": "0.0",
|
||||
"versionNumber": "0.0.0",
|
||||
"versionTitle": "Initial Commit",
|
||||
|
||||
"allowGoBack": true,
|
||||
"allowGoBack": false,
|
||||
"defaultShowSmall": false,
|
||||
"defaultDecimalsShown": 2,
|
||||
"useHeader": true,
|
||||
|
|
190
src/data/socket.tsx
Normal file
190
src/data/socket.tsx
Normal file
|
@ -0,0 +1,190 @@
|
|||
import Text from "components/fields/Text.vue";
|
||||
import { jsx, setDefault } from "features/feature";
|
||||
import { globalBus } from "game/events";
|
||||
import settings, { registerSettingField } from "game/settings";
|
||||
import { io, Socket } from "socket.io-client";
|
||||
import { load } from "util/save";
|
||||
import { ref, watch } from "vue";
|
||||
import { uniqueNamesGenerator, adjectives, colors, animals } from "unique-names-generator";
|
||||
import player from "game/player";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { ProxyState } from "util/proxies";
|
||||
import satisfies from "semver/functions/satisfies";
|
||||
import projInfo from "data/projInfo.json";
|
||||
|
||||
export const connected = ref<boolean>(false);
|
||||
export const room = ref<string | null>(null);
|
||||
export const isHosting = ref<boolean>(false);
|
||||
export const nicknames = ref<Record<string, string>>({});
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const socket = ref<Socket<ServerToClientEvents, ClientToServerEvents> | null>();
|
||||
const connectionError = ref<string>("");
|
||||
|
||||
export function emit<T extends keyof ClientToServerEvents>(
|
||||
event: T,
|
||||
...args: Parameters<ClientToServerEvents[T]>
|
||||
): void {
|
||||
if (!connected.value) {
|
||||
return;
|
||||
}
|
||||
socket.value?.emit(event, ...args);
|
||||
}
|
||||
|
||||
export function getGameState(): GameState {
|
||||
return player.layers.main[ProxyState] as unknown as GameState;
|
||||
}
|
||||
|
||||
globalBus.on("loadSettings", settings => {
|
||||
setDefault(settings, "server", window.location.origin);
|
||||
setDefault(settings, "nickname", randomName());
|
||||
|
||||
watch(
|
||||
() => settings.server,
|
||||
server => {
|
||||
if (socket.value) {
|
||||
socket.value.close();
|
||||
}
|
||||
|
||||
socket.value = io(server);
|
||||
setupSocket(socket.value);
|
||||
|
||||
connected.value = false;
|
||||
connectionError.value = "";
|
||||
socket.value.connect();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => settings.nickname,
|
||||
nickname => {
|
||||
if (room.value) {
|
||||
emit("set nickname", nickname);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerSettingField(
|
||||
jsx(() => (
|
||||
<>
|
||||
<Text
|
||||
title="Server URL"
|
||||
onUpdate:modelValue={value => (settings.server = value)}
|
||||
modelValue={settings.server}
|
||||
/>
|
||||
<div style="font-style: italic; font-size: small; margin-top: -10px;">
|
||||
{connected.value ? (
|
||||
<span>Connected!</span>
|
||||
) : connectionError.value ? (
|
||||
<span style="color: red">{connectionError.value}</span>
|
||||
) : (
|
||||
<span>Connecting...</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
))
|
||||
);
|
||||
registerSettingField(
|
||||
jsx(() => (
|
||||
<>
|
||||
<Text
|
||||
title={jsx(() => (
|
||||
<span>
|
||||
Nickname
|
||||
<button
|
||||
class="button"
|
||||
style="position: absolute; right: 0px; top: 2px;"
|
||||
onClick={() => (settings.nickname = randomName())}
|
||||
>
|
||||
<span class="material-icons">casino</span>
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
onUpdate:modelValue={value => (settings.nickname = value)}
|
||||
modelValue={settings.nickname}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
);
|
||||
});
|
||||
|
||||
function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>) {
|
||||
socket.on("connect", () => {
|
||||
connectionError.value = "";
|
||||
connected.value = true;
|
||||
});
|
||||
socket.on("connect_error", error => {
|
||||
connectionError.value = `${error.name}: ${error.message}`;
|
||||
});
|
||||
socket.on("disconnect", (reason, details) => {
|
||||
connectionError.value =
|
||||
details instanceof Error
|
||||
? `${details.name}: ${details.message}`
|
||||
: details?.description ?? reason;
|
||||
connected.value = false;
|
||||
});
|
||||
socket.on("server version", semver => {
|
||||
if (!satisfies(projInfo.versionNumber, semver)) {
|
||||
toast.info("Server only accepts game versions in range: " + semver);
|
||||
socket.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("info", message => {
|
||||
toast.info(message);
|
||||
globalBus.emit("serverSentInfo");
|
||||
});
|
||||
socket.on("set rooms", rooms => {
|
||||
globalBus.emit("setRooms", rooms);
|
||||
});
|
||||
socket.on("joined room", (r, hosting) => {
|
||||
room.value = r;
|
||||
isHosting.value = hosting;
|
||||
});
|
||||
socket.on("left room", () => {
|
||||
room.value = null;
|
||||
});
|
||||
socket.on("set nicknames", n => {
|
||||
nicknames.value = n;
|
||||
});
|
||||
}
|
||||
|
||||
function randomName(): string {
|
||||
return uniqueNamesGenerator({
|
||||
dictionaries: [adjectives, colors, animals],
|
||||
length: 3,
|
||||
separator: " ",
|
||||
style: "capital"
|
||||
});
|
||||
}
|
||||
|
||||
watch(connected, connected => {
|
||||
if (!connected && room.value) {
|
||||
stopMultiplayer();
|
||||
}
|
||||
});
|
||||
|
||||
function stopMultiplayer() {
|
||||
if (!isHosting.value) {
|
||||
load();
|
||||
}
|
||||
room.value = null;
|
||||
isHosting.value = false;
|
||||
}
|
||||
|
||||
declare module "game/settings" {
|
||||
interface Settings {
|
||||
server: string;
|
||||
nickname: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "game/events" {
|
||||
interface GlobalEvents {
|
||||
openMultiplayer: VoidFunction;
|
||||
setRooms: (rooms: ClientRoomData[]) => void;
|
||||
serverSentInfo: VoidFunction;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import projInfo from "data/projInfo.json";
|
||||
import { isHosting, room } from "data/socket";
|
||||
import { globalBus } from "game/events";
|
||||
import type { Player, PlayerData } from "game/player";
|
||||
import player, { stringifySave } from "game/player";
|
||||
|
@ -118,12 +119,12 @@ export async function loadSave(playerObj: Partial<PlayerData>): Promise<void> {
|
|||
}
|
||||
|
||||
setInterval(() => {
|
||||
if (player.autosave) {
|
||||
if (player.autosave && (!room.value || isHosting.value)) {
|
||||
save();
|
||||
}
|
||||
}, 1000);
|
||||
window.onbeforeunload = () => {
|
||||
if (player.autosave) {
|
||||
if (player.autosave && (!room.value || isHosting.value)) {
|
||||
save();
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue