From 32142945027626de061fb6e53e602f169f536705 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Wed, 26 Jan 2022 09:28:13 -0500 Subject: [PATCH 1/7] Initial work on the Star Map Editor --- client/package.json | 4 + client/src/pages/Config/ConfigList.tsx | 2 +- client/src/pages/Config/Starmap/index.tsx | 59 ++ client/src/pages/Config/index.tsx | 2 + client/src/utils/sleep.ts | 4 + package-lock.json | 821 +++++++++++++++++++++- 6 files changed, 876 insertions(+), 16 deletions(-) create mode 100644 client/src/pages/Config/Starmap/index.tsx create mode 100644 client/src/utils/sleep.ts diff --git a/client/package.json b/client/package.json index ae19c404..d395f445 100644 --- a/client/package.json +++ b/client/package.json @@ -18,6 +18,8 @@ "@mdx-js/mdx": "^2.0.0-next.9", "@mdx-js/react": "^1.6.22", "@msgpack/msgpack": "^2.7.1", + "@react-three/drei": "^8.6.3", + "@react-three/fiber": "^7.0.25", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@uiw/react-monacoeditor": "^3.4.5", @@ -25,6 +27,7 @@ "dot-beat-time": "^1.2.1", "eventemitter3": "^4.0.7", "flexsearch": "^0.7.21", + "gl-matrix": "^3.4.3", "gray-matter": "^4.0.3", "lodash.debounce": "^4.0.8", "lottie-web": "^5.8.1", @@ -44,6 +47,7 @@ "remark-mdx-images": "^1.0.3", "remark-prism": "^1.3.6", "remark-rehype": "^10.1.0", + "rng": "^0.2.2", "three": "^0.135.0", "valtio": "^1.2.7", "vite-plugin-mdx": "^3.5.10", diff --git a/client/src/pages/Config/ConfigList.tsx b/client/src/pages/Config/ConfigList.tsx index 8043b5ca..d194bf65 100644 --- a/client/src/pages/Config/ConfigList.tsx +++ b/client/src/pages/Config/ConfigList.tsx @@ -36,7 +36,7 @@ const ConfigList = () => {

Plugin Aspects

- +

Universe

diff --git a/client/src/pages/Config/Starmap/index.tsx b/client/src/pages/Config/Starmap/index.tsx new file mode 100644 index 00000000..483c7f4d --- /dev/null +++ b/client/src/pages/Config/Starmap/index.tsx @@ -0,0 +1,59 @@ +import Menubar from "@thorium/ui/Menubar"; +import {useParams} from "react-router-dom"; +import {Canvas, useThree} from "@react-three/fiber"; +import {forwardRef, useImperativeHandle, useRef, Suspense} from "react"; +import {Camera} from "three"; +import Nebula from "client/src/components/Starmap/Nebula"; +import {OrbitControls} from "@react-three/drei"; +const FAR = 1e27; + +interface SceneRef { + camera: () => Camera; +} + +export default function StarMap() { + const {pluginId} = useParams() as { + pluginId: string; + }; + const sceneRef = useRef(); + return ( +
+ +
+ { + e.preventDefault(); + }} + gl={{antialias: true, logarithmicDepthBuffer: true, alpha: false}} + camera={{fov: 45, far: FAR}} + mode="concurrent" + > + + +
+
+ ); +} + +const StarmapScene = forwardRef((props, ref) => { + const {camera} = useThree(); + useImperativeHandle(ref, () => ({ + camera: () => { + return camera; + }, + })); + return ( + <> + + + + + + + + + + + + ); +}); diff --git a/client/src/pages/Config/index.tsx b/client/src/pages/Config/index.tsx index 5330a343..19cb5226 100644 --- a/client/src/pages/Config/index.tsx +++ b/client/src/pages/Config/index.tsx @@ -5,6 +5,7 @@ const PluginEdit = lazy(() => import("./PluginEdit")); const ConfigList = lazy(() => import("./ConfigList")); const ShipsConfig = lazy(() => import("./Ships")); const ThemesConfig = lazy(() => import("./Themes")); +const StarmapConfig = lazy(() => import("./Starmap")); export default function ConfigRoutes() { return ( @@ -14,6 +15,7 @@ export default function ConfigRoutes() { } /> } /> } /> + } /> ); } diff --git a/client/src/utils/sleep.ts b/client/src/utils/sleep.ts new file mode 100644 index 00000000..74f3dd9e --- /dev/null +++ b/client/src/utils/sleep.ts @@ -0,0 +1,4 @@ +const sleep = (duration: number) => + new Promise(resolve => setTimeout(resolve, duration)); + +export default sleep; diff --git a/package-lock.json b/package-lock.json index 96eb66a0..1b59f864 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "thorium-nova", - "version": "0.0.0-development", + "version": "1.0.0-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "thorium-nova", - "version": "0.0.0-development", + "version": "1.0.0-alpha.1", "hasInstallScript": true, "license": "Apache 2.0", "workspaces": [ @@ -56,6 +56,8 @@ "@mdx-js/mdx": "^2.0.0-next.9", "@mdx-js/react": "^1.6.22", "@msgpack/msgpack": "^2.7.1", + "@react-three/drei": "^8.6.3", + "@react-three/fiber": "^7.0.25", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@uiw/react-monacoeditor": "^3.4.5", @@ -63,6 +65,7 @@ "dot-beat-time": "^1.2.1", "eventemitter3": "^4.0.7", "flexsearch": "^0.7.21", + "gl-matrix": "^3.4.3", "gray-matter": "^4.0.3", "lodash.debounce": "^4.0.8", "lottie-web": "^5.8.1", @@ -82,6 +85,7 @@ "remark-mdx-images": "^1.0.3", "remark-prism": "^1.3.6", "remark-rehype": "^10.1.0", + "rng": "^0.2.2", "three": "^0.135.0", "valtio": "^1.2.7", "vite-plugin-mdx": "^3.5.10", @@ -2572,9 +2576,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", + "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -2649,6 +2653,16 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@chevrotain/types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-9.1.0.tgz", + "integrity": "sha512-3hbCD1CThkv9gnaSIPq0GUXwKni68e0ph6jIHwCvcWiQ4JB2xi8bFxBain0RF04qHUWuDjgnZLj4rLgimuGO+g==" + }, + "node_modules/@chevrotain/utils": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-9.1.0.tgz", + "integrity": "sha512-llLJZ8OAlZrjGlBvamm6Zdo/HmGAcCLq5gx7cSwUX8No+n/8ip+oaC4x33IdZIif8+Rh5dQUIZXmfbSghiOmNQ==" + }, "node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -4155,6 +4169,135 @@ "@octokit/openapi-types": "^10.6.4" } }, + "node_modules/@react-spring/animated": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.4.2.tgz", + "integrity": "sha512-Dzum5Ho8e+LIAegAqRyoQFakD2IVH3ZQ2nsFXJorAFq3Xjv6IVPz/+TNxb/wSvnsMludfoF+ZIf319FSFmgD5w==", + "dependencies": { + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.4.2.tgz", + "integrity": "sha512-Ej/ULwdx8rQtMAWEpLgwbKcQEx6vPfjyG3cxLP05zAInpCoWkYpl+sXOp9tn3r99mTNQPTTt7BgQsSnmQA8+rQ==", + "dependencies": { + "@react-spring/animated": "~9.4.0", + "@react-spring/rafz": "~9.4.0", + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.4.2.tgz", + "integrity": "sha512-rSm+G8E/XEEpnCGtT/xYN6o8VvEXlU8wN/hyKp4Q44XAZzGSMHLIFP7pY94/MmWsxCxjkw1AxUWhiFYxWrnI5Q==" + }, + "node_modules/@react-spring/shared": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.4.2.tgz", + "integrity": "sha512-mZtbQLpMm6Vy5+O1MSlY9KuAcMO8rdUQvtdnC7Or7y7xiZlnzj8oAILyO6Y2rD2ZC1PmgVS0gMev/8T+MykW+Q==", + "dependencies": { + "@react-spring/rafz": "~9.4.0", + "@react-spring/types": "~9.4.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.4.2.tgz", + "integrity": "sha512-qAPHOMjQjl9V3Eh4Xbdsdx9mAMe+rtSBfEuZGfoF5l8P8zC42gxggbyM1sKUOip3yyz76YTPiosWkmvgCVxMng==", + "dependencies": { + "@react-spring/animated": "~9.4.0", + "@react-spring/core": "~9.4.0", + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": ">=16.11", + "three": ">=0.126" + } + }, + "node_modules/@react-spring/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.4.2.tgz", + "integrity": "sha512-GGiIscTM+CEUNV52anj3g5FqAZKL2+eRKtvBOAlC99qGBbvJ3qTLImrUR/I3lXY7PRuLgzI6kh34quA1oUxWYQ==" + }, + "node_modules/@react-three/drei": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-8.6.3.tgz", + "integrity": "sha512-PE8iyujVX9wOK7vXZ3cTO+MZwJIzUBH79Ec2pNxEHeqUVUaWD7ZuU1rZu10xEEJ8JnlKciE3luzXmTuQ9qDZHw==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@react-spring/three": "^9.3.1", + "@use-gesture/react": "^10.2.0", + "detect-gpu": "^3.1.28", + "glsl-noise": "^0.0.0", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "react-composer": "^5.0.2", + "react-merge-refs": "^1.1.0", + "stats.js": "^0.17.0", + "three-mesh-bvh": "^0.5.2", + "three-stdlib": "^2.6.1", + "troika-three-text": "^0.44.0", + "use-asset": "^1.0.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.13" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": ">=17.0", + "react-dom": ">=17.0", + "three": ">=0.134" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.25.tgz", + "integrity": "sha512-d4XudHlfSYhiMnA8E6HWK5UPr99SdQrg/wTNs2y/sjyqUMAa89WP62rsGUohGTN38qIk/c1DgaG/zSQKXEC6XA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "react-merge-refs": "^1.1.0", + "react-reconciler": "^0.26.2", + "react-three-fiber": "0.0.0-deprecated", + "react-use-measure": "^2.1.1", + "resize-observer-polyfill": "^1.5.1", + "scheduler": "^0.20.2", + "use-asset": "^1.0.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.1" + }, + "peerDependencies": { + "react": ">=17.0", + "react-dom": ">=17.0", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", @@ -5754,6 +5897,22 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.29.1.tgz", "integrity": "sha512-rguaEG/zrPQSaKzQB7IfX/PpNa0qxF1FY8ZXRkN4WIl8qZdTQRSRJCtRto7IMcSgrU6H53RXI+fTcywOBC4aVw==" }, + "node_modules/@use-gesture/core": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.4.tgz", + "integrity": "sha512-fk1LjCBj43BKb8NE05qkdtPOR0ngA7PwgvEqfFap/h+s7QHi+JTv4/mtDQ4wI9zzem+Ry5EKrHS/cVdBehI4wA==" + }, + "node_modules/@use-gesture/react": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.4.tgz", + "integrity": "sha512-CbqyRj+qNbRBOGmS8OWtaOa29fxEr7bKTYHvPuMQ1wsgQDh2/DqQxbp7cFxAg6WZ8oZjppDj/EkWnw22WpIIWQ==", + "dependencies": { + "@use-gesture/core": "10.2.4" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/@vitejs/plugin-react-refresh": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.6.tgz", @@ -5770,6 +5929,16 @@ "node": ">=12.0.0" } }, + "node_modules/@webgpu/glslang": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" + }, + "node_modules/@webxr-input-profiles/motion-controllers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webxr-input-profiles/motion-controllers/-/motion-controllers-1.0.0.tgz", + "integrity": "sha512-Ppxde+G1/QZbU8ShCQg+eq5VtlcL/FPkerF1dkDOLlIml0LJD1tFqnCZYR0SrHzYleIQ2siRnOx7xbFLaCpExQ==" + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -6792,6 +6961,14 @@ "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, + "node_modules/bidi-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.2.tgz", + "integrity": "sha512-rzSy/k7WdX5zOyeHHCOixGXbCHkyogkxPKL2r8QtzHmVQDiWCXUWa18bLdMWT9CYMLOYTjWpTHawuev2ouYJVw==", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -7338,6 +7515,16 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/chevrotain": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-9.1.0.tgz", + "integrity": "sha512-A86/55so63HCfu0dgGg3j9u8uuuBOrSqly1OhBZxRu2x6sAKILLzfVjbGMw45kgier6lz45EzcjjWtTRgoT84Q==", + "dependencies": { + "@chevrotain/types": "^9.1.0", + "@chevrotain/utils": "^9.1.0", + "regexp-to-ast": "0.5.0" + } + }, "node_modules/chokidar": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", @@ -8442,6 +8629,11 @@ "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", "dev": true }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "node_modules/debounce-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", @@ -8748,6 +8940,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/detect-gpu": { + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-3.1.30.tgz", + "integrity": "sha512-WUOk8imHH56AWVt6iHry69qbNEFsPjtS6qsinurfxeI3bVYQZzFk8zECTaodLxfeRad7QspDjjkJWkp5vBo8WA==", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -9168,6 +9368,11 @@ "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, + "node_modules/draco3d": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.0.tgz", + "integrity": "sha512-8ESjH7o5xju1nfSvcS2A9vIbwSRQ3yYY0Yv7SFhNszsq4FlN4LGZuxNc3YfAPcg0AddaK0dE5AES3w1JoGeViA==" + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -11714,6 +11919,11 @@ "pend": "~1.2.0" } }, + "node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -12340,6 +12550,11 @@ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" }, + "node_modules/gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -12529,6 +12744,11 @@ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha1-NndF86MzgsDu7Ey1S36Zz8HXZws=" + }, "node_modules/gonzales-pe": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", @@ -16616,6 +16836,11 @@ "node": ">=6" } }, + "node_modules/ktx-parse": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.2.2.tgz", + "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==" + }, "node_modules/language-subtag-registry": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", @@ -16966,6 +17191,16 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -18242,6 +18477,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mmd-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" + }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -21913,6 +22153,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", + "dependencies": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -23058,6 +23313,11 @@ "node": ">=6.14.4" } }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" + }, "node_modules/power-assert": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/power-assert/-/power-assert-1.6.1.tgz", @@ -23460,7 +23720,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -23470,8 +23729,7 @@ "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/property-information": { "version": "5.6.0", @@ -23652,6 +23910,17 @@ "node": ">=0.10.0" } }, + "node_modules/react-composer": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.2.tgz", + "integrity": "sha512-6E2UNjUF0e7KRY+/faU2Hv7D9zagXnYdTfSSCGdYfuds6mRnVpN19vrbHXShaQzJNVXL4VOUb8qq6DvClDIG1g==", + "dependencies": { + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -23706,6 +23975,31 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/react-merge-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", + "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/react-reconciler": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz", + "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^17.0.2" + } + }, "node_modules/react-refresh": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz", @@ -23739,6 +24033,23 @@ "react-dom": ">=16.8" } }, + "node_modules/react-three-fiber": { + "version": "0.0.0-deprecated", + "resolved": "https://registry.npmjs.org/react-three-fiber/-/react-three-fiber-0.0.0-deprecated.tgz", + "integrity": "sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A==" + }, + "node_modules/react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "dependencies": { + "debounce": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -23983,6 +24294,11 @@ "node": ">=0.10.0" } }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", @@ -24950,6 +25266,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -25074,6 +25395,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rng": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/rng/-/rng-0.2.2.tgz", + "integrity": "sha1-30PoDZvIKtRDC8/vA/SccX6LLow=" + }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -26564,6 +26890,11 @@ "node": ">=0.10.0" } }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha1-scPcRtlEmLV4t/05hbgaznExzH0=" + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -26642,6 +26973,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, "node_modules/string.prototype.matchall": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", @@ -27160,6 +27496,35 @@ "resolved": "https://registry.npmjs.org/three/-/three-0.135.0.tgz", "integrity": "sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ==" }, + "node_modules/three-mesh-bvh": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.5.4.tgz", + "integrity": "sha512-Hq3zpjqBxx2sp/K2Fw7cZ1yEoIVbMc4hOv3VRtmCjHapDKkZpDh8w3OcktbCwn+vBNPt9Ii8D0nDTeqt+73Dwg==", + "peerDependencies": { + "three": ">= 0.123.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.7.2.tgz", + "integrity": "sha512-6jtdJVZOcA+6xE+/YnuOZ8eCuhQhDi4eZ6XKFGYiUDEVTrAFTehScqhWxdchaPGNEEAqSCuXGwSd14m397xr7w==", + "dependencies": { + "@babel/runtime": "^7.16.7", + "@webgpu/glslang": "^0.0.15", + "@webxr-input-profiles/motion-controllers": "^1.0.0", + "chevrotain": "^9.0.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "ktx-parse": "^0.2.1", + "mmd-parser": "^1.0.4", + "opentype.js": "^1.3.3", + "potpack": "^1.0.1", + "zstddec": "^0.0.2" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, "node_modules/throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -27200,6 +27565,11 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, "node_modules/tiny-lru": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", @@ -27383,6 +27753,32 @@ "node": ">=8" } }, + "node_modules/troika-three-text": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.44.0.tgz", + "integrity": "sha512-YwqXczjXQ4yq2a2ufO9icOIjeJutE/ODS8PHmmt/WAzVFqoiqeemclp/Ewiqm0+sdI1KnWRm6lj8df/zmhU3Og==", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.44.0", + "troika-worker-utils": "^0.44.0" + }, + "peerDependencies": { + "three": ">=0.103.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.44.0.tgz", + "integrity": "sha512-gaEpqrlWnkrVU5UgUx+YZTC8NrhsA2Tt6zEIbn3WNuom7pLtrgjuHpAM72gif7DoYdOWEyFco3Zb6rpJh9Fodg==", + "peerDependencies": { + "three": ">=0.103.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.44.0.tgz", + "integrity": "sha512-/ETcH1rUoO9hVBL6Ifea2WOoGPw90ncrk8b8SJKTLtzcQvEWRIZ4eUxlVCtU93fLechCV+DWPs1y8+Bjh1WaJg==" + }, "node_modules/trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", @@ -28108,6 +28504,17 @@ "node": ">=0.10.0" } }, + "node_modules/use-asset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/use-asset/-/use-asset-1.0.4.tgz", + "integrity": "sha512-7/hqDrWa0iMnCoET9W1T07EmD4Eg/Wmoj/X8TGBc++ECRK4m5yTsjP4O6s0yagbxfqIOuUkIxe2/sA+VR2GxZA==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "react": ">=17.0" + } + }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", @@ -28132,6 +28539,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -28698,6 +29113,11 @@ "makeerror": "1.0.x" } }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -28978,6 +29398,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zstddec": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" + }, + "node_modules/zustand": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.6.9.tgz", + "integrity": "sha512-OvDNu/jEWpRnEC7k8xh8GKjqYog7td6FZrLMuHs/IeI8WhrCwV+FngVuwMIFhp5kysZXr6emaeReMqjLGaldAQ==", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", @@ -30369,9 +30810,9 @@ } }, "@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", + "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -30431,6 +30872,16 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@chevrotain/types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-9.1.0.tgz", + "integrity": "sha512-3hbCD1CThkv9gnaSIPq0GUXwKni68e0ph6jIHwCvcWiQ4JB2xi8bFxBain0RF04qHUWuDjgnZLj4rLgimuGO+g==" + }, + "@chevrotain/utils": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-9.1.0.tgz", + "integrity": "sha512-llLJZ8OAlZrjGlBvamm6Zdo/HmGAcCLq5gx7cSwUX8No+n/8ip+oaC4x33IdZIif8+Rh5dQUIZXmfbSghiOmNQ==" + }, "@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -31627,6 +32078,96 @@ "@octokit/openapi-types": "^10.6.4" } }, + "@react-spring/animated": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.4.2.tgz", + "integrity": "sha512-Dzum5Ho8e+LIAegAqRyoQFakD2IVH3ZQ2nsFXJorAFq3Xjv6IVPz/+TNxb/wSvnsMludfoF+ZIf319FSFmgD5w==", + "requires": { + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + } + }, + "@react-spring/core": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.4.2.tgz", + "integrity": "sha512-Ej/ULwdx8rQtMAWEpLgwbKcQEx6vPfjyG3cxLP05zAInpCoWkYpl+sXOp9tn3r99mTNQPTTt7BgQsSnmQA8+rQ==", + "requires": { + "@react-spring/animated": "~9.4.0", + "@react-spring/rafz": "~9.4.0", + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + } + }, + "@react-spring/rafz": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.4.2.tgz", + "integrity": "sha512-rSm+G8E/XEEpnCGtT/xYN6o8VvEXlU8wN/hyKp4Q44XAZzGSMHLIFP7pY94/MmWsxCxjkw1AxUWhiFYxWrnI5Q==" + }, + "@react-spring/shared": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.4.2.tgz", + "integrity": "sha512-mZtbQLpMm6Vy5+O1MSlY9KuAcMO8rdUQvtdnC7Or7y7xiZlnzj8oAILyO6Y2rD2ZC1PmgVS0gMev/8T+MykW+Q==", + "requires": { + "@react-spring/rafz": "~9.4.0", + "@react-spring/types": "~9.4.0" + } + }, + "@react-spring/three": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.4.2.tgz", + "integrity": "sha512-qAPHOMjQjl9V3Eh4Xbdsdx9mAMe+rtSBfEuZGfoF5l8P8zC42gxggbyM1sKUOip3yyz76YTPiosWkmvgCVxMng==", + "requires": { + "@react-spring/animated": "~9.4.0", + "@react-spring/core": "~9.4.0", + "@react-spring/shared": "~9.4.0", + "@react-spring/types": "~9.4.0" + } + }, + "@react-spring/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.4.2.tgz", + "integrity": "sha512-GGiIscTM+CEUNV52anj3g5FqAZKL2+eRKtvBOAlC99qGBbvJ3qTLImrUR/I3lXY7PRuLgzI6kh34quA1oUxWYQ==" + }, + "@react-three/drei": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-8.6.3.tgz", + "integrity": "sha512-PE8iyujVX9wOK7vXZ3cTO+MZwJIzUBH79Ec2pNxEHeqUVUaWD7ZuU1rZu10xEEJ8JnlKciE3luzXmTuQ9qDZHw==", + "requires": { + "@babel/runtime": "^7.11.2", + "@react-spring/three": "^9.3.1", + "@use-gesture/react": "^10.2.0", + "detect-gpu": "^3.1.28", + "glsl-noise": "^0.0.0", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "react-composer": "^5.0.2", + "react-merge-refs": "^1.1.0", + "stats.js": "^0.17.0", + "three-mesh-bvh": "^0.5.2", + "three-stdlib": "^2.6.1", + "troika-three-text": "^0.44.0", + "use-asset": "^1.0.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.13" + } + }, + "@react-three/fiber": { + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.25.tgz", + "integrity": "sha512-d4XudHlfSYhiMnA8E6HWK5UPr99SdQrg/wTNs2y/sjyqUMAa89WP62rsGUohGTN38qIk/c1DgaG/zSQKXEC6XA==", + "requires": { + "@babel/runtime": "^7.13.10", + "react-merge-refs": "^1.1.0", + "react-reconciler": "^0.26.2", + "react-three-fiber": "0.0.0-deprecated", + "react-use-measure": "^2.1.1", + "resize-observer-polyfill": "^1.5.1", + "scheduler": "^0.20.2", + "use-asset": "^1.0.4", + "utility-types": "^3.10.0", + "zustand": "^3.5.1" + } + }, "@rollup/pluginutils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", @@ -32874,6 +33415,19 @@ } } }, + "@use-gesture/core": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.4.tgz", + "integrity": "sha512-fk1LjCBj43BKb8NE05qkdtPOR0ngA7PwgvEqfFap/h+s7QHi+JTv4/mtDQ4wI9zzem+Ry5EKrHS/cVdBehI4wA==" + }, + "@use-gesture/react": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.4.tgz", + "integrity": "sha512-CbqyRj+qNbRBOGmS8OWtaOa29fxEr7bKTYHvPuMQ1wsgQDh2/DqQxbp7cFxAg6WZ8oZjppDj/EkWnw22WpIIWQ==", + "requires": { + "@use-gesture/core": "10.2.4" + } + }, "@vitejs/plugin-react-refresh": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.6.tgz", @@ -32887,6 +33441,16 @@ "react-refresh": "^0.10.0" } }, + "@webgpu/glslang": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" + }, + "@webxr-input-profiles/motion-controllers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webxr-input-profiles/motion-controllers/-/motion-controllers-1.0.0.tgz", + "integrity": "sha512-Ppxde+G1/QZbU8ShCQg+eq5VtlcL/FPkerF1dkDOLlIml0LJD1tFqnCZYR0SrHzYleIQ2siRnOx7xbFLaCpExQ==" + }, "@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -33669,6 +34233,14 @@ "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", "dev": true }, + "bidi-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.2.tgz", + "integrity": "sha512-rzSy/k7WdX5zOyeHHCOixGXbCHkyogkxPKL2r8QtzHmVQDiWCXUWa18bLdMWT9CYMLOYTjWpTHawuev2ouYJVw==", + "requires": { + "require-from-string": "^2.0.2" + } + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -34079,6 +34651,16 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chevrotain": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-9.1.0.tgz", + "integrity": "sha512-A86/55so63HCfu0dgGg3j9u8uuuBOrSqly1OhBZxRu2x6sAKILLzfVjbGMw45kgier6lz45EzcjjWtTRgoT84Q==", + "requires": { + "@chevrotain/types": "^9.1.0", + "@chevrotain/utils": "^9.1.0", + "regexp-to-ast": "0.5.0" + } + }, "chokidar": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", @@ -34255,6 +34837,8 @@ "@mdx-js/mdx": "^2.0.0-next.9", "@mdx-js/react": "^1.6.22", "@msgpack/msgpack": "^2.7.1", + "@react-three/drei": "*", + "@react-three/fiber": "^7.0.25", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@types/color": "^3.0.2", @@ -34272,6 +34856,7 @@ "dot-beat-time": "^1.2.1", "eventemitter3": "^4.0.7", "flexsearch": "^0.7.21", + "gl-matrix": "^3.4.3", "gray-matter": "^4.0.3", "hast-util-to-estree": "^2.0.2", "lodash.debounce": "^4.0.8", @@ -34298,6 +34883,7 @@ "remark-mdx-images": "^1.0.3", "remark-prism": "^1.3.6", "remark-rehype": "^10.1.0", + "rng": "^0.2.2", "tailwindcss": "^3.0.5", "three": "^0.135.0", "typescript": "^4.5.4", @@ -35292,6 +35878,11 @@ "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", "dev": true }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "debounce-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", @@ -35600,6 +36191,14 @@ "repeat-string": "^1.5.4" } }, + "detect-gpu": { + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-3.1.30.tgz", + "integrity": "sha512-WUOk8imHH56AWVt6iHry69qbNEFsPjtS6qsinurfxeI3bVYQZzFk8zECTaodLxfeRad7QspDjjkJWkp5vBo8WA==", + "requires": { + "webgl-constants": "^1.1.1" + } + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -35930,6 +36529,11 @@ "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, + "draco3d": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.0.tgz", + "integrity": "sha512-8ESjH7o5xju1nfSvcS2A9vIbwSRQ3yYY0Yv7SFhNszsq4FlN4LGZuxNc3YfAPcg0AddaK0dE5AES3w1JoGeViA==" + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -37807,6 +38411,11 @@ "pend": "~1.2.0" } }, + "fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" + }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -38281,6 +38890,11 @@ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" }, + "gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -38417,6 +39031,11 @@ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" }, + "glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha1-NndF86MzgsDu7Ey1S36Zz8HXZws=" + }, "gonzales-pe": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", @@ -41525,6 +42144,11 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "ktx-parse": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.2.2.tgz", + "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==" + }, "language-subtag-registry": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", @@ -41818,6 +42442,16 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -42643,6 +43277,11 @@ "minimist": "^1.2.5" } }, + "mmd-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" + }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -45318,6 +45957,15 @@ "is-wsl": "^2.1.1" } }, + "opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", + "requires": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -46140,6 +46788,11 @@ "uniq": "^1.0.1" } }, + "potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" + }, "power-assert": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/power-assert/-/power-assert-1.6.1.tgz", @@ -46479,7 +47132,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -46489,8 +47141,7 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" } } }, @@ -46625,6 +47276,14 @@ "object-assign": "^4.1.1" } }, + "react-composer": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.2.tgz", + "integrity": "sha512-6E2UNjUF0e7KRY+/faU2Hv7D9zagXnYdTfSSCGdYfuds6mRnVpN19vrbHXShaQzJNVXL4VOUb8qq6DvClDIG1g==", + "requires": { + "prop-types": "^15.6.0" + } + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -46663,6 +47322,21 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "react-merge-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", + "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==" + }, + "react-reconciler": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz", + "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, "react-refresh": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz", @@ -46686,6 +47360,19 @@ "react-router": "6.1.1" } }, + "react-three-fiber": { + "version": "0.0.0-deprecated", + "resolved": "https://registry.npmjs.org/react-three-fiber/-/react-three-fiber-0.0.0-deprecated.tgz", + "integrity": "sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A==" + }, + "react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "requires": { + "debounce": "^1.2.1" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -46896,6 +47583,11 @@ "safe-regex": "^1.1.0" } }, + "regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" + }, "regexp.prototype.flags": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", @@ -47535,6 +48227,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -47624,6 +48321,11 @@ "glob": "^7.1.3" } }, + "rng": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/rng/-/rng-0.2.2.tgz", + "integrity": "sha1-30PoDZvIKtRDC8/vA/SccX6LLow=" + }, "roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -48213,7 +48915,7 @@ "@types/three": "^0.135.0", "@types/ws": "^8.2.2", "@types/yauzl": "^2.9.2", - "@types/yazl": "*", + "@types/yazl": "^2.4.2", "esbuild": "^0.14.5", "fast-glob": "^3.2.7", "fastify": "^3.25.0", @@ -48869,6 +49571,11 @@ } } }, + "stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha1-scPcRtlEmLV4t/05hbgaznExzH0=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -48937,6 +49644,11 @@ } } }, + "string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, "string.prototype.matchall": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", @@ -49327,6 +50039,30 @@ "resolved": "https://registry.npmjs.org/three/-/three-0.135.0.tgz", "integrity": "sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ==" }, + "three-mesh-bvh": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.5.4.tgz", + "integrity": "sha512-Hq3zpjqBxx2sp/K2Fw7cZ1yEoIVbMc4hOv3VRtmCjHapDKkZpDh8w3OcktbCwn+vBNPt9Ii8D0nDTeqt+73Dwg==", + "requires": {} + }, + "three-stdlib": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.7.2.tgz", + "integrity": "sha512-6jtdJVZOcA+6xE+/YnuOZ8eCuhQhDi4eZ6XKFGYiUDEVTrAFTehScqhWxdchaPGNEEAqSCuXGwSd14m397xr7w==", + "requires": { + "@babel/runtime": "^7.16.7", + "@webgpu/glslang": "^0.0.15", + "@webxr-input-profiles/motion-controllers": "^1.0.0", + "chevrotain": "^9.0.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "ktx-parse": "^0.2.1", + "mmd-parser": "^1.0.4", + "opentype.js": "^1.3.3", + "potpack": "^1.0.1", + "zstddec": "^0.0.2" + } + }, "throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -49366,6 +50102,11 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, "tiny-lru": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz", @@ -49508,6 +50249,27 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, + "troika-three-text": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.44.0.tgz", + "integrity": "sha512-YwqXczjXQ4yq2a2ufO9icOIjeJutE/ODS8PHmmt/WAzVFqoiqeemclp/Ewiqm0+sdI1KnWRm6lj8df/zmhU3Og==", + "requires": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.44.0", + "troika-worker-utils": "^0.44.0" + } + }, + "troika-three-utils": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.44.0.tgz", + "integrity": "sha512-gaEpqrlWnkrVU5UgUx+YZTC8NrhsA2Tt6zEIbn3WNuom7pLtrgjuHpAM72gif7DoYdOWEyFco3Zb6rpJh9Fodg==", + "requires": {} + }, + "troika-worker-utils": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.44.0.tgz", + "integrity": "sha512-/ETcH1rUoO9hVBL6Ifea2WOoGPw90ncrk8b8SJKTLtzcQvEWRIZ4eUxlVCtU93fLechCV+DWPs1y8+Bjh1WaJg==" + }, "trough": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", @@ -50030,6 +50792,14 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "use-asset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/use-asset/-/use-asset-1.0.4.tgz", + "integrity": "sha512-7/hqDrWa0iMnCoET9W1T07EmD4Eg/Wmoj/X8TGBc++ECRK4m5yTsjP4O6s0yagbxfqIOuUkIxe2/sA+VR2GxZA==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, "use-isomorphic-layout-effect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", @@ -50047,6 +50817,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -50412,6 +51187,11 @@ "makeerror": "1.0.x" } }, + "webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -50620,6 +51400,17 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, + "zstddec": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" + }, + "zustand": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.6.9.tgz", + "integrity": "sha512-OvDNu/jEWpRnEC7k8xh8GKjqYog7td6FZrLMuHs/IeI8WhrCwV+FngVuwMIFhp5kysZXr6emaeReMqjLGaldAQ==", + "requires": {} + }, "zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", From 863de1d1a2aa72c350a6e1985d42871f82b84cc9 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Tue, 1 Feb 2022 18:48:24 -0500 Subject: [PATCH 2/7] Finished initial work on the 3D interstellar starmap. --- client/package.json | 5 +- .../Starmap/SystemMarker/SystemCircle.tsx | 164 ++++++++++++ .../Starmap/SystemMarker/SystemLabel.tsx | 88 +++++++ .../components/Starmap/SystemMarker/index.tsx | 75 ++++++ client/src/components/Starmap/starmapStore.ts | 26 ++ client/src/context/ThoriumContext.tsx | 3 +- client/src/hooks/useObjectDrag.tsx | 75 ++++++ client/src/pages/Config/Starmap/index.tsx | 233 ++++++++++++++++-- package-lock.json | 26 +- server/src/inputs/plugins/solarSystems.ts | 2 +- .../src/netRequests/plugins/solarSystems.ts | 6 +- server/src/utils/constants.ts | 6 +- server/src/utils/unitTypes.ts | 7 + 13 files changed, 688 insertions(+), 28 deletions(-) create mode 100644 client/src/components/Starmap/SystemMarker/SystemCircle.tsx create mode 100644 client/src/components/Starmap/SystemMarker/SystemLabel.tsx create mode 100644 client/src/components/Starmap/SystemMarker/index.tsx create mode 100644 client/src/components/Starmap/starmapStore.ts create mode 100644 client/src/hooks/useObjectDrag.tsx diff --git a/client/package.json b/client/package.json index d395f445..b0067d45 100644 --- a/client/package.json +++ b/client/package.json @@ -20,9 +20,11 @@ "@msgpack/msgpack": "^2.7.1", "@react-three/drei": "^8.6.3", "@react-three/fiber": "^7.0.25", + "@seregpie/three.text-texture": "^3.2.1", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@uiw/react-monacoeditor": "^3.4.5", + "@use-gesture/react": "^10.2.4", "color": "^4.1.0", "dot-beat-time": "^1.2.1", "eventemitter3": "^4.0.7", @@ -51,7 +53,8 @@ "three": "^0.135.0", "valtio": "^1.2.7", "vite-plugin-mdx": "^3.5.10", - "vite-tsconfig-paths": "^3.3.17" + "vite-tsconfig-paths": "^3.3.17", + "zustand": "^3.6.9" }, "devDependencies": { "@types/color": "^3.0.2", diff --git a/client/src/components/Starmap/SystemMarker/SystemCircle.tsx b/client/src/components/Starmap/SystemMarker/SystemCircle.tsx new file mode 100644 index 00000000..6536e029 --- /dev/null +++ b/client/src/components/Starmap/SystemMarker/SystemCircle.tsx @@ -0,0 +1,164 @@ +import {MeshProps, useFrame} from "@react-three/fiber"; +import {netSend} from "client/src/context/netSend"; +import useObjectDrag from "client/src/hooks/useObjectDrag"; +import * as React from "react"; +import {useCallback} from "react"; +import {CanvasTexture, Group, Vector3} from "three"; +import {useStarmapStore} from "../starmapStore"; + +const size = 50; +const lineWidth = 0.07; +export const DraggableSystemCircle: React.FC< + { + hoveringDirection: React.MutableRefObject; + systemId: string; + parentObject: React.MutableRefObject; + } & MeshProps +> = ({parentObject: parent, hoveringDirection, systemId, ...props}) => { + const bind = useObjectDrag(parent, { + onMouseUp: (position: Vector3) => { + useStarmapStore.getState().setCameraControlsEnabled(true); + const pluginId = useStarmapStore.getState().pluginId; + if (!pluginId) return; + netSend("pluginSolarSystemUpdate", { + pluginId, + solarSystemId: systemId, + position, + }); + }, + onMouseDown: () => { + useStarmapStore.setState({ + selectedObjectId: systemId, + // selectedPosition: parent.current.position, + // scaledSelectedPosition: parent.current.position, + }); + useStarmapStore.getState().setCameraControlsEnabled(false); + }, + onDrag: (position: Vector3) => { + useStarmapStore.setState({ + hoveredPosition: [position.x, position.y, position.z], + }); + }, + }); + const setSystemId = useStarmapStore(s => s.setSystemId); + + return ( + { + props?.onPointerOver?.(e); + const position = parent.current.position; + useStarmapStore.setState({ + hoveredPosition: [position.x, position.y, position.z], + }); + }} + onPointerOut={e => { + props?.onPointerOut?.(e); + useStarmapStore.setState({ + hoveredPosition: null, + }); + }} + onDoubleClick={() => { + setSystemId(systemId); + }} + /> + ); +}; + +const SystemCircle: React.FC< + { + systemId: string; + hoveringDirection: React.MutableRefObject; + } & MeshProps +> = ({systemId, hoveringDirection, ...props}) => { + const ctx = React.useMemo(() => { + const canvas = document.createElement("canvas"); + + canvas.height = size; + canvas.width = size; + + var ctx = canvas.getContext("2d") as CanvasRenderingContext2D; + return ctx; + }, []); + + const drawRadius = useCallback( + function drawRadius(endArc = 360) { + const selectedObjectId = useStarmapStore.getState().selectedObjectId; + const isSelected = systemId === selectedObjectId; + ctx.clearRect(0, 0, size, size); + + ctx.lineWidth = size / (1 / lineWidth); + ctx.strokeStyle = isSelected ? "white" : "rgba(0,255,255,0.2)"; + ctx.beginPath(); + ctx.arc( + size / 2, + size / 2, + size / 2 - size / (1 / lineWidth), + 0, + Math.PI * 2 + ); + ctx.stroke(); + ctx.strokeStyle = "cyan"; + ctx.beginPath(); + ctx.arc( + size / 2, + size / 2, + size / 2 - size / (1 / lineWidth), + -Math.PI / 2, + endArc + ); + ctx.stroke(); + }, + [ctx, systemId] + ); + const radius = React.useRef(0); + const selected = React.useRef(false); + + const texture = React.useMemo(() => { + const texture = new CanvasTexture(ctx.canvas); + texture.needsUpdate = true; + return texture; + }, [ctx]); + + useFrame(() => { + const selectedObjectId = useStarmapStore.getState().selectedObjectId; + const isSelected = systemId === selectedObjectId; + if (isSelected) { + selected.current = true; + } + if (selected.current && !isSelected) { + selected.current = false; + drawRadius(radius.current - Math.PI / 2); + texture.needsUpdate = true; + } + if (hoveringDirection.current === 0) return; + radius.current += 0.5 * hoveringDirection.current; + if (radius.current >= Math.PI * 2) { + hoveringDirection.current = 0; + radius.current = Math.PI * 2; + } + if (radius.current <= 0) { + hoveringDirection.current = 0; + radius.current = 0; + } + + drawRadius(radius.current - Math.PI / 2); + texture.needsUpdate = true; + }); + + React.useEffect(() => { + drawRadius(radius.current - Math.PI / 2); + texture.needsUpdate = true; + }, [drawRadius, texture]); + + return ( + + + + + ); +}; +export default SystemCircle; diff --git a/client/src/components/Starmap/SystemMarker/SystemLabel.tsx b/client/src/components/Starmap/SystemMarker/SystemLabel.tsx new file mode 100644 index 00000000..f7c3c126 --- /dev/null +++ b/client/src/components/Starmap/SystemMarker/SystemLabel.tsx @@ -0,0 +1,88 @@ +import React from "react"; +// @ts-ignore +import TextTexture from "@seregpie/three.text-texture"; +import {AdditiveBlending, Sprite} from "three"; +import {useFrame} from "@react-three/fiber"; +import {useStarmapStore} from "../starmapStore"; + +const SystemLabel: React.FC<{ + systemId: string; + name: string; + color?: string; + scale?: number; + hoveringDirection: React.MutableRefObject; +}> = ({ + systemId, + color = "rgb(0,255,255)", + scale = 3 / 128, + name, + hoveringDirection, +}) => { + React.useEffect(() => { + if (text.current) { + text.current.material.opacity = 0.5; + } + }, []); + + const textTexture = React.useMemo(() => { + let texture = new TextTexture({ + color, + fontFamily: 'Electrolize, "Gill Sans", sans-serif', + fontSize: 128, + alignment: "right", + text: name, + }); + texture.redraw(); + return texture; + }, [name, color]); + + const text = React.useRef(); + const selected = React.useRef(false); + useFrame(({camera}) => { + const selectedObjectId = useStarmapStore.getState().selectedObjectId; + const isSelected = systemId === selectedObjectId; + if (text.current) { + if (isSelected) { + selected.current = true; + text.current.material.opacity = 1; + return; + } + + if (hoveringDirection.current !== 0) { + text.current.material.opacity = Math.max( + 0.5, + Math.min( + 1, + text.current.material.opacity + 0.05 * hoveringDirection.current + ) + ); + } else if (selected.current) { + text.current.material.opacity = 0.5; + } + } + }); + + const spriteWidth = textTexture.width / textTexture.height; + return ( + + + + + ); +}; +export default SystemLabel; diff --git a/client/src/components/Starmap/SystemMarker/index.tsx b/client/src/components/Starmap/SystemMarker/index.tsx new file mode 100644 index 00000000..ba51991c --- /dev/null +++ b/client/src/components/Starmap/SystemMarker/index.tsx @@ -0,0 +1,75 @@ +import React from "react"; +import {Group} from "three"; +import SystemLabel from "./SystemLabel"; +import SystemCircle, {DraggableSystemCircle} from "./SystemCircle"; +import {MeshProps, useFrame} from "@react-three/fiber"; +const SystemMarker: React.FC< + { + systemId: string; + name: string; + position: [number, number, number]; + draggable?: boolean; + onPointerDown?: () => void; + } & MeshProps +> = ({systemId, name, position, draggable, ...props}) => { + const group = React.useRef(new Group()); + + const direction = React.useRef(0); + + useFrame(({camera}) => { + const zoom = group.current?.position + ? camera.position.distanceTo(group.current?.position) + : 1; + let zoomedScale = (zoom / 2) * 0.015; + group.current?.scale.set(zoomedScale, zoomedScale, zoomedScale); + group.current?.quaternion.copy(camera.quaternion); + }); + + return ( + <> + + {draggable ? ( + { + props?.onPointerOver?.(e); + direction.current = 1; + document.body.style.cursor = "pointer"; + }} + onPointerOut={e => { + props?.onPointerOut?.(e); + direction.current = -1; + document.body.style.cursor = "auto"; + }} + /> + ) : ( + { + props?.onPointerOver?.(e); + direction.current = 1; + document.body.style.cursor = "pointer"; + }} + onPointerOut={e => { + props?.onPointerOut?.(e); + direction.current = -1; + document.body.style.cursor = "auto"; + }} + /> + )} + + + + ); +}; + +export default SystemMarker; diff --git a/client/src/components/Starmap/starmapStore.ts b/client/src/components/Starmap/starmapStore.ts new file mode 100644 index 00000000..d68633a8 --- /dev/null +++ b/client/src/components/Starmap/starmapStore.ts @@ -0,0 +1,26 @@ +import {Vector3} from "three"; +import create from "zustand"; + +interface StarmapStore { + viewingMode: "editor" | "core" | "station" | "viewscreen"; + skyboxKey: string; + selectedObjectId: string | null; + cameraControlsEnabled: boolean; + setCameraControlsEnabled: (enabled: boolean) => void; + pluginId: string | null; + systemId: string | null; + setSystemId: (systemId: string | null) => void; + hoveredPosition: [number, number, number] | null; +} +export const useStarmapStore = create(set => ({ + skyboxKey: "blank", + viewingMode: "editor", + selectedObjectId: null, + cameraControlsEnabled: true, + setCameraControlsEnabled: (enabled: boolean) => + set({cameraControlsEnabled: enabled}), + pluginId: null, + systemId: null, + setSystemId: (systemId: string | null) => set({systemId: systemId}), + hoveredPosition: null, +})); diff --git a/client/src/context/ThoriumContext.tsx b/client/src/context/ThoriumContext.tsx index 14582fef..f4ccf1a5 100644 --- a/client/src/context/ThoriumContext.tsx +++ b/client/src/context/ThoriumContext.tsx @@ -1,5 +1,4 @@ import {createContext, ReactNode, useContext, useMemo} from "react"; -import * as React from "react"; import {useDataConnection} from "../hooks/useDataConnection"; import {FaSpinner} from "react-icons/fa"; import {SnapshotInterpolation} from "@geckos.io/snapshot-interpolation"; @@ -8,7 +7,7 @@ import Button from "@thorium/ui/Button"; import {ThoriumAccountContextProvider} from "./ThoriumAccountContext"; import {SI} from "../utils/clientSocket"; -const ThoriumContext = createContext(null); +export const ThoriumContext = createContext(null); interface IThoriumContext { SI: SnapshotInterpolation; diff --git a/client/src/hooks/useObjectDrag.tsx b/client/src/hooks/useObjectDrag.tsx new file mode 100644 index 00000000..fd519b4a --- /dev/null +++ b/client/src/hooks/useObjectDrag.tsx @@ -0,0 +1,75 @@ +import {useThree} from "@react-three/fiber"; +import React from "react"; +import {Matrix4, Object3D, Plane, Raycaster, Vector3} from "three"; +import {useGesture} from "@use-gesture/react"; + +export default function useObjectDrag( + obj: React.MutableRefObject, + { + onMouseUp, + onMouseDown, + onDrag, + }: {onMouseUp?: any; onMouseDown?: any; onDrag?: any} +) { + const {mouse, camera} = useThree(); + const raycaster = React.useRef(new Raycaster()); + + const distance = React.useRef(0); + const plane = React.useRef(new Plane(new Vector3(0, 0, 1), 0)); + const intersection = React.useRef(new Vector3()); + const worldPosition = React.useRef(new Vector3()); + const offset = React.useRef(new Vector3()); + const inverseMatrix = React.useRef(new Matrix4()); + + const bind = useGesture({ + onMouseDown: e => { + onMouseDown?.(e); + }, + onDragStart: e => { + if (!obj.current) return; + e.event?.stopPropagation(); + onMouseDown?.(e); + distance.current = camera.position.distanceTo(obj.current.position); + plane.current.setFromNormalAndCoplanarPoint( + camera.getWorldDirection(plane.current.normal), + worldPosition.current.setFromMatrixPosition(obj.current.matrixWorld) + ); + if ( + raycaster.current.ray.intersectPlane( + plane.current, + intersection.current + ) && + obj.current.parent + ) { + inverseMatrix.current.copy(obj.current.parent.matrixWorld).invert(); + offset.current + .copy(intersection.current) + .sub( + worldPosition.current.setFromMatrixPosition(obj.current.matrixWorld) + ); + } + }, + onDragEnd: e => { + if (!obj.current) return; + onMouseUp?.(obj.current.position); + }, + onDrag: e => { + onDrag?.(obj.current?.position); + raycaster.current.setFromCamera(mouse, camera); + if ( + raycaster.current.ray.intersectPlane( + plane.current, + intersection.current + ) + ) { + obj.current?.position.copy( + intersection.current + // .sub(offset.current) + .applyMatrix4(inverseMatrix.current) + ); + } + }, + }); + + return bind; +} diff --git a/client/src/pages/Config/Starmap/index.tsx b/client/src/pages/Config/Starmap/index.tsx index 483c7f4d..da38fb7c 100644 --- a/client/src/pages/Config/Starmap/index.tsx +++ b/client/src/pages/Config/Starmap/index.tsx @@ -1,25 +1,155 @@ import Menubar from "@thorium/ui/Menubar"; -import {useParams} from "react-router-dom"; -import {Canvas, useThree} from "@react-three/fiber"; -import {forwardRef, useImperativeHandle, useRef, Suspense} from "react"; -import {Camera} from "three"; -import Nebula from "client/src/components/Starmap/Nebula"; -import {OrbitControls} from "@react-three/drei"; +import {useMatch, useNavigate, useParams} from "react-router-dom"; +import {Canvas, useFrame, useThree} from "@react-three/fiber"; +import { + forwardRef, + useImperativeHandle, + useRef, + Suspense, + useEffect, + useState, +} from "react"; +import {Camera, MOUSE, Vector3} from "three"; +import {OrbitControls, useContextBridge} from "@react-three/drei"; +import {useStarmapStore} from "client/src/components/Starmap/starmapStore"; +import {useNetRequest} from "client/src/context/useNetRequest"; +import {ThoriumContext} from "client/src/context/ThoriumContext"; +import SystemMarker from "client/src/components/Starmap/SystemMarker"; +import Button from "@thorium/ui/Button"; +import { + lightMinuteToLightYear, + LightYear, + lightYearToLightMinute, +} from "server/src/utils/unitTypes"; +import {netSend} from "client/src/context/netSend"; +import {toast} from "client/src/context/ToastContext"; +import {useConfirm} from "@thorium/ui/AlertDialog"; + const FAR = 1e27; interface SceneRef { camera: () => Camera; } +function useSynchronizeSystemId() { + const {pluginId} = useParams() as { + pluginId: string; + }; + const navigate = useNavigate(); + const systemId = useStarmapStore(store => store.systemId) || null; + const match = useMatch("/config/:pluginId/starmap/:systemId"); + const matchSystemId = match?.params.systemId || null; + const [storedSystemId, setStoredSystemId] = useState(matchSystemId); + let mounted = useRef(false); + useEffect(() => { + if (!mounted.current) return; + setStoredSystemId(matchSystemId); + }, [matchSystemId]); + useEffect(() => { + if (!mounted.current) return; + setStoredSystemId(systemId); + }, [systemId]); + useEffect(() => { + if (storedSystemId) { + navigate(`/config/${pluginId}/starmap/${storedSystemId}`); + useStarmapStore.setState({systemId: storedSystemId}); + } else { + navigate(`/config/${pluginId}/starmap`); + useStarmapStore.setState({systemId: null}); + } + }, [storedSystemId]); + useEffect(() => { + mounted.current = true; + }, []); + + return storedSystemId; +} export default function StarMap() { const {pluginId} = useParams() as { pluginId: string; }; + const sceneRef = useRef(); + + useEffect(() => { + useStarmapStore.setState({pluginId}); + return () => useStarmapStore.setState({pluginId: null}); + }, [pluginId]); + + const systemId = useSynchronizeSystemId(); + + const ContextBridge = useContextBridge(ThoriumContext); + const selectedObjectId = useStarmapStore(s => s.selectedObjectId); + + const confirm = useConfirm(); + async function deleteObject() { + const selectedObjectId = useStarmapStore.getState().selectedObjectId; + if (!selectedObjectId) return; + + const doRemove = await confirm({ + header: "Are you sure you want to remove this object?", + body: "It will remove all of the objects inside of it.", + }); + if (!doRemove) return; + + await netSend("pluginSolarSystemDelete", { + pluginId, + solarSystemId: selectedObjectId, + }); + + useStarmapStore.setState({ + selectedObjectId: null, + }); + } + return (
- -
+ + + + + +
{ e.preventDefault(); @@ -28,32 +158,101 @@ export default function StarMap() { camera={{fov: 45, far: FAR}} mode="concurrent" > - + + + +
); } +function StatusBar() { + const hoveredPosition = useStarmapStore(s => s.hoveredPosition); + return ( +
+ {hoveredPosition && ( + + {Math.round(lightMinuteToLightYear(hoveredPosition[0]) * 100) / 100},{" "} + {Math.round(lightMinuteToLightYear(hoveredPosition[1]) * 100) / 100},{" "} + {Math.round(lightMinuteToLightYear(hoveredPosition[2]) * 100) / 100} + + )} +
+ ); +} + +const INTERSTELLAR_MAX_DISTANCE: LightYear = 2000; + +function InterstellarMap() { + const pluginId = useStarmapStore(s => s.pluginId as string); + + const stars = useNetRequest("pluginSolarSystems", {pluginId}); + const controlsEnabled = useStarmapStore(s => s.cameraControlsEnabled); + + const orbitControls = useRef(); + const {camera} = useThree(); + useEffect(() => { + // Set the initial camera position + camera.position.setY(lightYearToLightMinute(INTERSTELLAR_MAX_DISTANCE) / 2); + camera.position.setZ(0); + camera.position.setX(0); + camera.lookAt(0, 0, 0); + }, [camera]); + + return ( + + + + {stars.map(star => ( + + ))} + + ); +} +function SolarSystemMap() { + return ( + + + + + ); +} + const StarmapScene = forwardRef((props, ref) => { + const pluginId = useStarmapStore(s => s.pluginId); + const systemId = useStarmapStore(s => s.systemId); + const {camera} = useThree(); useImperativeHandle(ref, () => ({ camera: () => { return camera; }, })); + return ( <> - - - - - - - - + {pluginId && !systemId && } + {pluginId && systemId && } ); }); diff --git a/package-lock.json b/package-lock.json index 1b59f864..6aea2c6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,9 +58,11 @@ "@msgpack/msgpack": "^2.7.1", "@react-three/drei": "^8.6.3", "@react-three/fiber": "^7.0.25", + "@seregpie/three.text-texture": "^3.2.1", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@uiw/react-monacoeditor": "^3.4.5", + "@use-gesture/react": "^10.2.4", "color": "^4.1.0", "dot-beat-time": "^1.2.1", "eventemitter3": "^4.0.7", @@ -89,7 +91,8 @@ "three": "^0.135.0", "valtio": "^1.2.7", "vite-plugin-mdx": "^3.5.10", - "vite-tsconfig-paths": "^3.3.17" + "vite-tsconfig-paths": "^3.3.17", + "zustand": "^3.6.9" }, "devDependencies": { "@types/color": "^3.0.2", @@ -4836,6 +4839,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@seregpie/three.text-texture": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@seregpie/three.text-texture/-/three.text-texture-3.2.1.tgz", + "integrity": "sha512-+rBfu63PolUyg6WB56SxYIIGGw7BMiFMeoj6AcxGooGs1apnudu024EMY/6dr1KnpIa9lNIwSgJETeaclgT/BQ==", + "peerDependencies": { + "three": ">=0.113" + } + }, "node_modules/@sideway/address": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", @@ -32561,6 +32572,12 @@ } } }, + "@seregpie/three.text-texture": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@seregpie/three.text-texture/-/three.text-texture-3.2.1.tgz", + "integrity": "sha512-+rBfu63PolUyg6WB56SxYIIGGw7BMiFMeoj6AcxGooGs1apnudu024EMY/6dr1KnpIa9lNIwSgJETeaclgT/BQ==", + "requires": {} + }, "@sideway/address": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", @@ -34837,8 +34854,9 @@ "@mdx-js/mdx": "^2.0.0-next.9", "@mdx-js/react": "^1.6.22", "@msgpack/msgpack": "^2.7.1", - "@react-three/drei": "*", + "@react-three/drei": "^8.6.3", "@react-three/fiber": "^7.0.25", + "@seregpie/three.text-texture": "*", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@types/color": "^3.0.2", @@ -34849,6 +34867,7 @@ "@types/react-dom": "^17.0.11", "@types/three": "^0.135.0", "@uiw/react-monacoeditor": "^3.4.5", + "@use-gesture/react": "^10.2.4", "@vitejs/plugin-react-refresh": "^1.3.6", "autoprefixer": "^10.4.0", "color": "^4.1.0", @@ -34891,7 +34910,8 @@ "vite": "^2.7.2", "vite-plugin-mdx": "^3.5.10", "vite-react-jsx": "^1.1.2", - "vite-tsconfig-paths": "^3.3.17" + "vite-tsconfig-paths": "^3.3.17", + "zustand": "^3.6.9" }, "dependencies": { "@types/estree": { diff --git a/server/src/inputs/plugins/solarSystems.ts b/server/src/inputs/plugins/solarSystems.ts index 880039af..b6a49b73 100644 --- a/server/src/inputs/plugins/solarSystems.ts +++ b/server/src/inputs/plugins/solarSystems.ts @@ -45,7 +45,7 @@ export const solarSystemsPluginInputs = { ); await solarSystem?.removeFile(); - pubsub.publish("pluginShips", {pluginId: params.pluginId}); + pubsub.publish("pluginSolarSystems", {pluginId: params.pluginId}); }, async pluginSolarSystemUpdate( context: DataContext, diff --git a/server/src/netRequests/plugins/solarSystems.ts b/server/src/netRequests/plugins/solarSystems.ts index 7f071320..ebd678f4 100644 --- a/server/src/netRequests/plugins/solarSystems.ts +++ b/server/src/netRequests/plugins/solarSystems.ts @@ -9,7 +9,11 @@ export const pluginSolarSystemsRequest = { ) { if (publishParams && params.pluginId !== publishParams.pluginId) throw null; const plugin = getPlugin(context, params.pluginId); - return plugin.aspects.solarSystems; + return plugin.aspects.solarSystems.map(solarSystem => ({ + name: solarSystem.name, + position: solarSystem.position, + description: solarSystem.description, + })); }, pluginSolarSystem( context: DataContext, diff --git a/server/src/utils/constants.ts b/server/src/utils/constants.ts index 35c238a5..71e7bf2a 100644 --- a/server/src/utils/constants.ts +++ b/server/src/utils/constants.ts @@ -1,9 +1,9 @@ -import {Centimeter, LightMinute} from "./unitTypes"; +import {Centimeter, LightMinute, lightYearToLightMinute} from "./unitTypes"; /** - * Measured in light minutes; the radius of the Milky Way + * Measured in light minutes; 2000 light years in radius */ -export const UNIVERSE_RADIUS: LightMinute = 2.6e10; +export const UNIVERSE_RADIUS: LightMinute = lightYearToLightMinute(2000); /** * Measured in centimeters diff --git a/server/src/utils/unitTypes.ts b/server/src/utils/unitTypes.ts index 411818a7..ca1b0f9c 100644 --- a/server/src/utils/unitTypes.ts +++ b/server/src/utils/unitTypes.ts @@ -11,4 +11,11 @@ export type AstronomicalUnit = Flavor; export type LightYear = Flavor; export type LightMinute = Flavor; +export function lightMinuteToLightYear(len: LightMinute) { + return len / (60 * 24 * 365.25); +} +export function lightYearToLightMinute(len: LightYear) { + return len * (60 * 24 * 365.25); +} + export type Kilograms = Flavor; From 17e810a24c4b29e58149ca86f9e8785130748713 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Thu, 3 Feb 2022 08:09:20 -0500 Subject: [PATCH 3/7] Add a unit test to make sure interstellar objects are appearing correctly. --- client/package.json | 2 + client/src/context/useNetRequest.ts | 13 ++- .../src/pages/Config/Starmap/index.test.tsx | 72 ++++++++++++++++ client/src/pages/Config/Starmap/index.tsx | 3 +- client/test-utils.tsx | 11 ++- package-lock.json | 86 +++++++++++++++++-- .../__test__/solarSystemsPlugin.test.ts | 4 +- test/jest.client.cjs | 5 +- 8 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 client/src/pages/Config/Starmap/index.test.tsx diff --git a/client/package.json b/client/package.json index b0067d45..1e242059 100644 --- a/client/package.json +++ b/client/package.json @@ -57,6 +57,7 @@ "zustand": "^3.6.9" }, "devDependencies": { + "@react-three/test-renderer": "^7.0.25", "@types/color": "^3.0.2", "@types/flexsearch": "^0.7.2", "@types/lodash.debounce": "^4.0.6", @@ -68,6 +69,7 @@ "autoprefixer": "^10.4.0", "daisyui": "^1.16.5", "hast-util-to-estree": "^2.0.2", + "jest-canvas-mock": "^2.3.1", "markdown-it": "^12.3.0", "postcss": "^8.4.5", "postcss-cli": "^9.1.0", diff --git a/client/src/context/useNetRequest.ts b/client/src/context/useNetRequest.ts index 12cb7f06..6e4d6e38 100644 --- a/client/src/context/useNetRequest.ts +++ b/client/src/context/useNetRequest.ts @@ -1,12 +1,15 @@ import { + createContext, MutableRefObject, useCallback, + useContext, useEffect, useReducer, useRef, useState, } from "react"; import { + AllRequests, AllRequestNames, AllRequestParams, AllRequestReturns, @@ -66,6 +69,8 @@ function useNetRequestData() { type UnwrapPromise = T extends Promise ? U : T; +export const MockNetRequestContext = createContext(null!); + export async function netRequest< T extends AllRequestNames, R extends AllRequestReturns[T] @@ -105,7 +110,9 @@ export function useNetRequest< const {socket} = useThorium(); const [ready, resetReady] = useReducer(() => ({}), {}); const [hookId] = useState(() => uniqid()); - if (!socket) throw new Promise(() => {}); + const mockData = useContext(MockNetRequestContext); + + if (!socket && !mockData) throw new Promise(() => {}); const setUpRequest = useCallback( hookId => { @@ -141,6 +148,7 @@ export function useNetRequest< resetReady(); delete data[requestId]; }; + if (mockData) return; socket.on("ready", handleReady); return () => { socket.off("ready", handleReady); @@ -148,6 +156,7 @@ export function useNetRequest< }, [socket, requestId, data]); useEffect(() => { + if (mockData) return; setUpRequest(hookId); return () => { takeDownRequest(hookId); @@ -168,6 +177,8 @@ export function useNetRequest< }; }, [requestId]); + if (mockData) return mockData[requestName]; + if (!data[requestId] && data[requestId] !== null) { setUpRequest(hookId); throw new Promise(res => { diff --git a/client/src/pages/Config/Starmap/index.test.tsx b/client/src/pages/Config/Starmap/index.test.tsx new file mode 100644 index 00000000..ec411a8f --- /dev/null +++ b/client/src/pages/Config/Starmap/index.test.tsx @@ -0,0 +1,72 @@ +import * as React from "react"; +import {Suspense} from "react"; +import ReactThreeTestRenderer from "@react-three/test-renderer"; +import {InterstellarMap} from "."; +import {ThoriumContext} from "client/src/context/ThoriumContext"; +import {MockNetRequestContext} from "client/src/context/useNetRequest"; + +jest.mock("scheduler", () => require("scheduler/unstable_mock")); + +describe("Starmap Plugin Editor", () => { + it("should render a single solar system properly", async () => { + const renderer = await ReactThreeTestRenderer.create( + + + + + + + + ); + + // Stars, the solar system, and the camera + expect(renderer.scene.allChildren.length).toBe(3); + expect(renderer.scene.findByType("Group").props.position).toEqual([ + 10, 20, 30, + ]); + }); + it("should render multiple solar systems properly", async () => { + const renderer = await ReactThreeTestRenderer.create( + + + + + + + + ); + + // Stars, the solar system, and the camera + expect(renderer.scene.allChildren.length).toBe(5); + }); +}); diff --git a/client/src/pages/Config/Starmap/index.tsx b/client/src/pages/Config/Starmap/index.tsx index da38fb7c..0f1383a8 100644 --- a/client/src/pages/Config/Starmap/index.tsx +++ b/client/src/pages/Config/Starmap/index.tsx @@ -1,3 +1,4 @@ +import * as React from "react"; import Menubar from "@thorium/ui/Menubar"; import {useMatch, useNavigate, useParams} from "react-router-dom"; import {Canvas, useFrame, useThree} from "@react-three/fiber"; @@ -185,7 +186,7 @@ function StatusBar() { const INTERSTELLAR_MAX_DISTANCE: LightYear = 2000; -function InterstellarMap() { +export function InterstellarMap() { const pluginId = useStarmapStore(s => s.pluginId as string); const stars = useNetRequest("pluginSolarSystems", {pluginId}); diff --git a/client/test-utils.tsx b/client/test-utils.tsx index 9f89b763..30900f3e 100644 --- a/client/test-utils.tsx +++ b/client/test-utils.tsx @@ -7,6 +7,8 @@ import { MockClientDataContext, } from "./src/context/useCardData"; import {DataCardNames} from "./src/utils/cardData"; +import {MockNetRequestContext} from "./src/context/useNetRequest"; +import {AllRequests} from "server/src/netRequests"; let netSendResponse: {response: any} = {response: ""}; const netSendSpy = jest.fn((input, params) => netSendResponse); @@ -31,6 +33,7 @@ global.fetch = jest.fn((path: string, {body}: {body: FormData}) => { interface OptionsInterface { initialRoutes?: string[]; cardData?: Required; + netRequestData?: AllRequests; } async function render( @@ -80,9 +83,11 @@ async function render( theme: null, }} > - - {children} - + + + {children} + + ); diff --git a/package-lock.json b/package-lock.json index 6aea2c6f..7b58dec9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,6 +95,7 @@ "zustand": "^3.6.9" }, "devDependencies": { + "@react-three/test-renderer": "^7.0.25", "@types/color": "^3.0.2", "@types/flexsearch": "^0.7.2", "@types/lodash.debounce": "^4.0.6", @@ -106,6 +107,7 @@ "autoprefixer": "^10.4.0", "daisyui": "^1.16.5", "hast-util-to-estree": "^2.0.2", + "jest-canvas-mock": "^2.3.1", "markdown-it": "^12.3.0", "postcss": "^8.4.5", "postcss-cli": "^9.1.0", @@ -4275,9 +4277,9 @@ } }, "node_modules/@react-three/fiber": { - "version": "7.0.25", - "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.25.tgz", - "integrity": "sha512-d4XudHlfSYhiMnA8E6HWK5UPr99SdQrg/wTNs2y/sjyqUMAa89WP62rsGUohGTN38qIk/c1DgaG/zSQKXEC6XA==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.26.tgz", + "integrity": "sha512-46NBais4fQIGcMGLBbOf84lp8y/cg73jOEVmAQQJqWX6iOVeNg29jYd15LBuCW2qPD1qDRU0rOfLbMDgwr/vxQ==", "dependencies": { "@babel/runtime": "^7.13.10", "react-merge-refs": "^1.1.0", @@ -4301,6 +4303,17 @@ } } }, + "node_modules/@react-three/test-renderer": { + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/@react-three/test-renderer/-/test-renderer-7.0.25.tgz", + "integrity": "sha512-Gdx9z58g907hj8dtGVAwxWegH++2t71fnHybvi7ia1SSo7J9dA0IoFJwDVIV3FljIfqc0Tf6OOVZ+fVRgnsT9g==", + "dev": true, + "peerDependencies": { + "@react-three/fiber": ">=7.0.26", + "react": ">=17.0", + "three": ">=0.126" + } + }, "node_modules/@rollup/pluginutils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", @@ -8560,6 +8573,12 @@ "node": ">=4" } }, + "node_modules/cssfontparser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", + "integrity": "sha1-9AIvyPlwDGgCnVQghK+69CWj8+M=", + "dev": true + }, "node_modules/cssom": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", @@ -14350,6 +14369,16 @@ } } }, + "node_modules/jest-canvas-mock": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.3.1.tgz", + "integrity": "sha512-5FnSZPrX3Q2ZfsbYNE3wqKR3+XorN8qFzDzB5o0golWgt6EOX1+emBnpOc9IAQ+NXFj8Nzm3h7ZdE/9H0ylBcg==", + "dev": true, + "dependencies": { + "cssfontparser": "^1.2.1", + "moo-color": "^1.0.2" + } + }, "node_modules/jest-changed-files": { "version": "27.4.2", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", @@ -18554,6 +18583,15 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz", "integrity": "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==" }, + "node_modules/moo-color": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.2.tgz", + "integrity": "sha512-5iXz5n9LWQzx/C2WesGFfpE6RLamzdHwsn3KpfzShwbfIqs7stnoEpaNErf/7+3mbxwZ4s8Foq7I0tPxw7BWHg==", + "dev": true, + "dependencies": { + "color-name": "^1.1.4" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -32163,9 +32201,9 @@ } }, "@react-three/fiber": { - "version": "7.0.25", - "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.25.tgz", - "integrity": "sha512-d4XudHlfSYhiMnA8E6HWK5UPr99SdQrg/wTNs2y/sjyqUMAa89WP62rsGUohGTN38qIk/c1DgaG/zSQKXEC6XA==", + "version": "7.0.26", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-7.0.26.tgz", + "integrity": "sha512-46NBais4fQIGcMGLBbOf84lp8y/cg73jOEVmAQQJqWX6iOVeNg29jYd15LBuCW2qPD1qDRU0rOfLbMDgwr/vxQ==", "requires": { "@babel/runtime": "^7.13.10", "react-merge-refs": "^1.1.0", @@ -32179,6 +32217,13 @@ "zustand": "^3.5.1" } }, + "@react-three/test-renderer": { + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/@react-three/test-renderer/-/test-renderer-7.0.25.tgz", + "integrity": "sha512-Gdx9z58g907hj8dtGVAwxWegH++2t71fnHybvi7ia1SSo7J9dA0IoFJwDVIV3FljIfqc0Tf6OOVZ+fVRgnsT9g==", + "dev": true, + "requires": {} + }, "@rollup/pluginutils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", @@ -34856,7 +34901,8 @@ "@msgpack/msgpack": "^2.7.1", "@react-three/drei": "^8.6.3", "@react-three/fiber": "^7.0.25", - "@seregpie/three.text-texture": "*", + "@react-three/test-renderer": "^7.0.25", + "@seregpie/three.text-texture": "^3.2.1", "@tailwindcss/typography": "^0.5.0", "@thorium-sim/react-mde": "^11.5.0", "@types/color": "^3.0.2", @@ -34878,6 +34924,7 @@ "gl-matrix": "^3.4.3", "gray-matter": "^4.0.3", "hast-util-to-estree": "^2.0.2", + "jest-canvas-mock": "*", "lodash.debounce": "^4.0.8", "lottie-web": "^5.8.1", "markdown-it": "^12.3.0", @@ -35832,6 +35879,12 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, + "cssfontparser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", + "integrity": "sha1-9AIvyPlwDGgCnVQghK+69CWj8+M=", + "dev": true + }, "cssom": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", @@ -40206,6 +40259,16 @@ "jest-cli": "^27.4.5" } }, + "jest-canvas-mock": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.3.1.tgz", + "integrity": "sha512-5FnSZPrX3Q2ZfsbYNE3wqKR3+XorN8qFzDzB5o0golWgt6EOX1+emBnpOc9IAQ+NXFj8Nzm3h7ZdE/9H0ylBcg==", + "dev": true, + "requires": { + "cssfontparser": "^1.2.1", + "moo-color": "^1.0.2" + } + }, "jest-changed-files": { "version": "27.4.2", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", @@ -43350,6 +43413,15 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz", "integrity": "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==" }, + "moo-color": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.2.tgz", + "integrity": "sha512-5iXz5n9LWQzx/C2WesGFfpE6RLamzdHwsn3KpfzShwbfIqs7stnoEpaNErf/7+3mbxwZ4s8Foq7I0tPxw7BWHg==", + "dev": true, + "requires": { + "color-name": "^1.1.4" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/server/src/inputs/__test__/solarSystemsPlugin.test.ts b/server/src/inputs/__test__/solarSystemsPlugin.test.ts index e9320248..7f2cd36b 100644 --- a/server/src/inputs/__test__/solarSystemsPlugin.test.ts +++ b/server/src/inputs/__test__/solarSystemsPlugin.test.ts @@ -99,6 +99,8 @@ describe("solar system plugin input", () => { ); }); afterAll(async () => { - await fs.rm("plugins", {recursive: true}); + try { + await fs.rm("plugins", {recursive: true}); + } catch {} }); }); diff --git a/test/jest.client.cjs b/test/jest.client.cjs index c97f707a..72a7bf14 100644 --- a/test/jest.client.cjs +++ b/test/jest.client.cjs @@ -4,6 +4,9 @@ module.exports = { displayName: "client", testEnvironment: "jest-environment-jsdom", coverageDirectory: path.join(__dirname, "../coverage/client"), - setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"], + setupFilesAfterEnv: [ + "@testing-library/jest-dom/extend-expect", + "jest-canvas-mock", + ], testMatch: ["**/client/src/**/*.test.{js,ts,jsx,tsx}"], }; From 10c71a3b5aba72c3840d9319dfb7eb97666fdd7d Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sat, 22 Jan 2022 11:19:48 -0500 Subject: [PATCH 4/7] feat(Star Map): Add backend and API for adding, updating, and deleting stars from solar systems. Closes #174 --- .../classes/Plugins/Universe/SolarSystem.ts | 4 + server/src/classes/Plugins/Universe/Star.ts | 90 +++++++++ server/src/components/satellite.ts | 43 ++++ .../__test__/solarSystemStarsPlugin.test.ts | 122 +++++++++++ .../__test__/solarSystemsPlugin.test.ts | 2 +- server/src/inputs/list.ts | 2 +- .../plugins/{ => universe}/solarSystems.ts | 2 +- server/src/inputs/plugins/universe/stars.ts | 190 ++++++++++++++++++ server/src/spawners/starTypes.ts | 106 ++++++++++ server/src/utils/getOrbitPosition.ts | 18 +- server/src/utils/randomFromRange.ts | 11 + server/src/utils/unitTypes.ts | 19 ++ 12 files changed, 597 insertions(+), 12 deletions(-) create mode 100644 server/src/classes/Plugins/Universe/Star.ts create mode 100644 server/src/components/satellite.ts create mode 100644 server/src/inputs/__test__/solarSystemStarsPlugin.test.ts rename server/src/inputs/plugins/{ => universe}/solarSystems.ts (98%) create mode 100644 server/src/inputs/plugins/universe/stars.ts create mode 100644 server/src/spawners/starTypes.ts create mode 100644 server/src/utils/randomFromRange.ts diff --git a/server/src/classes/Plugins/Universe/SolarSystem.ts b/server/src/classes/Plugins/Universe/SolarSystem.ts index 3b22da98..698ae1d3 100644 --- a/server/src/classes/Plugins/Universe/SolarSystem.ts +++ b/server/src/classes/Plugins/Universe/SolarSystem.ts @@ -5,6 +5,7 @@ import {randomFromList} from "server/src/utils/randomFromList"; import {AstronomicalUnit, LightMinute} from "server/src/utils/unitTypes"; import BasePlugin from ".."; import {Aspect} from "../Aspect"; +import StarPlugin from "./Star"; export default class SolarSystemPlugin extends Aspect { apiVersion = "solarSystem/v1" as const; @@ -35,6 +36,7 @@ export default class SolarSystemPlugin extends Aspect { * A string key that is used to procedurally generate the nebula skybox background in this system in the viewscreen. */ skyboxKey: string; + stars: StarPlugin[] = []; assets = {}; constructor(params: Partial, plugin: BasePlugin) { @@ -67,5 +69,7 @@ export default class SolarSystemPlugin extends Aspect { this.habitableZoneInner = params.habitableZoneInner || 0.9; this.habitableZoneOuter = params.habitableZoneOuter || 3.0; this.skyboxKey = params.skyboxKey || "Random Key"; + + this.stars = params.stars?.map(star => new StarPlugin(star, this)) ?? []; } } diff --git a/server/src/classes/Plugins/Universe/Star.ts b/server/src/classes/Plugins/Universe/Star.ts new file mode 100644 index 00000000..ca739552 --- /dev/null +++ b/server/src/classes/Plugins/Universe/Star.ts @@ -0,0 +1,90 @@ +import {SatelliteComponent} from "server/src/components/satellite"; +import {SpectralTypes, starTypes} from "server/src/spawners/starTypes"; +import { + Degree, + Kelvin, + SolarMass, + SolarRadius, + Year, +} from "server/src/utils/unitTypes"; +import type SolarSystemPlugin from "./SolarSystem"; + +const ALPHABET = "ABC"; + +export default class StarPlugin { + name: string; + description: string; + + tags: string[]; + + /** + * The mass of the star in comparison to the Sun + */ + solarMass: SolarMass; + + /** + * The age of the star in years + */ + age: Year; + + /** + * The spectral type of the star, one of O,B,G,K,A,MG,M,D + */ + spectralType: SpectralTypes; + + /** + * The color hue of the star, based on the spectral type + */ + hue: Degree; + + /** + * Whether the star appears to be white + */ + isWhite: boolean; + + /** + * The radius of the star compared to the radius of the Sun + */ + radius: SolarRadius; + + /** + * Temperature in Kelvin (K) + */ + temperature: Kelvin; + + satellite: Omit; + + constructor( + params: Partial< + Omit & { + satellite: Partial>; + } + >, + solarSystem: SolarSystemPlugin + ) { + this.name = + params.name || + `${solarSystem.name} ${ALPHABET[solarSystem.stars.length]}`; + this.description = params.description || ""; + this.tags = params.tags || []; + + this.solarMass = params.solarMass || 1; + this.age = params.age || 4000000000; + this.spectralType = params.spectralType || "G"; + this.hue = params.hue || 0; + this.isWhite = params.isWhite || false; + this.radius = params.radius || 1; + + this.temperature = params.temperature || 5800; + + this.satellite = { + axialTilt: params.satellite?.axialTilt || 0, + eccentricity: params.satellite?.eccentricity || 0, + inclination: params.satellite?.inclination || 0, + semiMajorAxis: params.satellite?.semiMajorAxis || 0, + orbitalArc: params.satellite?.orbitalArc || 0, + showOrbit: false, + parentId: solarSystem.name, + }; + } +} diff --git a/server/src/components/satellite.ts b/server/src/components/satellite.ts new file mode 100644 index 00000000..a78ad7e9 --- /dev/null +++ b/server/src/components/satellite.ts @@ -0,0 +1,43 @@ +import {Degree, Kilometer} from "../utils/unitTypes"; +import {Component} from "./utils"; + +export class SatelliteComponent extends Component { + static id = "satellite" as const; + /** + * The tilt of the axis of rotation in degrees + */ + axialTilt: Degree = 23.5; + + /** + * Orbital mechanics based on Keplerian Elements https://en.wikipedia.org/wiki/Orbital_elements#Keplerian_elements + * Check this page if you need a visualization https://ciechanow.ski/gps/ + * To simplify it, this doesn't include the Longitude of Ascending Node or the Argument of Periapsis, and + * True Anomaly is renamed to Orbital Arc to be a little easier to understand. + * Defaults based on Earth + */ + /** + * Distance from the center of the orbit to the furthest point + */ + semiMajorAxis: Kilometer = 149600000; + /** + * The shape of the orbit elliptical compared to a circle. 0 is a circular orbit. + */ + eccentricity: number = 0.01671022; + /** + * Vertical tilt of the orbit in degrees + */ + inclination: Degree = 0; + /** + * Angle where the object currently is in its orbit + */ + orbitalArc: Degree = 0; + /** + * Whether the orbit should be shown on the star map + */ + showOrbit: boolean = true; + + /** + * The ID of the parent object + */ + parentId?: string | null = null; +} diff --git a/server/src/inputs/__test__/solarSystemStarsPlugin.test.ts b/server/src/inputs/__test__/solarSystemStarsPlugin.test.ts new file mode 100644 index 00000000..272c60b0 --- /dev/null +++ b/server/src/inputs/__test__/solarSystemStarsPlugin.test.ts @@ -0,0 +1,122 @@ +import {starPluginInputs} from "../plugins/universe/stars"; +function createMockDataContext() { + const context = { + flight: null, + server: { + plugins: [ + { + id: "Test Plugin", + name: "Test Plugin", + active: true, + aspects: { + ships: [ + { + name: "Test Template", + }, + ], + solarSystems: [ + { + name: "Test System", + stars: [], + }, + ], + }, + }, + ], + }, + } as any; + + return context; +} + +describe("solar system star plugin input", () => { + it("should create a new star in the solar system", async () => { + const mockDataContext = createMockDataContext(); + + const system = mockDataContext.server.plugins[0].aspects.solarSystems[0]; + const star = starPluginInputs.pluginStarCreate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + spectralType: "G", + }); + + expect(system.stars.length).toBe(1); + expect(system.stars[0].spectralType).toBe("G"); + + expect(star.name).toBe("Test System A"); + expect(star.spectralType).toBe("G"); + }); + it("should adjust the orbital positions when there are two stars in the system", async () => { + const mockDataContext = createMockDataContext(); + + const system = mockDataContext.server.plugins[0].aspects.solarSystems[0]; + const star = starPluginInputs.pluginStarCreate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + spectralType: "G", + }); + + const {orbitalArc, semiMajorAxis} = star.satellite; + const star2 = starPluginInputs.pluginStarCreate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + spectralType: "O", + }); + + expect(system.stars.length).toBe(2); + expect(orbitalArc).toBe(star.satellite.orbitalArc); + expect(Math.round(star2.satellite.orbitalArc - orbitalArc)).toBe(180); + + expect(star.satellite.semiMajorAxis).toEqual(star2.satellite.semiMajorAxis); + expect(star.satellite.semiMajorAxis).toBeGreaterThan(0); + }); + it("should delete a system that has been created", () => { + const mockDataContext = createMockDataContext(); + + const system = mockDataContext.server.plugins[0].aspects.solarSystems[0]; + const star = starPluginInputs.pluginStarCreate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + spectralType: "G", + }); + + expect(system.stars.length).toBe(1); + + starPluginInputs.pluginStarDelete(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + starId: star.name, + }); + + expect(system.stars.length).toBe(0); + }); + it("should update properties of a star", () => { + const mockDataContext = createMockDataContext(); + + const system = mockDataContext.server.plugins[0].aspects.solarSystems[0]; + const star = starPluginInputs.pluginStarCreate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + spectralType: "G", + }); + + expect(system.stars.length).toBe(1); + expect(star.spectralType).toBe("G"); + + starPluginInputs.pluginStarUpdate(mockDataContext, { + pluginId: "Test Plugin", + solarSystemId: system.name, + starId: star.name, + temperature: 100, + age: 50, + name: "Test Star", + solarMass: 20, + }); + + expect(system.stars.length).toBe(1); + expect(star.temperature).toBe(100); + expect(star.age).toBe(50); + expect(star.name).toBe("Test Star"); + expect(star.solarMass).toBe(20); + }); +}); diff --git a/server/src/inputs/__test__/solarSystemsPlugin.test.ts b/server/src/inputs/__test__/solarSystemsPlugin.test.ts index 7f2cd36b..885821a8 100644 --- a/server/src/inputs/__test__/solarSystemsPlugin.test.ts +++ b/server/src/inputs/__test__/solarSystemsPlugin.test.ts @@ -1,4 +1,4 @@ -import {solarSystemsPluginInputs} from "../plugins/solarSystems"; +import {solarSystemsPluginInputs} from "../plugins/universe/solarSystems"; import {promises as fs} from "fs"; function createMockDataContext() { return { diff --git a/server/src/inputs/list.ts b/server/src/inputs/list.ts index 4c04ab23..602ec2ef 100644 --- a/server/src/inputs/list.ts +++ b/server/src/inputs/list.ts @@ -6,4 +6,4 @@ export {pluginInputs} from "./plugins"; export {shipsPluginInputs} from "./plugins/ships"; export {themesPluginInput} from "./plugins/themes"; export {officerLogInputs} from "./officersLog"; -export {solarSystemsPluginInputs} from "./plugins/solarSystems"; +export {solarSystemsPluginInputs} from "./plugins/universe/solarSystems"; diff --git a/server/src/inputs/plugins/solarSystems.ts b/server/src/inputs/plugins/universe/solarSystems.ts similarity index 98% rename from server/src/inputs/plugins/solarSystems.ts rename to server/src/inputs/plugins/universe/solarSystems.ts index b6a49b73..4fef2ede 100644 --- a/server/src/inputs/plugins/solarSystems.ts +++ b/server/src/inputs/plugins/universe/solarSystems.ts @@ -2,7 +2,7 @@ import SolarSystemPlugin from "server/src/classes/Plugins/Universe/SolarSystem"; import {DataContext} from "server/src/utils/DataContext"; import {pubsub} from "server/src/utils/pubsub"; import {AstronomicalUnit, LightMinute} from "server/src/utils/unitTypes"; -import {getPlugin} from "./utils"; +import {getPlugin} from "../utils"; export const solarSystemsPluginInputs = { pluginSolarSystemCreate( diff --git a/server/src/inputs/plugins/universe/stars.ts b/server/src/inputs/plugins/universe/stars.ts new file mode 100644 index 00000000..2bb31529 --- /dev/null +++ b/server/src/inputs/plugins/universe/stars.ts @@ -0,0 +1,190 @@ +import StarPlugin from "server/src/classes/Plugins/Universe/Star"; +import {SpectralTypes, starTypes} from "server/src/spawners/starTypes"; +import {DataContext} from "server/src/utils/DataContext"; +import {pubsub} from "server/src/utils/pubsub"; +import {randomFromRange} from "server/src/utils/randomFromRange"; +import {getPlugin} from "../utils"; + +function getSolarSystem( + context: DataContext, + pluginId: string, + solarSystemId: string +) { + const plugin = getPlugin(context, pluginId); + const solarSystem = plugin.aspects.solarSystems.find( + solarSystem => solarSystem.name === solarSystemId + ); + if (!solarSystem) { + throw new Error(`No solar system found with id ${solarSystemId}`); + } + return solarSystem; +} + +const ALPHABET = "ABC"; + +/** + * The distance between stars in the same system. + */ +const STAR_DISTANCE = 6; + +export const starPluginInputs = { + pluginStarCreate( + context: DataContext, + params: { + pluginId: string; + solarSystemId: string; + spectralType: SpectralTypes; + } + ) { + const solarSystem = getSolarSystem( + context, + params.pluginId, + params.solarSystemId + ); + const childrenStars = solarSystem.stars; + + const starType = starTypes.find( + s => s.spectralType === params.spectralType + ); + if (solarSystem.stars.length >= 3) { + throw new Error(`Only 3 stars are allowed`); + } + + if (!starType) { + throw new Error(`Invalid spectral type: ${params.spectralType}`); + } + + // Let's assume that there are fewer than 3 stars in the system. + const name = `${solarSystem.name} ${ALPHABET[solarSystem.stars.length]}`; + + const radius = randomFromRange(starType.radiusRange); + + // TODO January 21, 2022 Calculate the distance of the star for binary systems + let semiMajorAxis = 0; + let orbitalArc = Math.random() * 360; + if (childrenStars.length === 1) { + const otherStar = childrenStars[0]; + semiMajorAxis = (radius + (otherStar.radius || 0)) * STAR_DISTANCE; + orbitalArc = (otherStar.satellite?.orbitalArc || 0) + 180; + if (otherStar.satellite) { + otherStar.satellite.semiMajorAxis = semiMajorAxis; + } + } + if (childrenStars.length === 2) { + const star1 = childrenStars[0]; + const star2 = childrenStars[1]; + semiMajorAxis = + (radius + (star1.radius || 0) + (star2.radius || 0)) * STAR_DISTANCE; + orbitalArc = (star1.satellite?.orbitalArc || 0) + 120; + if (star1.satellite) { + star1.satellite.semiMajorAxis = semiMajorAxis; + } + if (star2.satellite) { + star2.satellite.orbitalArc = orbitalArc + 120; + star2.satellite.semiMajorAxis = semiMajorAxis; + } + } + + const star = new StarPlugin( + { + name, + spectralType: params.spectralType, + radius, + age: randomFromRange(starType.ageRange), + hue: randomFromRange(starType.hueRange), + isWhite: starType.white, + solarMass: randomFromRange(starType.solarMassRange), + temperature: randomFromRange(starType.temperatureRange), + satellite: { + orbitalArc, + semiMajorAxis, + }, + }, + solarSystem + ); + solarSystem.stars.push(star); + + pubsub.publish("pluginSolarSystem", { + pluginId: params.pluginId, + solarSystemId: solarSystem.name, + }); + + return star; + }, + pluginStarDelete( + context: DataContext, + params: { + pluginId: string; + solarSystemId: string; + starId: string; + } + ) { + const solarSystem = getSolarSystem( + context, + params.pluginId, + params.solarSystemId + ); + const star = solarSystem.stars.find(s => s.name === params.starId); + if (!star) { + throw new Error(`No star found with id ${params.starId}`); + } + solarSystem.stars = solarSystem.stars.filter(s => s !== star); + pubsub.publish("pluginSolarSystem", { + pluginId: params.pluginId, + solarSystemId: solarSystem.name, + }); + return star; + }, + + pluginStarUpdate( + context: DataContext, + params: { + pluginId: string; + solarSystemId: string; + starId: string; + name?: string; + radius?: number; + age?: number; + hue?: number; + isWhite?: boolean; + solarMass?: number; + temperature?: number; + } + ) { + const solarSystem = getSolarSystem( + context, + params.pluginId, + params.solarSystemId + ); + const star = solarSystem.stars.find(s => s.name === params.starId); + if (!star) { + throw new Error(`No star found with id ${params.starId}`); + } + if (params.name) { + star.name = params.name; + } + if (params.radius) { + star.radius = params.radius; + } + if (params.age) { + star.age = params.age; + } + if (params.hue) { + star.hue = params.hue; + } + if (params.isWhite !== undefined) { + star.isWhite = params.isWhite; + } + if (params.solarMass) { + star.solarMass = params.solarMass; + } + if (params.temperature) { + star.temperature = params.temperature; + } + pubsub.publish("pluginSolarSystem", { + pluginId: params.pluginId, + solarSystemId: solarSystem.name, + }); + return star; + }, +}; diff --git a/server/src/spawners/starTypes.ts b/server/src/spawners/starTypes.ts new file mode 100644 index 00000000..6af90707 --- /dev/null +++ b/server/src/spawners/starTypes.ts @@ -0,0 +1,106 @@ +import {Range} from "../utils/randomFromRange"; +import {Degree, Kelvin, SolarMass, SolarRadius, Year} from "../utils/unitTypes"; + +export type SpectralTypes = "O" | "B" | "G" | "K" | "A" | "MG" | "M" | "D"; + +interface StarType { + name: string; + spectralType: SpectralTypes; + /** + * The percentage of stars that are this type. + */ + prevalence: number; + /** + * Temperature of the star in Kelvin + */ + temperatureRange: Range; + /** + * Mass as compared to the Sun + */ + solarMassRange: Range; + /** + * Age of the star in years + */ + ageRange: Range; + + /** + * The radius range compared to the Sun + */ + radiusRange: Range; + hueRange: Range; + white?: boolean; +} + +export const starTypes: StarType[] = [ + { + name: "Blue", + spectralType: "B", + prevalence: 0.015, + temperatureRange: {min: 28000, max: 33000}, + solarMassRange: {min: 2.5, max: 90}, + ageRange: {min: 38000000, max: 42000000}, + radiusRange: {min: 2.7, max: 10}, + hueRange: {min: 195, max: 250}, + }, + { + name: "Blue Giant", + spectralType: "O", + prevalence: 0.015, + temperatureRange: {min: 10000, max: 50000}, + solarMassRange: {min: 20, max: 1000}, + ageRange: {min: 8000000, max: 12000000}, + radiusRange: {min: 18, max: 22}, + hueRange: {min: 220, max: 270}, + }, + { + name: "Red Giant", + spectralType: "MG", + prevalence: 0.06, + temperatureRange: {min: 3300, max: 5300}, + solarMassRange: {min: 0.3, max: 10}, + ageRange: {min: 100000000, max: 2000000000}, + radiusRange: {min: 20, max: 100}, + hueRange: {min: 0, max: 20}, + }, + { + name: "Yellow Dwarf", + spectralType: "G", + prevalence: 0.11, + temperatureRange: {min: 5200, max: 7500}, + solarMassRange: {min: 0.8, max: 1.4}, + ageRange: {min: 4000000000, max: 17000000000}, + radiusRange: {min: 0.9, max: 1.4}, + hueRange: {min: 40, max: 60}, + }, + { + name: "Orange Dwarf", + spectralType: "K", + prevalence: 0.12, + temperatureRange: {min: 3700, max: 5200}, + solarMassRange: {min: 0.45, max: 0.8}, + ageRange: {min: 15000000000, max: 30000000000}, + radiusRange: {min: 0.7, max: 0.9}, + hueRange: {min: 20, max: 40}, + }, + { + name: "White Dwarf", + spectralType: "D", + prevalence: 0.2, + temperatureRange: {min: 3300, max: 5300}, + solarMassRange: {min: 0.3, max: 10}, + ageRange: {min: 100000000, max: 2000000000}, + radiusRange: {min: 0.01, max: 0.04}, + hueRange: {min: 0, max: 20}, + white: true, + }, + { + name: "Red Dwarf", + spectralType: "M", + prevalence: 0.5, + temperatureRange: {min: 8000, max: 40000}, + solarMassRange: {min: 0.1, max: 1.4}, + ageRange: {min: 100000, max: 10000000000}, + radiusRange: {min: 0.008, max: 0.2}, + hueRange: {min: 0, max: 1}, + }, +]; diff --git a/server/src/utils/getOrbitPosition.ts b/server/src/utils/getOrbitPosition.ts index 69ac050c..d8a36410 100644 --- a/server/src/utils/getOrbitPosition.ts +++ b/server/src/utils/getOrbitPosition.ts @@ -1,29 +1,29 @@ import {Vector3} from "three"; -export const DEG_TO_RAD = Math.PI / 180; +import {degToRad} from "./unitTypes"; const axis = new Vector3(0, 0, 1); export function getOrbitPosition({ - radius, + semiMajorAxis, eccentricity, orbitalArc, - orbitalInclination, + inclination, origin = new Vector3(), }: OrbitPositionProps) { - const radiusY = radius - radius * eccentricity; - const X = radius * Math.cos(DEG_TO_RAD * orbitalArc); - const Z = radiusY * Math.sin(DEG_TO_RAD * orbitalArc); + const radiusY = semiMajorAxis - semiMajorAxis * eccentricity; + const X = semiMajorAxis * Math.cos(degToRad(orbitalArc)); + const Z = radiusY * Math.sin(degToRad(orbitalArc)); const vec = new Vector3(X, 0, Z); - const angle = orbitalInclination * DEG_TO_RAD; + const angle = degToRad(inclination); vec.applyAxisAngle(axis, angle).add(origin); return vec; } interface OrbitPositionProps { - radius: number; + semiMajorAxis: number; eccentricity: number; orbitalArc: number; - orbitalInclination: number; + inclination: number; origin?: Vector3; } diff --git a/server/src/utils/randomFromRange.ts b/server/src/utils/randomFromRange.ts new file mode 100644 index 00000000..a953bb4b --- /dev/null +++ b/server/src/utils/randomFromRange.ts @@ -0,0 +1,11 @@ +export function randomFromRange( + {min, max}: Range, + precision: number = 5 +): number { + return ( + Math.round((Math.random() * (max - min) + min) * Math.pow(10, precision)) / + Math.pow(10, precision) + ); +} + +export type Range = {min: Type; max: Type}; diff --git a/server/src/utils/unitTypes.ts b/server/src/utils/unitTypes.ts index ca1b0f9c..e1a105be 100644 --- a/server/src/utils/unitTypes.ts +++ b/server/src/utils/unitTypes.ts @@ -6,6 +6,10 @@ export type Flavor = T & Flavoring; export type Kilometer = Flavor; export type Meter = Flavor; export type Centimeter = Flavor; +/** + * Distance compared to the radius of the sun eg. 1 solar radius = the radius of the sun + */ +export type SolarRadius = Flavor; export type AstronomicalUnit = Flavor; export type LightYear = Flavor; @@ -19,3 +23,18 @@ export function lightYearToLightMinute(len: LightYear) { } export type Kilograms = Flavor; +/** + * Mass compared to the sun eg. 1 solar mass = the mass of the sun + */ +export type SolarMass = Flavor; + +export type Kelvin = Flavor; + +export type Year = Flavor; + +export type Degree = Flavor; +export type Radian = Flavor; + +export function degToRad(degree: Degree): Radian { + return (degree * Math.PI) / 180; +} From 0735e4fab2c3074f7879fa1044b3da2eb0bed905 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Wed, 26 Jan 2022 10:52:20 -0500 Subject: [PATCH 5/7] Added a small segment to the plugin docs to explain how they are added before flights. --- client/src/docs/Plugins/plugins.mdx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/docs/Plugins/plugins.mdx b/client/src/docs/Plugins/plugins.mdx index 268fb91c..e242a79b 100644 --- a/client/src/docs/Plugins/plugins.mdx +++ b/client/src/docs/Plugins/plugins.mdx @@ -9,14 +9,15 @@ order: 1 Plugins are wrappers around all the things that can be configured in Thorium Nova, and all of these things can be edited from within Thorium Nova. These -include: +include different "Aspects", which are the parts of Thorium Nova that the plugin +affects. These include: - Custom themes for the controls - UI sound packs that play when clicking on buttons and using the controls - Ships which fly around the 3D Starmap - Ship systems, like engines or weapons, which are a part of these ships - Inventory on the ship, like probe casings, coolant, and repair supplies -- Planetary systems, stars, and planets in the Starmap +- Solar systems, stars, and planets in the Starmap - Factions, or organizations which control the planets and solar systems and define the behavior of ships. - Campaigns, Mission storylines, and timelines, including any visuals and @@ -25,6 +26,11 @@ include: This also includes all of the assets and files which are used by these plugins, such as images, 3D models, and sounds. +Plugins are intended to be modular, where a Flight Director can choose to add or +remove plugins _before_ starting a flight to adjust what is possible during the +flight. Currently, it isn't possible to add or remove plugins after a flight has +started. + ## Plugin Config Plugins can easily be created from within Thorium Nova. On the From e4090c8621e00c804fd274f7f4b9175bd9545760 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Thu, 3 Feb 2022 08:18:47 -0500 Subject: [PATCH 6/7] Fix ESLint Errors --- client/src/components/Starmap/SystemMarker/SystemCircle.tsx | 2 +- client/src/components/Starmap/SystemMarker/SystemLabel.tsx | 1 - client/src/context/useNetRequest.ts | 5 ++--- client/src/pages/Config/Starmap/index.tsx | 4 ++-- server/src/spawners/systemNames.ts | 4 +++- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/components/Starmap/SystemMarker/SystemCircle.tsx b/client/src/components/Starmap/SystemMarker/SystemCircle.tsx index 6536e029..6f60adf6 100644 --- a/client/src/components/Starmap/SystemMarker/SystemCircle.tsx +++ b/client/src/components/Starmap/SystemMarker/SystemCircle.tsx @@ -80,7 +80,7 @@ const SystemCircle: React.FC< canvas.height = size; canvas.width = size; - var ctx = canvas.getContext("2d") as CanvasRenderingContext2D; + const ctx = canvas.getContext("2d") as CanvasRenderingContext2D; return ctx; }, []); diff --git a/client/src/components/Starmap/SystemMarker/SystemLabel.tsx b/client/src/components/Starmap/SystemMarker/SystemLabel.tsx index f7c3c126..94060ec7 100644 --- a/client/src/components/Starmap/SystemMarker/SystemLabel.tsx +++ b/client/src/components/Starmap/SystemMarker/SystemLabel.tsx @@ -1,5 +1,4 @@ import React from "react"; -// @ts-ignore import TextTexture from "@seregpie/three.text-texture"; import {AdditiveBlending, Sprite} from "three"; import {useFrame} from "@react-three/fiber"; diff --git a/client/src/context/useNetRequest.ts b/client/src/context/useNetRequest.ts index 6e4d6e38..10ad6b9b 100644 --- a/client/src/context/useNetRequest.ts +++ b/client/src/context/useNetRequest.ts @@ -9,7 +9,6 @@ import { useState, } from "react"; import { - AllRequests, AllRequestNames, AllRequestParams, AllRequestReturns, @@ -153,7 +152,7 @@ export function useNetRequest< return () => { socket.off("ready", handleReady); }; - }, [socket, requestId, data]); + }, [socket, requestId, data, mockData]); useEffect(() => { if (mockData) return; @@ -161,7 +160,7 @@ export function useNetRequest< return () => { takeDownRequest(hookId); }; - }, [setUpRequest, takeDownRequest, ready, hookId, requestId]); + }, [setUpRequest, takeDownRequest, ready, hookId, requestId, mockData]); const callbackRef = useRef(callback); useEffect(() => { diff --git a/client/src/pages/Config/Starmap/index.tsx b/client/src/pages/Config/Starmap/index.tsx index 0f1383a8..cedc475e 100644 --- a/client/src/pages/Config/Starmap/index.tsx +++ b/client/src/pages/Config/Starmap/index.tsx @@ -58,7 +58,7 @@ function useSynchronizeSystemId() { navigate(`/config/${pluginId}/starmap`); useStarmapStore.setState({systemId: null}); } - }, [storedSystemId]); + }, [storedSystemId, navigate, pluginId]); useEffect(() => { mounted.current = true; }, []); @@ -237,7 +237,7 @@ function SolarSystemMap() { ); } -const StarmapScene = forwardRef((props, ref) => { +const StarmapScene = forwardRef(function StarmapScene(props, ref) { const pluginId = useStarmapStore(s => s.pluginId); const systemId = useStarmapStore(s => s.systemId); diff --git a/server/src/spawners/systemNames.ts b/server/src/spawners/systemNames.ts index 12302a6e..1a64e7f8 100644 --- a/server/src/spawners/systemNames.ts +++ b/server/src/spawners/systemNames.ts @@ -1,5 +1,5 @@ // System names from Endless Sky and Ur Quan Masters -export default [ +const SystemNames = [ "Ablodab", "Ablub", "Acamar", @@ -859,3 +859,5 @@ export default [ "Beeblebrox", "Mendon", ]; + +export default SystemNames; From fff63a4985f3a66677b33990cd44934173f139d1 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Fri, 4 Feb 2022 18:59:08 -0500 Subject: [PATCH 7/7] Test fix --- client/src/pages/Config/Starmap/index.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/pages/Config/Starmap/index.test.tsx b/client/src/pages/Config/Starmap/index.test.tsx index ec411a8f..33dbab7a 100644 --- a/client/src/pages/Config/Starmap/index.test.tsx +++ b/client/src/pages/Config/Starmap/index.test.tsx @@ -30,7 +30,7 @@ describe("Starmap Plugin Editor", () => { ); // Stars, the solar system, and the camera - expect(renderer.scene.allChildren.length).toBe(3); + expect(renderer.scene.allChildren.length).toBe(2); expect(renderer.scene.findByType("Group").props.position).toEqual([ 10, 20, 30, ]); @@ -67,6 +67,6 @@ describe("Starmap Plugin Editor", () => { ); // Stars, the solar system, and the camera - expect(renderer.scene.allChildren.length).toBe(5); + expect(renderer.scene.allChildren.length).toBe(4); }); });