├── server
├── .gitignore
├── package.json
├── default.json
├── index.js
└── yarn.lock
├── .DS_Store
├── client
├── public
│ ├── favicon.ico
│ ├── models
│ │ ├── Tablet.glb
│ │ ├── Skyscraper.glb
│ │ └── items
│ │ │ ├── bear.glb
│ │ │ ├── bench.glb
│ │ │ ├── chair.glb
│ │ │ ├── desk.glb
│ │ │ ├── dryer.glb
│ │ │ ├── laptop.glb
│ │ │ ├── plant.glb
│ │ │ ├── radio.glb
│ │ │ ├── table.glb
│ │ │ ├── washer.glb
│ │ │ ├── bathtub.glb
│ │ │ ├── rugRound.glb
│ │ │ ├── speaker.glb
│ │ │ ├── stoolBar.glb
│ │ │ ├── toaster.glb
│ │ │ ├── trashcan.glb
│ │ │ ├── bedDouble.glb
│ │ │ ├── bedSingle.glb
│ │ │ ├── kitchenBar.glb
│ │ │ ├── kitchenSink.glb
│ │ │ ├── loungeChair.glb
│ │ │ ├── loungeSofa.glb
│ │ │ ├── plantSmall.glb
│ │ │ ├── rugRounded.glb
│ │ │ ├── rugSquare.glb
│ │ │ ├── showerRound.glb
│ │ │ ├── tableCoffee.glb
│ │ │ ├── bathroomSink.glb
│ │ │ ├── chairCushion.glb
│ │ │ ├── chairRounded.glb
│ │ │ ├── deskComputer.glb
│ │ │ ├── kitchenFridge.glb
│ │ │ ├── kitchenStove.glb
│ │ │ ├── rugRectangle.glb
│ │ │ ├── speakerSmall.glb
│ │ │ ├── toiletSquare.glb
│ │ │ ├── bathroomCabinet.glb
│ │ │ ├── bathroomMirror.glb
│ │ │ ├── benchCushionLow.glb
│ │ │ ├── bookcaseOpenLow.glb
│ │ │ ├── cabinetBedDrawer.glb
│ │ │ ├── coatRackStanding.glb
│ │ │ ├── kitchenBlender.glb
│ │ │ ├── kitchenCabinet.glb
│ │ │ ├── kitchenMicrowave.glb
│ │ │ ├── lampRoundFloor.glb
│ │ │ ├── lampRoundTable.glb
│ │ │ ├── lampSquareFloor.glb
│ │ │ ├── lampSquareTable.glb
│ │ │ ├── loungeDesignSofa.glb
│ │ │ ├── loungeSofaCorner.glb
│ │ │ ├── stoolBarSquare.glb
│ │ │ ├── tableCrossCloth.glb
│ │ │ ├── televisionModern.glb
│ │ │ ├── bookcaseClosedWide.glb
│ │ │ ├── cardboardBoxClosed.glb
│ │ │ ├── chairModernCushion.glb
│ │ │ ├── kitchenFridgeLarge.glb
│ │ │ ├── loungeSofaOttoman.glb
│ │ │ ├── televisionVintage.glb
│ │ │ ├── bathroomCabinetDrawer.glb
│ │ │ ├── cabinetBedDrawerTable.glb
│ │ │ ├── chairModernFrameCushion.glb
│ │ │ ├── loungeDesignSofaCorner.glb
│ │ │ ├── tableCoffeeGlassSquare.glb
│ │ │ ├── kitchenCabinetCornerInner.glb
│ │ │ └── kitchenCabinetCornerRound.glb
│ ├── animations
│ │ ├── M_Walk_001.glb
│ │ ├── M_Dances_001.glb
│ │ ├── M_Standing_Idle_001.glb
│ │ └── M_Standing_Expressions_001.glb
│ ├── textures
│ │ └── venice_sunset_1k.hdr
│ └── fonts
│ │ └── Inter_Bold.json
├── postcss.config.js
├── vite.config.js
├── README.md
├── src
│ ├── main.jsx
│ ├── index.css
│ ├── hooks
│ │ └── useGrid.jsx
│ ├── components
│ │ ├── Loader.jsx
│ │ ├── Skyscraper.jsx
│ │ ├── LobbyAvatar.jsx
│ │ ├── Tablet.jsx
│ │ ├── Item.jsx
│ │ ├── Shop.jsx
│ │ ├── SocketManager.jsx
│ │ ├── Experience.jsx
│ │ ├── Lobby.jsx
│ │ ├── Avatar.jsx
│ │ ├── Room.jsx
│ │ └── UI.jsx
│ ├── App.jsx
│ └── assets
│ │ └── react.svg
├── tailwind.config.js
├── .gitignore
├── index.html
└── package.json
└── README.md
/server/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | rooms.json
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/.DS_Store
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/client/public/models/Tablet.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/Tablet.glb
--------------------------------------------------------------------------------
/client/public/models/Skyscraper.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/Skyscraper.glb
--------------------------------------------------------------------------------
/client/public/models/items/bear.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bear.glb
--------------------------------------------------------------------------------
/client/public/models/items/bench.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bench.glb
--------------------------------------------------------------------------------
/client/public/models/items/chair.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/chair.glb
--------------------------------------------------------------------------------
/client/public/models/items/desk.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/desk.glb
--------------------------------------------------------------------------------
/client/public/models/items/dryer.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/dryer.glb
--------------------------------------------------------------------------------
/client/public/models/items/laptop.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/laptop.glb
--------------------------------------------------------------------------------
/client/public/models/items/plant.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/plant.glb
--------------------------------------------------------------------------------
/client/public/models/items/radio.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/radio.glb
--------------------------------------------------------------------------------
/client/public/models/items/table.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/table.glb
--------------------------------------------------------------------------------
/client/public/models/items/washer.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/washer.glb
--------------------------------------------------------------------------------
/client/public/animations/M_Walk_001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/animations/M_Walk_001.glb
--------------------------------------------------------------------------------
/client/public/models/items/bathtub.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bathtub.glb
--------------------------------------------------------------------------------
/client/public/models/items/rugRound.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/rugRound.glb
--------------------------------------------------------------------------------
/client/public/models/items/speaker.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/speaker.glb
--------------------------------------------------------------------------------
/client/public/models/items/stoolBar.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/stoolBar.glb
--------------------------------------------------------------------------------
/client/public/models/items/toaster.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/toaster.glb
--------------------------------------------------------------------------------
/client/public/models/items/trashcan.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/trashcan.glb
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | [Video tutorial](https://youtu.be/73XOJlLhhZg)
4 |
--------------------------------------------------------------------------------
/client/public/animations/M_Dances_001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/animations/M_Dances_001.glb
--------------------------------------------------------------------------------
/client/public/models/items/bedDouble.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bedDouble.glb
--------------------------------------------------------------------------------
/client/public/models/items/bedSingle.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bedSingle.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenBar.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenBar.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenSink.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenSink.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeChair.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeChair.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeSofa.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeSofa.glb
--------------------------------------------------------------------------------
/client/public/models/items/plantSmall.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/plantSmall.glb
--------------------------------------------------------------------------------
/client/public/models/items/rugRounded.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/rugRounded.glb
--------------------------------------------------------------------------------
/client/public/models/items/rugSquare.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/rugSquare.glb
--------------------------------------------------------------------------------
/client/public/models/items/showerRound.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/showerRound.glb
--------------------------------------------------------------------------------
/client/public/models/items/tableCoffee.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/tableCoffee.glb
--------------------------------------------------------------------------------
/client/public/models/items/bathroomSink.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bathroomSink.glb
--------------------------------------------------------------------------------
/client/public/models/items/chairCushion.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/chairCushion.glb
--------------------------------------------------------------------------------
/client/public/models/items/chairRounded.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/chairRounded.glb
--------------------------------------------------------------------------------
/client/public/models/items/deskComputer.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/deskComputer.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenFridge.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenFridge.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenStove.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenStove.glb
--------------------------------------------------------------------------------
/client/public/models/items/rugRectangle.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/rugRectangle.glb
--------------------------------------------------------------------------------
/client/public/models/items/speakerSmall.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/speakerSmall.glb
--------------------------------------------------------------------------------
/client/public/models/items/toiletSquare.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/toiletSquare.glb
--------------------------------------------------------------------------------
/client/public/textures/venice_sunset_1k.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/textures/venice_sunset_1k.hdr
--------------------------------------------------------------------------------
/client/public/models/items/bathroomCabinet.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bathroomCabinet.glb
--------------------------------------------------------------------------------
/client/public/models/items/bathroomMirror.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bathroomMirror.glb
--------------------------------------------------------------------------------
/client/public/models/items/benchCushionLow.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/benchCushionLow.glb
--------------------------------------------------------------------------------
/client/public/models/items/bookcaseOpenLow.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bookcaseOpenLow.glb
--------------------------------------------------------------------------------
/client/public/models/items/cabinetBedDrawer.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/cabinetBedDrawer.glb
--------------------------------------------------------------------------------
/client/public/models/items/coatRackStanding.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/coatRackStanding.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenBlender.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenBlender.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenCabinet.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenCabinet.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenMicrowave.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenMicrowave.glb
--------------------------------------------------------------------------------
/client/public/models/items/lampRoundFloor.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/lampRoundFloor.glb
--------------------------------------------------------------------------------
/client/public/models/items/lampRoundTable.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/lampRoundTable.glb
--------------------------------------------------------------------------------
/client/public/models/items/lampSquareFloor.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/lampSquareFloor.glb
--------------------------------------------------------------------------------
/client/public/models/items/lampSquareTable.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/lampSquareTable.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeDesignSofa.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeDesignSofa.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeSofaCorner.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeSofaCorner.glb
--------------------------------------------------------------------------------
/client/public/models/items/stoolBarSquare.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/stoolBarSquare.glb
--------------------------------------------------------------------------------
/client/public/models/items/tableCrossCloth.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/tableCrossCloth.glb
--------------------------------------------------------------------------------
/client/public/models/items/televisionModern.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/televisionModern.glb
--------------------------------------------------------------------------------
/client/public/animations/M_Standing_Idle_001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/animations/M_Standing_Idle_001.glb
--------------------------------------------------------------------------------
/client/public/models/items/bookcaseClosedWide.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bookcaseClosedWide.glb
--------------------------------------------------------------------------------
/client/public/models/items/cardboardBoxClosed.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/cardboardBoxClosed.glb
--------------------------------------------------------------------------------
/client/public/models/items/chairModernCushion.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/chairModernCushion.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenFridgeLarge.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenFridgeLarge.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeSofaOttoman.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeSofaOttoman.glb
--------------------------------------------------------------------------------
/client/public/models/items/televisionVintage.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/televisionVintage.glb
--------------------------------------------------------------------------------
/client/public/models/items/bathroomCabinetDrawer.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/bathroomCabinetDrawer.glb
--------------------------------------------------------------------------------
/client/public/models/items/cabinetBedDrawerTable.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/cabinetBedDrawerTable.glb
--------------------------------------------------------------------------------
/client/public/models/items/chairModernFrameCushion.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/chairModernFrameCushion.glb
--------------------------------------------------------------------------------
/client/public/models/items/loungeDesignSofaCorner.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/loungeDesignSofaCorner.glb
--------------------------------------------------------------------------------
/client/public/models/items/tableCoffeeGlassSquare.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/tableCoffeeGlassSquare.glb
--------------------------------------------------------------------------------
/client/public/animations/M_Standing_Expressions_001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/animations/M_Standing_Expressions_001.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenCabinetCornerInner.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenCabinetCornerInner.glb
--------------------------------------------------------------------------------
/client/public/models/items/kitchenCabinetCornerRound.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wass08/r3f-sims-online-final/HEAD/client/public/models/items/kitchenCabinetCornerRound.glb
--------------------------------------------------------------------------------
/client/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # r3f-vite-starter
2 | A boilerplate to build R3F projects
3 |
4 | ```
5 | yarn
6 | yarn dev
7 | ```
8 |
9 |
10 | 
11 |
--------------------------------------------------------------------------------
/client/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/client/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | fontFamily: {
6 | sans: ["Poppins", "sans-serif"],
7 | },
8 | extend: {},
9 | },
10 | plugins: [],
11 | };
12 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "scripts": {
4 | "dev": "nodemon index.js --ignore '*.json'",
5 | "start": "NODE_ENV=production node index.js"
6 | },
7 | "dependencies": {
8 | "pathfinding": "^0.4.18",
9 | "socket.io": "^4.7.2"
10 | },
11 | "devDependencies": {
12 | "nodemon": "^3.0.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap");
2 |
3 | @tailwind base;
4 | @tailwind components;
5 | @tailwind utilities;
6 |
7 | html,
8 | body {
9 | width: 100%;
10 | height: 100%;
11 | }
12 | #root {
13 | width: 100%;
14 | height: 100%;
15 | will-change: transform;
16 | }
17 |
18 | body {
19 | margin: 0;
20 | }
21 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Wawa Hotel
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/client/src/hooks/useGrid.jsx:
--------------------------------------------------------------------------------
1 | import { useAtom } from "jotai";
2 | import { mapAtom } from "../components/SocketManager";
3 |
4 | import * as THREE from "three";
5 |
6 | export const useGrid = () => {
7 | const [map] = useAtom(mapAtom);
8 |
9 | const vector3ToGrid = (vector3) => {
10 | return [
11 | Math.floor(vector3.x * map.gridDivision),
12 | Math.floor(vector3.z * map.gridDivision),
13 | ];
14 | };
15 |
16 | const gridToVector3 = (gridPosition, width = 1, height = 1) => {
17 | return new THREE.Vector3(
18 | width / map.gridDivision / 2 + gridPosition[0] / map.gridDivision,
19 | 0,
20 | height / map.gridDivision / 2 + gridPosition[1] / map.gridDivision
21 | );
22 | };
23 |
24 | return {
25 | vector3ToGrid,
26 | gridToVector3,
27 | };
28 | };
29 |
--------------------------------------------------------------------------------
/client/src/components/Loader.jsx:
--------------------------------------------------------------------------------
1 | import { useProgress } from "@react-three/drei";
2 | import { useAtom } from "jotai";
3 | import { itemsAtom } from "./SocketManager";
4 |
5 | export const Loader = ({ loaded }) => {
6 | const { progress } = useProgress();
7 | const [items] = useAtom(itemsAtom);
8 | return (
9 |
10 |
15 |
WAWA MANSION
16 |
22 | {progress < 100 &&
Loading resources...
}
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "r3f-vite-starter",
3 | "private": true,
4 | "version": "1.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@react-three/drei": "9.75.0",
13 | "@react-three/fiber": "8.13.3",
14 | "@react-three/postprocessing": "^2.15.1",
15 | "@readyplayerme/react-avatar-creator": "^0.3.0",
16 | "@types/three": "0.152.1",
17 | "autoprefixer": "^10.4.15",
18 | "framer-motion": "^10.16.4",
19 | "framer-motion-3d": "^10.16.4",
20 | "jotai": "^2.2.3",
21 | "lodash": "^4.17.21",
22 | "postcss": "^8.4.28",
23 | "react": "^18.2.0",
24 | "react-dom": "^18.2.0",
25 | "socket.io-client": "^4.7.2",
26 | "three": "0.153.0",
27 | "three-stdlib": "^2.24.1"
28 | },
29 | "devDependencies": {
30 | "@types/react": "^18.0.27",
31 | "@types/react-dom": "^18.0.10",
32 | "@vitejs/plugin-react": "^3.1.0",
33 | "tailwindcss": "^3.3.3",
34 | "vite": "^4.1.0"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/client/src/components/Skyscraper.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | Command: npx gltfjsx@6.2.3 public/models/Skyscraper.glb -o src/components/Skyscraper.jsx -r public
4 | */
5 |
6 | import { useGLTF } from "@react-three/drei";
7 | import React from "react";
8 |
9 | export function Skyscraper(props) {
10 | const { nodes, materials } = useGLTF("/models/Skyscraper.glb");
11 | return (
12 |
13 |
18 |
23 |
28 |
33 |
38 |
43 |
44 | );
45 | }
46 |
47 | useGLTF.preload("/models/Skyscraper.glb");
48 |
--------------------------------------------------------------------------------
/client/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { Canvas } from "@react-three/fiber";
2 | // import { EffectComposer, N8AO } from "@react-three/postprocessing";
3 | import { ScrollControls, useProgress } from "@react-three/drei";
4 | import { useAtom } from "jotai";
5 | import { useEffect, useState } from "react";
6 | import { Experience } from "./components/Experience";
7 | import { Loader } from "./components/Loader";
8 | import {
9 | SocketManager,
10 | itemsAtom,
11 | roomIDAtom,
12 | } from "./components/SocketManager";
13 | import { UI } from "./components/UI";
14 |
15 | function App() {
16 | const [roomID] = useAtom(roomIDAtom);
17 |
18 | const { progress } = useProgress();
19 | const [loaded, setLoaded] = useState(false);
20 | const [items] = useAtom(itemsAtom);
21 |
22 | useEffect(() => {
23 | if (progress === 100 && items) {
24 | setLoaded(true); // As progress can go back to 0 when new resources are loaded, we need to make sure we don't fade out the UI when that happens
25 | }
26 | }, [progress]);
27 | return (
28 | <>
29 |
30 |
46 |
47 | {loaded && }
48 | >
49 | );
50 | }
51 |
52 | export default App;
53 |
--------------------------------------------------------------------------------
/client/src/components/LobbyAvatar.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | Command: npx gltfjsx@6.2.3 public/models/Animated Woman.glb -o src/components/AnimatedWoman.jsx -r public
4 | */
5 |
6 | import { useAnimations, useGLTF } from "@react-three/drei";
7 | import { useAtom } from "jotai";
8 | import React, { useEffect, useRef, useState } from "react";
9 | import { avatarUrlAtom } from "./UI";
10 |
11 | export function LobbyAvatar({ ...props }) {
12 | const [avatarUrl] = useAtom(avatarUrlAtom);
13 | const avatar = useRef();
14 | const group = useRef();
15 | const { scene } = useGLTF(avatarUrl);
16 |
17 | const { animations: waveAnimation } = useGLTF(
18 | "/animations/M_Standing_Expressions_001.glb"
19 | );
20 | const { animations: idleAnimation } = useGLTF(
21 | "/animations/M_Standing_Idle_001.glb"
22 | );
23 |
24 | const { actions } = useAnimations(
25 | [waveAnimation[0], idleAnimation[0]],
26 | avatar
27 | );
28 | const [animation, setAnimation] = useState("M_Standing_Idle_001");
29 | const [init, setInit] = useState(avatarUrl);
30 |
31 | useEffect(() => {
32 | actions[animation]
33 | .reset()
34 | .fadeIn(init === avatarUrl ? 0.32 : 0)
35 | .play();
36 | setInit(avatarUrl);
37 | return () => actions[animation]?.fadeOut(0.32);
38 | }, [animation, avatarUrl]);
39 |
40 | const delayWave = (delay) => {
41 | setTimeout(() => {
42 | setAnimation("M_Standing_Expressions_001");
43 | setTimeout(() => {
44 | setAnimation("M_Standing_Idle_001");
45 | delayWave(3000);
46 | }, 6000);
47 | }, delay);
48 | };
49 |
50 | useEffect(() => {
51 | delayWave(12);
52 | }, []);
53 |
54 | return (
55 |
56 |
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/client/src/components/Tablet.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | Command: npx gltfjsx@6.2.3 public/models/Tablet.glb -o src/components/Tablet.jsx -r public
4 | */
5 |
6 | import { useGLTF } from "@react-three/drei";
7 | import React from "react";
8 |
9 | export function Tablet(props) {
10 | const { nodes, materials } = useGLTF("/models/Tablet.glb");
11 | return (
12 |
13 |
17 |
21 |
25 |
29 |
33 |
37 |
41 |
45 |
49 |
53 |
57 |
61 |
65 |
66 | );
67 | }
68 |
69 | useGLTF.preload("/models/Tablet.glb");
70 |
--------------------------------------------------------------------------------
/client/src/components/Item.jsx:
--------------------------------------------------------------------------------
1 | import { useCursor, useGLTF } from "@react-three/drei";
2 | import { useAtom } from "jotai";
3 | import { useEffect, useMemo, useState } from "react";
4 | import { SkeletonUtils } from "three-stdlib";
5 | import { useGrid } from "../hooks/useGrid";
6 | import { mapAtom } from "./SocketManager";
7 | import { buildModeAtom } from "./UI";
8 |
9 | export const Item = ({
10 | item,
11 | onClick,
12 | isDragging,
13 | dragPosition,
14 | canDrop,
15 | dragRotation,
16 | }) => {
17 | const { name, gridPosition, size, rotation: itemRotation } = item;
18 |
19 | const rotation = isDragging ? dragRotation : itemRotation;
20 | const { gridToVector3 } = useGrid();
21 | const [map] = useAtom(mapAtom);
22 | const { scene } = useGLTF(`/models/items/${name}.glb`);
23 | // Skinned meshes cannot be re-used in threejs without cloning them
24 | const clone = useMemo(() => SkeletonUtils.clone(scene), [scene]);
25 | const width = rotation === 1 || rotation === 3 ? size[1] : size[0];
26 | const height = rotation === 1 || rotation === 3 ? size[0] : size[1];
27 | const [hover, setHover] = useState(false);
28 | const [buildMode] = useAtom(buildModeAtom);
29 | useCursor(buildMode ? hover : undefined);
30 |
31 | useEffect(() => {
32 | clone.traverse((child) => {
33 | if (child.isMesh) {
34 | child.castShadow = true;
35 | child.receiveShadow = true;
36 | }
37 | });
38 | }, []);
39 |
40 | return (
41 | setHover(true)}
49 | onPointerLeave={() => setHover(false)}
50 | >
51 |
52 | {isDragging && (
53 |
54 |
57 |
62 |
63 | )}
64 |
65 | );
66 | };
67 |
--------------------------------------------------------------------------------
/client/src/components/Shop.jsx:
--------------------------------------------------------------------------------
1 | import { useCursor, useGLTF, useScroll } from "@react-three/drei";
2 | import { useFrame } from "@react-three/fiber";
3 | import { useAtom } from "jotai";
4 | import { useMemo, useRef, useState } from "react";
5 | import { SkeletonUtils } from "three-stdlib";
6 | import { useGrid } from "../hooks/useGrid";
7 | import { itemsAtom, mapAtom } from "./SocketManager";
8 |
9 | const ShopItem = ({ item, ...props }) => {
10 | const { name, size, rotation } = item;
11 | const { scene } = useGLTF(`/models/items/${name}.glb`);
12 | // Skinned meshes cannot be re-used in threejs without cloning them
13 | const clone = useMemo(() => SkeletonUtils.clone(scene), [scene]);
14 | const { gridToVector3 } = useGrid();
15 | const [hover, setHover] = useState(false);
16 | useCursor(hover);
17 | return (
18 |
19 | setHover(true)}
23 | onPointerLeave={() => setHover(false)}
24 | >
25 |
26 |
27 |
28 | );
29 | };
30 |
31 | export const Shop = ({ onItemSelected }) => {
32 | const [items] = useAtom(itemsAtom);
33 | const [map] = useAtom(mapAtom);
34 |
35 | const maxX = useRef(0);
36 |
37 | const shopItems = useMemo(() => {
38 | let x = 0;
39 | return Object.values(items).map((item, index) => {
40 | const xPos = x;
41 | x += item.size[0] / map.gridDivision + 1;
42 | maxX.current = x;
43 | return (
44 | {
49 | e.stopPropagation(); // Prevents the onPlaneClicked from firing just after we pick up an item
50 | onItemSelected(item);
51 | }}
52 | />
53 | );
54 | });
55 | }, [items]);
56 |
57 | const shopContainer = useRef();
58 | const scrollData = useScroll();
59 | const scale = 0.42;
60 | useFrame(() => {
61 | shopContainer.current.position.x =
62 | -scrollData.offset * maxX.current * scale;
63 | });
64 | return (
65 |
66 | {shopItems}
67 |
68 | );
69 | };
70 |
--------------------------------------------------------------------------------
/client/src/components/SocketManager.jsx:
--------------------------------------------------------------------------------
1 | import { useGLTF } from "@react-three/drei";
2 | import { atom, useAtom } from "jotai";
3 | import { useEffect } from "react";
4 | import { io } from "socket.io-client";
5 |
6 | export const socket = io(
7 | import.meta.env.VITE_SERVER_URL || "http://localhost:3000"
8 | );
9 | export const charactersAtom = atom([]);
10 | export const mapAtom = atom(null);
11 | export const userAtom = atom(null);
12 | export const itemsAtom = atom(null);
13 | export const roomIDAtom = atom(null);
14 | export const roomsAtom = atom([]);
15 |
16 | export const SocketManager = () => {
17 | const [_characters, setCharacters] = useAtom(charactersAtom);
18 | const [_map, setMap] = useAtom(mapAtom);
19 | const [_user, setUser] = useAtom(userAtom);
20 | const [items, setItems] = useAtom(itemsAtom);
21 | const [_rooms, setRooms] = useAtom(roomsAtom);
22 |
23 | useEffect(() => {
24 | if (!items) {
25 | return;
26 | }
27 | Object.values(items).forEach((item) => {
28 | useGLTF.preload(`/models/items/${item.name}.glb`);
29 | });
30 | }, [items]);
31 | useEffect(() => {
32 | function onConnect() {
33 | console.log("connected");
34 | }
35 | function onDisconnect() {
36 | console.log("disconnected");
37 | }
38 |
39 | function onWelcome(value) {
40 | setRooms(value.rooms);
41 | setItems(value.items);
42 | }
43 |
44 | function onRoomJoined(value) {
45 | setMap(value.map);
46 | setUser(value.id);
47 | setCharacters(value.characters);
48 | }
49 |
50 | function onCharacters(value) {
51 | setCharacters(value);
52 | }
53 |
54 | function onMapUpdate(value) {
55 | setMap(value.map);
56 | setCharacters(value.characters);
57 | }
58 |
59 | function onRooms(value) {
60 | setRooms(value);
61 | }
62 |
63 | socket.on("connect", onConnect);
64 | socket.on("disconnect", onDisconnect);
65 | socket.on("roomJoined", onRoomJoined);
66 | socket.on("rooms", onRooms);
67 | socket.on("welcome", onWelcome);
68 | socket.on("characters", onCharacters);
69 | socket.on("mapUpdate", onMapUpdate);
70 | return () => {
71 | socket.off("connect", onConnect);
72 | socket.off("disconnect", onDisconnect);
73 | socket.off("roomJoined", onRoomJoined);
74 | socket.off("rooms", onRooms);
75 | socket.off("welcome", onWelcome);
76 | socket.off("characters", onCharacters);
77 | socket.off("mapUpdate", onMapUpdate);
78 | };
79 | }, []);
80 | };
81 |
--------------------------------------------------------------------------------
/client/src/components/Experience.jsx:
--------------------------------------------------------------------------------
1 | import { CameraControls, Environment, Sky } from "@react-three/drei";
2 |
3 | import { useFrame } from "@react-three/fiber";
4 | import { useAtom } from "jotai";
5 | import { useEffect, useRef } from "react";
6 | import { Lobby } from "./Lobby";
7 | import { Room } from "./Room";
8 | import { mapAtom, roomIDAtom, userAtom } from "./SocketManager";
9 | import { buildModeAtom, shopModeAtom } from "./UI";
10 | export const Experience = ({ loaded }) => {
11 | const [buildMode] = useAtom(buildModeAtom);
12 | const [shopMode] = useAtom(shopModeAtom);
13 |
14 | const controls = useRef();
15 | const [roomID] = useAtom(roomIDAtom);
16 | const [map] = useAtom(mapAtom);
17 | const [user] = useAtom(userAtom);
18 |
19 | useEffect(() => {
20 | // INITIAL POSITION
21 | if (!loaded) {
22 | controls.current.setPosition(0, 8, 2);
23 | controls.current.setTarget(0, 8, 0);
24 | return;
25 | }
26 | // LOBBY
27 | if (!roomID) {
28 | controls.current.setPosition(0, 8, 2);
29 | controls.current.setTarget(0, 8, 0);
30 | controls.current.setPosition(0, 0, 2, true);
31 | controls.current.setTarget(0, 0, 0, true);
32 | return;
33 | }
34 | if (shopMode) {
35 | controls.current.setPosition(0, 1, 6, true);
36 | controls.current.setTarget(0, 0, 0, true);
37 | return;
38 | }
39 | if (buildMode) {
40 | controls.current.setPosition(14, 10, 14, true);
41 | controls.current.setTarget(3.5, 0, 3.5, true);
42 | return;
43 | }
44 |
45 | // ROOM
46 | if (!buildMode && !shopMode && roomID) {
47 | controls.current.setPosition(0, 10, 5);
48 | controls.current.setTarget(0, 10, 0);
49 | return;
50 | }
51 | }, [buildMode, roomID, shopMode, loaded]);
52 |
53 | useFrame(({ scene }) => {
54 | if (!user) {
55 | return;
56 | }
57 |
58 | const character = scene.getObjectByName(`character-${user}`);
59 | if (!character) {
60 | return;
61 | }
62 | controls.current.setTarget(
63 | character.position.x,
64 | 0,
65 | character.position.z,
66 | true
67 | );
68 | controls.current.setPosition(
69 | character.position.x + 8,
70 | character.position.y + 8,
71 | character.position.z + 8,
72 | true
73 | );
74 | });
75 |
76 | return (
77 | <>
78 |
85 |
86 |
87 |
88 |
94 |
99 |
100 |
116 | {roomID && map && }
117 | {loaded && !roomID && }
118 | >
119 | );
120 | };
121 |
--------------------------------------------------------------------------------
/client/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/components/Lobby.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | AccumulativeShadows,
3 | Html,
4 | RandomizedLight,
5 | Text3D,
6 | useFont,
7 | } from "@react-three/drei";
8 | import { motion } from "framer-motion-3d";
9 | import { useAtom } from "jotai";
10 | import { Suspense, useMemo, useRef } from "react";
11 | import { LobbyAvatar } from "./LobbyAvatar";
12 | import { Skyscraper } from "./Skyscraper";
13 | import { mapAtom, roomIDAtom, roomsAtom, socket } from "./SocketManager";
14 | import { Tablet } from "./Tablet";
15 | import { avatarUrlAtom } from "./UI";
16 | let firstLoad = true;
17 | export const Lobby = () => {
18 | const [rooms] = useAtom(roomsAtom);
19 | const [avatarUrl] = useAtom(avatarUrlAtom);
20 | const [_roomID, setRoomID] = useAtom(roomIDAtom);
21 | const [_map, setMap] = useAtom(mapAtom);
22 | const joinRoom = (roomId) => {
23 | socket.emit("joinRoom", roomId, {
24 | avatarUrl,
25 | });
26 | setMap(null);
27 | setRoomID(roomId);
28 | };
29 |
30 | const isMobile = window.innerWidth < 1024;
31 |
32 | const tablet = useRef();
33 |
34 | const goldenRatio = Math.min(1, window.innerWidth / 1600);
35 |
36 | const accumulativeShadows = useMemo(
37 | () => (
38 |
46 |
53 |
60 |
61 | ),
62 | []
63 | );
64 | const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // ugly safari fix as transform position is buggy on it
65 |
66 | return (
67 |
68 | {
86 | firstLoad = false;
87 | }}
88 | >
89 |
90 |
96 |
103 |
104 |
105 | WELCOME TO
106 |
107 | WAWA MANSION
108 |
109 |
110 | Please select a room to relax
111 |
112 | {rooms.map((room) => (
113 |
joinRoom(room.id)}
117 | >
118 |
119 | {room.name}
120 |
121 |
122 |
0 ? "bg-green-500" : "bg-orange-500"
125 | }`}
126 | >
127 | {room.nbCharacters} people in this room
128 |
129 |
130 | ))}
131 |
132 |
133 |
134 |
135 |
136 |
147 | MANSION
148 |
149 |
150 |
151 |
162 | WAWA
163 |
164 |
165 |
166 |
167 |
168 |
169 | {accumulativeShadows}
170 |
171 |
177 |
178 |
179 | );
180 | };
181 |
182 | useFont.preload("/fonts/Inter_Bold.json");
183 |
--------------------------------------------------------------------------------
/client/src/components/Avatar.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | Command: npx gltfjsx@6.2.3 public/models/Animated Woman.glb -o src/components/AnimatedWoman.jsx -r public
4 | */
5 |
6 | import { Html, useAnimations, useGLTF } from "@react-three/drei";
7 | import { useFrame, useGraph } from "@react-three/fiber";
8 | import { useAtom } from "jotai";
9 | import React, { useEffect, useMemo, useRef, useState } from "react";
10 | import { SkeletonUtils } from "three-stdlib";
11 | import { useGrid } from "../hooks/useGrid";
12 | import { socket, userAtom } from "./SocketManager";
13 |
14 | import { motion } from "framer-motion-3d";
15 |
16 | const MOVEMENT_SPEED = 4;
17 |
18 | export function Avatar({
19 | id,
20 | avatarUrl = "https://models.readyplayer.me/64f0265b1db75f90dcfd9e2c.glb",
21 | ...props
22 | }) {
23 | const [chatMessage, setChatMessage] = useState("");
24 | const position = useMemo(() => props.position, []);
25 |
26 | const avatar = useRef();
27 | const [path, setPath] = useState();
28 | const { gridToVector3 } = useGrid();
29 |
30 | const group = useRef();
31 | const { scene } = useGLTF(avatarUrl);
32 | // Skinned meshes cannot be re-used in threejs without cloning them
33 | const clone = useMemo(() => SkeletonUtils.clone(scene), [scene]);
34 | // useGraph creates two flat object collections for nodes and materials
35 | const { nodes } = useGraph(clone);
36 |
37 | const { animations: walkAnimation } = useGLTF("/animations/M_Walk_001.glb");
38 | const { animations: danceAnimation } = useGLTF(
39 | "/animations/M_Dances_001.glb"
40 | );
41 | const { animations: idleAnimation } = useGLTF(
42 | "/animations/M_Standing_Idle_001.glb"
43 | );
44 |
45 | const { actions } = useAnimations(
46 | [walkAnimation[0], idleAnimation[0], danceAnimation[0]],
47 | avatar
48 | );
49 | const [animation, setAnimation] = useState("M_Standing_Idle_001");
50 | const [isDancing, setIsDancing] = useState(false);
51 | const [init, setInit] = useState(false);
52 | const [showChatBubble, setShowChatBubble] = useState(false);
53 |
54 | useEffect(() => {
55 | clone.traverse((child) => {
56 | if (child.isMesh) {
57 | child.castShadow = true;
58 | child.receiveShadow = true;
59 | }
60 | });
61 | }, [clone]);
62 |
63 | useEffect(() => {
64 | actions[animation]
65 | .reset()
66 | .fadeIn(init ? 0.32 : 0)
67 | .play();
68 | setInit(true);
69 | return () => actions[animation]?.fadeOut(0.32);
70 | }, [animation, avatarUrl]);
71 |
72 | useEffect(() => {
73 | function onPlayerDance(value) {
74 | if (value.id === id) {
75 | setIsDancing(true);
76 | }
77 | }
78 | function onPlayerMove(value) {
79 | if (value.id === id) {
80 | const path = [];
81 | value.path?.forEach((gridPosition) => {
82 | path.push(gridToVector3(gridPosition));
83 | });
84 | setPath(path);
85 | }
86 | }
87 |
88 | let chatMessageBubbleTimeout;
89 | function onPlayerChatMessage(value) {
90 | if (value.id === id) {
91 | setChatMessage(value.message);
92 | clearTimeout(chatMessageBubbleTimeout);
93 | setShowChatBubble(true);
94 | chatMessageBubbleTimeout = setTimeout(() => {
95 | setShowChatBubble(false);
96 | }, 3500);
97 | }
98 | }
99 |
100 | socket.on("playerMove", onPlayerMove);
101 | socket.on("playerDance", onPlayerDance);
102 | socket.on("playerChatMessage", onPlayerChatMessage);
103 | return () => {
104 | socket.off("playerDance", onPlayerDance);
105 | socket.off("playerMove", onPlayerMove);
106 | socket.off("playerChatMessage", onPlayerChatMessage);
107 | };
108 | }, [id]);
109 |
110 | const [user] = useAtom(userAtom);
111 |
112 | useFrame((_state, delta) => {
113 | const hips = avatar.current.getObjectByName("Hips");
114 | hips.position.set(0, hips.position.y, 0);
115 | if (path?.length && group.current.position.distanceTo(path[0]) > 0.1) {
116 | const direction = group.current.position
117 | .clone()
118 | .sub(path[0])
119 | .normalize()
120 | .multiplyScalar(MOVEMENT_SPEED * delta);
121 | group.current.position.sub(direction);
122 | group.current.lookAt(path[0]);
123 | setAnimation("M_Walk_001");
124 | setIsDancing(false);
125 | } else if (path?.length) {
126 | path.shift();
127 | } else {
128 | if (isDancing) {
129 | setAnimation("M_Dances_001");
130 | } else {
131 | setAnimation("M_Standing_Idle_001");
132 | }
133 | }
134 | });
135 |
136 | return (
137 |
144 |
145 |
146 |
151 | {chatMessage}
152 |
153 |
154 |
155 |
173 |
174 |
175 |
176 | );
177 | }
178 |
179 | useGLTF.preload(
180 | localStorage.getItem("avatarURL") ||
181 | "https://models.readyplayer.me/64f0265b1db75f90dcfd9e2c.glb?meshlod=1&quality=medium"
182 | );
183 | useGLTF.preload("/animations/M_Walk_001.glb");
184 | useGLTF.preload("/animations/M_Standing_Idle_001.glb");
185 | useGLTF.preload("/animations/M_Dances_001.glb");
186 | useGLTF.preload("/animations/M_Standing_Expressions_001.glb");
187 |
--------------------------------------------------------------------------------
/client/src/components/Room.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | AccumulativeShadows,
3 | Grid,
4 | RandomizedLight,
5 | useCursor,
6 | } from "@react-three/drei";
7 |
8 | import { useThree } from "@react-three/fiber";
9 | import { atom, useAtom } from "jotai";
10 | import { Suspense, useEffect, useMemo, useState } from "react";
11 | import { useGrid } from "../hooks/useGrid";
12 | import { Avatar } from "./Avatar";
13 | import { Item } from "./Item";
14 | import { Shop } from "./Shop";
15 | import { charactersAtom, mapAtom, socket, userAtom } from "./SocketManager";
16 | import {
17 | buildModeAtom,
18 | draggedItemAtom,
19 | draggedItemRotationAtom,
20 | shopModeAtom,
21 | } from "./UI";
22 |
23 | export const roomItemsAtom = atom([]);
24 |
25 | export const Room = () => {
26 | const [buildMode] = useAtom(buildModeAtom);
27 | const [shopMode, setShopMode] = useAtom(shopModeAtom);
28 | const [characters] = useAtom(charactersAtom);
29 | const [map] = useAtom(mapAtom);
30 | const [items, setItems] = useAtom(roomItemsAtom);
31 | const [onFloor, setOnFloor] = useState(false);
32 | useCursor(onFloor);
33 | const { vector3ToGrid, gridToVector3 } = useGrid();
34 |
35 | const scene = useThree((state) => state.scene);
36 | const [user] = useAtom(userAtom);
37 |
38 | useEffect(() => {
39 | setItems(map.items);
40 | }, [map]);
41 |
42 | const onPlaneClicked = (e) => {
43 | if (!buildMode) {
44 | const character = scene.getObjectByName(`character-${user}`);
45 | if (!character) {
46 | return;
47 | }
48 | socket.emit(
49 | "move",
50 | vector3ToGrid(character.position),
51 | vector3ToGrid(e.point)
52 | );
53 | } else {
54 | if (draggedItem !== null) {
55 | if (canDrop) {
56 | setItems((prev) => {
57 | const newItems = [...prev];
58 | delete newItems[draggedItem].tmp;
59 | newItems[draggedItem].gridPosition = vector3ToGrid(e.point);
60 | newItems[draggedItem].rotation = draggedItemRotation;
61 | return newItems;
62 | });
63 | }
64 | setDraggedItem(null);
65 | }
66 | }
67 | };
68 |
69 | const [draggedItem, setDraggedItem] = useAtom(draggedItemAtom);
70 | const [draggedItemRotation, setDraggedItemRotation] = useAtom(
71 | draggedItemRotationAtom
72 | );
73 | const [dragPosition, setDragPosition] = useState([0, 0]);
74 | const [canDrop, setCanDrop] = useState(false);
75 |
76 | useEffect(() => {
77 | if (draggedItem === null) {
78 | setItems((prev) => prev.filter((item) => !item.tmp));
79 | }
80 | }, [draggedItem]);
81 |
82 | useEffect(() => {
83 | if (draggedItem === null) {
84 | // FIXED: issue with 0 being falsy
85 | return;
86 | }
87 | const item = items[draggedItem];
88 | const width =
89 | draggedItemRotation === 1 || draggedItemRotation === 3
90 | ? item.size[1]
91 | : item.size[0];
92 | const height =
93 | draggedItemRotation === 1 || draggedItemRotation === 3
94 | ? item.size[0]
95 | : item.size[1];
96 |
97 | let droppable = true;
98 |
99 | // check if item is in bounds
100 | if (
101 | dragPosition[0] < 0 ||
102 | dragPosition[0] + width > map.size[0] * map.gridDivision
103 | ) {
104 | droppable = false;
105 | }
106 | if (
107 | dragPosition[1] < 0 ||
108 | dragPosition[1] + height > map.size[1] * map.gridDivision
109 | ) {
110 | droppable = false;
111 | }
112 | // check if item is not colliding with other items
113 | if (!item.walkable && !item.wall) {
114 | items.forEach((otherItem, idx) => {
115 | // ignore self
116 | if (idx === draggedItem) {
117 | return;
118 | }
119 |
120 | // ignore wall & floor
121 | if (otherItem.walkable || otherItem.wall) {
122 | return;
123 | }
124 |
125 | // check item overlap
126 | const otherWidth =
127 | otherItem.rotation === 1 || otherItem.rotation === 3
128 | ? otherItem.size[1]
129 | : otherItem.size[0];
130 | const otherHeight =
131 | otherItem.rotation === 1 || otherItem.rotation === 3
132 | ? otherItem.size[0]
133 | : otherItem.size[1];
134 | if (
135 | dragPosition[0] < otherItem.gridPosition[0] + otherWidth &&
136 | dragPosition[0] + width > otherItem.gridPosition[0] &&
137 | dragPosition[1] < otherItem.gridPosition[1] + otherHeight &&
138 | dragPosition[1] + height > otherItem.gridPosition[1]
139 | ) {
140 | droppable = false;
141 | }
142 | });
143 | }
144 |
145 | setCanDrop(droppable);
146 | }, [dragPosition, draggedItem, items, draggedItemRotation]);
147 | const state = useThree((state) => state);
148 |
149 | useEffect(() => {
150 | if (buildMode) {
151 | setItems(map?.items || []);
152 | } else {
153 | socket.emit("itemsUpdate", items);
154 | }
155 | }, [buildMode]);
156 |
157 | const onItemSelected = (item) => {
158 | setShopMode(false);
159 |
160 | setItems((prev) => [
161 | ...prev,
162 | {
163 | ...item,
164 | gridPosition: [0, 0],
165 | tmp: true,
166 | },
167 | ]);
168 | setDraggedItem(items.length);
169 | setDraggedItemRotation(item.rotation || 0);
170 | };
171 |
172 | const accumulativeShadows = useMemo(
173 | () => (
174 |
182 |
189 |
196 |
197 | ),
198 | [items]
199 | );
200 |
201 | return (
202 | <>
203 | {shopMode && }
204 | {!buildMode && !shopMode && accumulativeShadows}
205 | {!shopMode &&
206 | (buildMode ? items : map.items).map((item, idx) => (
207 | - {
211 | if (buildMode) {
212 | setDraggedItem((prev) => (prev === null ? idx : prev));
213 | setDraggedItemRotation(item.rotation || 0);
214 | }
215 | }}
216 | isDragging={draggedItem === idx}
217 | dragPosition={dragPosition}
218 | dragRotation={draggedItemRotation}
219 | canDrop={canDrop}
220 | />
221 | ))}
222 |
223 | {!shopMode && (
224 | setOnFloor(true)}
229 | onPointerLeave={() => setOnFloor(false)}
230 | onPointerMove={(e) => {
231 | if (!buildMode) {
232 | return;
233 | }
234 | const newPosition = vector3ToGrid(e.point);
235 | if (
236 | !dragPosition ||
237 | newPosition[0] !== dragPosition[0] ||
238 | newPosition[1] !== dragPosition[1]
239 | ) {
240 | setDragPosition(newPosition);
241 | }
242 | }}
243 | position-x={map.size[0] / 2}
244 | position-z={map.size[1] / 2}
245 | receiveShadow
246 | >
247 |
248 |
249 |
250 | )}
251 | {(buildMode || shopMode) && (
252 |
253 | )}
254 | {!buildMode &&
255 | characters.map((character) => (
256 |
257 |
258 |
266 |
267 |
268 | ))}
269 | >
270 | );
271 | };
272 |
--------------------------------------------------------------------------------
/server/default.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "name": "PARTY ROOM",
5 | "password": "WAWA",
6 | "items": [
7 | {
8 | "name": "loungeSofaCorner",
9 | "size": [5, 5],
10 | "rotation": 3,
11 | "gridPosition": [0, 0]
12 | },
13 | {
14 | "name": "bear",
15 | "size": [2, 1],
16 | "wall": true,
17 | "gridPosition": [2, 0],
18 | "rotation": 0
19 | },
20 | {
21 | "name": "tableCoffeeGlassSquare",
22 | "size": [2, 2],
23 | "gridPosition": [5, 4],
24 | "rotation": 0
25 | },
26 | {
27 | "name": "loungeSofa",
28 | "size": [5, 2],
29 | "rotation": 1,
30 | "gridPosition": [8, 2]
31 | },
32 | {
33 | "name": "plant",
34 | "size": [1, 1],
35 | "gridPosition": [0, 6],
36 | "rotation": 0
37 | },
38 | {
39 | "name": "chairCushion",
40 | "size": [1, 1],
41 | "rotation": 1,
42 | "gridPosition": [12, 4]
43 | },
44 | {
45 | "name": "deskComputer",
46 | "size": [3, 2],
47 | "gridPosition": [10, 3],
48 | "rotation": 1
49 | },
50 | {
51 | "name": "deskComputer",
52 | "size": [3, 2],
53 | "gridPosition": [3, 10],
54 | "rotation": 0
55 | },
56 | {
57 | "name": "chairCushion",
58 | "size": [1, 1],
59 | "rotation": 0,
60 | "gridPosition": [4, 12]
61 | },
62 | {
63 | "name": "lampSquareFloor",
64 | "size": [1, 1],
65 | "gridPosition": [13, 0],
66 | "rotation": 0
67 | },
68 | {
69 | "name": "speaker",
70 | "size": [1, 1],
71 | "gridPosition": [7, 0],
72 | "rotation": 0
73 | },
74 | {
75 | "name": "speakerSmall",
76 | "size": [1, 1],
77 | "rotation": 2,
78 | "gridPosition": [10, 6]
79 | },
80 | {
81 | "name": "laptop",
82 | "size": [1, 1],
83 | "gridPosition": [6, 0],
84 | "rotation": 0
85 | },
86 | {
87 | "name": "deskComputer",
88 | "size": [3, 2],
89 | "gridPosition": [8, 10],
90 | "rotation": 0
91 | },
92 | {
93 | "name": "chairCushion",
94 | "size": [1, 1],
95 | "rotation": 0,
96 | "gridPosition": [9, 12]
97 | },
98 | {
99 | "name": "speakerSmall",
100 | "size": [1, 1],
101 | "rotation": 3,
102 | "gridPosition": [0, 5]
103 | }
104 | ]
105 | },
106 | {
107 | "id": 2,
108 | "name": "BATHROOM",
109 | "password": "WAWA",
110 | "items": [
111 | {
112 | "name": "washer",
113 | "size": [2, 2],
114 | "gridPosition": [12, 0],
115 | "rotation": 0
116 | },
117 | {
118 | "name": "toiletSquare",
119 | "size": [2, 2],
120 | "gridPosition": [6, 0],
121 | "rotation": 0
122 | },
123 | {
124 | "name": "trashcan",
125 | "size": [1, 1],
126 | "gridPosition": [8, 0],
127 | "rotation": 0
128 | },
129 | {
130 | "name": "bathroomCabinetDrawer",
131 | "size": [2, 2],
132 | "gridPosition": [4, 0],
133 | "rotation": 0
134 | },
135 | {
136 | "name": "bathtub",
137 | "size": [4, 2],
138 | "gridPosition": [6, 7],
139 | "rotation": 0
140 | },
141 | {
142 | "name": "bathroomMirror",
143 | "size": [2, 1],
144 | "wall": true,
145 | "gridPosition": [4, 0],
146 | "rotation": 0
147 | },
148 | {
149 | "name": "bathroomCabinet",
150 | "size": [2, 1],
151 | "wall": true,
152 | "gridPosition": [12, 0],
153 | "rotation": 0
154 | },
155 | {
156 | "name": "bathroomSink",
157 | "size": [2, 2],
158 | "gridPosition": [0, 7],
159 | "rotation": 1
160 | },
161 | {
162 | "name": "toiletSquare",
163 | "size": [2, 2],
164 | "gridPosition": [0, 9],
165 | "rotation": 1
166 | },
167 | {
168 | "name": "bathroomMirror",
169 | "size": [2, 1],
170 | "wall": true,
171 | "gridPosition": [0, 7],
172 | "rotation": 1
173 | },
174 | {
175 | "name": "showerRound",
176 | "size": [2, 2],
177 | "gridPosition": [0, 0],
178 | "rotation": 0
179 | },
180 | {
181 | "name": "rugRounded",
182 | "size": [6, 4],
183 | "walkable": true,
184 | "gridPosition": [5, 9],
185 | "rotation": 0
186 | },
187 | {
188 | "name": "plant",
189 | "size": [1, 1],
190 | "gridPosition": [10, 8],
191 | "rotation": 0
192 | },
193 | {
194 | "name": "plantSmall",
195 | "size": [1, 1],
196 | "gridPosition": [0, 11],
197 | "rotation": 0
198 | },
199 | {
200 | "name": "bookcaseOpenLow",
201 | "size": [2, 1],
202 | "gridPosition": [5, 7],
203 | "rotation": 1
204 | },
205 | {
206 | "name": "tableCoffeeGlassSquare",
207 | "size": [2, 2],
208 | "gridPosition": [0, 4],
209 | "rotation": 0
210 | }
211 | ]
212 | },
213 | {
214 | "id": 3,
215 | "name": "KITCHEN",
216 | "password": "WAWA",
217 | "items": [
218 | {
219 | "name": "plant",
220 | "size": [1, 1],
221 | "gridPosition": [1, 0],
222 | "rotation": 0
223 | },
224 | {
225 | "name": "bookcaseOpenLow",
226 | "size": [2, 1],
227 | "gridPosition": [2, 0],
228 | "rotation": 0
229 | },
230 | {
231 | "name": "tableCrossCloth",
232 | "size": [4, 2],
233 | "gridPosition": [4, 10],
234 | "rotation": 0
235 | },
236 | {
237 | "name": "chairCushion",
238 | "size": [1, 1],
239 | "rotation": 2,
240 | "gridPosition": [6, 9]
241 | },
242 | {
243 | "name": "chairCushion",
244 | "size": [1, 1],
245 | "rotation": 0,
246 | "gridPosition": [6, 12]
247 | },
248 | {
249 | "name": "chairCushion",
250 | "size": [1, 1],
251 | "rotation": 0,
252 | "gridPosition": [4, 12]
253 | },
254 | {
255 | "name": "chairCushion",
256 | "size": [1, 1],
257 | "rotation": 2,
258 | "gridPosition": [4, 9]
259 | },
260 | {
261 | "name": "kitchenMicrowave",
262 | "size": [1, 1],
263 | "gridPosition": [5, 0],
264 | "rotation": 0
265 | },
266 | {
267 | "name": "kitchenSink",
268 | "size": [2, 2],
269 | "gridPosition": [10, 0],
270 | "rotation": 0
271 | },
272 | {
273 | "name": "dryer",
274 | "size": [2, 2],
275 | "gridPosition": [8, 0],
276 | "rotation": 0
277 | },
278 | {
279 | "name": "kitchenBlender",
280 | "size": [1, 1],
281 | "gridPosition": [6, 0],
282 | "rotation": 1
283 | },
284 | {
285 | "name": "kitchenCabinetCornerRound",
286 | "size": [2, 2],
287 | "gridPosition": [12, 4],
288 | "rotation": 0
289 | },
290 | {
291 | "name": "kitchenCabinetCornerInner",
292 | "size": [2, 2],
293 | "gridPosition": [12, 0],
294 | "rotation": 0
295 | },
296 | {
297 | "name": "kitchenCabinet",
298 | "size": [2, 2],
299 | "gridPosition": [12, 2],
300 | "rotation": 3
301 | },
302 | {
303 | "name": "plantSmall",
304 | "size": [1, 1],
305 | "gridPosition": [0, 0],
306 | "rotation": 0
307 | },
308 | {
309 | "name": "tableCrossCloth",
310 | "size": [4, 2],
311 | "gridPosition": [8, 10],
312 | "rotation": 0
313 | },
314 | {
315 | "name": "benchCushionLow",
316 | "size": [2, 1],
317 | "gridPosition": [9, 12],
318 | "rotation": 0
319 | },
320 | {
321 | "name": "benchCushionLow",
322 | "size": [2, 1],
323 | "gridPosition": [9, 9],
324 | "rotation": 0
325 | },
326 | {
327 | "name": "kitchenFridge",
328 | "size": [2, 1],
329 | "rotation": 3,
330 | "gridPosition": [0, 3]
331 | },
332 | {
333 | "name": "kitchenFridgeLarge",
334 | "size": [2, 1],
335 | "rotation": 1,
336 | "gridPosition": [0, 12]
337 | },
338 | {
339 | "name": "kitchenStove",
340 | "size": [2, 2],
341 | "gridPosition": [0, 6],
342 | "rotation": 1
343 | },
344 | { "name": "bench", "size": [2, 1], "rotation": 3, "gridPosition": [0, 9] }
345 | ]
346 | },
347 | {
348 | "id": 4,
349 | "name": "COSY ROOM",
350 | "password": "WAWA",
351 | "items": [
352 | {
353 | "name": "tableCoffee",
354 | "size": [4, 2],
355 | "gridPosition": [5, 4],
356 | "rotation": 0
357 | },
358 | {
359 | "name": "rugRectangle",
360 | "size": [8, 4],
361 | "walkable": true,
362 | "gridPosition": [3, 3],
363 | "rotation": 0
364 | },
365 | {
366 | "name": "plant",
367 | "size": [1, 1],
368 | "gridPosition": [4, 0],
369 | "rotation": 0
370 | },
371 | {
372 | "name": "speaker",
373 | "size": [1, 1],
374 | "gridPosition": [9, 0],
375 | "rotation": 0
376 | },
377 | {
378 | "name": "loungeChair",
379 | "size": [2, 2],
380 | "rotation": 2,
381 | "gridPosition": [6, 0]
382 | },
383 | {
384 | "name": "plantSmall",
385 | "size": [1, 1],
386 | "gridPosition": [3, 0],
387 | "rotation": 0
388 | },
389 | {
390 | "name": "plant",
391 | "size": [1, 1],
392 | "gridPosition": [1, 0],
393 | "rotation": 0
394 | },
395 | {
396 | "name": "plantSmall",
397 | "size": [1, 1],
398 | "gridPosition": [0, 0],
399 | "rotation": 0
400 | },
401 | {
402 | "name": "plantSmall",
403 | "size": [1, 1],
404 | "gridPosition": [1, 1],
405 | "rotation": 0
406 | },
407 | {
408 | "name": "plant",
409 | "size": [1, 1],
410 | "gridPosition": [0, 1],
411 | "rotation": 0
412 | },
413 | {
414 | "name": "plantSmall",
415 | "size": [1, 1],
416 | "gridPosition": [0, 2],
417 | "rotation": 0
418 | },
419 | {
420 | "name": "televisionModern",
421 | "size": [4, 2],
422 | "rotation": 0,
423 | "gridPosition": [5, 9]
424 | },
425 | {
426 | "name": "lampRoundFloor",
427 | "size": [1, 1],
428 | "gridPosition": [11, 0],
429 | "rotation": 0
430 | }
431 | ]
432 | }
433 | ]
434 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import pathfinding from "pathfinding";
3 | import { Server } from "socket.io";
4 |
5 | const origin = process.env.CLIENT_URL || "http://localhost:5173";
6 | const io = new Server({
7 | cors: {
8 | origin,
9 | },
10 | });
11 |
12 | io.listen(3000);
13 |
14 | console.log("Server started on port 3000, allowed cors origin: " + origin);
15 |
16 | // PATHFINDING UTILS
17 |
18 | const finder = new pathfinding.AStarFinder({
19 | allowDiagonal: true,
20 | dontCrossCorners: true,
21 | });
22 |
23 | const findPath = (room, start, end) => {
24 | const gridClone = room.grid.clone();
25 | const path = finder.findPath(start[0], start[1], end[0], end[1], gridClone);
26 | return path;
27 | };
28 |
29 | const updateGrid = (room) => {
30 | // RESET GRID FOR ROOM
31 | for (let x = 0; x < room.size[0] * room.gridDivision; x++) {
32 | for (let y = 0; y < room.size[1] * room.gridDivision; y++) {
33 | room.grid.setWalkableAt(x, y, true);
34 | }
35 | }
36 |
37 | room.items.forEach((item) => {
38 | if (item.walkable || item.wall) {
39 | return;
40 | }
41 | const width =
42 | item.rotation === 1 || item.rotation === 3 ? item.size[1] : item.size[0];
43 | const height =
44 | item.rotation === 1 || item.rotation === 3 ? item.size[0] : item.size[1];
45 | for (let x = 0; x < width; x++) {
46 | for (let y = 0; y < height; y++) {
47 | room.grid.setWalkableAt(
48 | item.gridPosition[0] + x,
49 | item.gridPosition[1] + y,
50 | false
51 | );
52 | }
53 | }
54 | });
55 | };
56 |
57 | // ROOMS MANAGEMENT
58 | const rooms = [];
59 |
60 | const loadRooms = async () => {
61 | let data;
62 | try {
63 | data = fs.readFileSync("rooms.json", "utf8");
64 | } catch (ex) {
65 | console.log("No rooms.json file found, using default file");
66 | try {
67 | data = fs.readFileSync("default.json", "utf8");
68 | } catch (ex) {
69 | console.log("No default.json file found, exiting");
70 | process.exit(1);
71 | }
72 | }
73 | data = JSON.parse(data);
74 | data.forEach((roomItem) => {
75 | const room = {
76 | ...roomItem,
77 | size: [7, 7], // HARDCODED FOR SIMPLICITY PURPOSES
78 | gridDivision: 2,
79 | characters: [],
80 | };
81 | room.grid = new pathfinding.Grid(
82 | room.size[0] * room.gridDivision,
83 | room.size[1] * room.gridDivision
84 | );
85 | updateGrid(room);
86 | rooms.push(room);
87 | });
88 | };
89 |
90 | loadRooms();
91 |
92 | // UTILS
93 |
94 | const generateRandomPosition = (room) => {
95 | // TO AVOID INFINITE LOOP WE LIMIT TO 100, BEST WOULD BE TO CHECK IF THERE IS ENOUGH SPACE LEFT 🤭
96 | for (let i = 0; i < 100; i++) {
97 | const x = Math.floor(Math.random() * room.size[0] * room.gridDivision);
98 | const y = Math.floor(Math.random() * room.size[1] * room.gridDivision);
99 | if (room.grid.isWalkableAt(x, y)) {
100 | return [x, y];
101 | }
102 | }
103 | };
104 |
105 | // SOCKET MANAGEMENT
106 |
107 | io.on("connection", (socket) => {
108 | try {
109 | let room = null;
110 | let character = null;
111 |
112 | socket.emit("welcome", {
113 | rooms: rooms.map((room) => ({
114 | id: room.id,
115 | name: room.name,
116 | nbCharacters: room.characters.length,
117 | })),
118 | items,
119 | });
120 |
121 | socket.on("joinRoom", (roomId, opts) => {
122 | room = rooms.find((room) => room.id === roomId);
123 | if (!room) {
124 | return;
125 | }
126 | socket.join(room.id);
127 | character = {
128 | id: socket.id,
129 | session: parseInt(Math.random() * 1000),
130 | position: generateRandomPosition(room),
131 | avatarUrl: opts.avatarUrl,
132 | };
133 | room.characters.push(character);
134 |
135 | socket.emit("roomJoined", {
136 | map: {
137 | gridDivision: room.gridDivision,
138 | size: room.size,
139 | items: room.items,
140 | },
141 | characters: room.characters,
142 | id: socket.id,
143 | });
144 | onRoomUpdate();
145 | });
146 |
147 | const onRoomUpdate = () => {
148 | io.to(room.id).emit("characters", room.characters);
149 | io.emit(
150 | "rooms",
151 | rooms.map((room) => ({
152 | id: room.id,
153 | name: room.name,
154 | nbCharacters: room.characters.length,
155 | }))
156 | );
157 | };
158 |
159 | socket.on("leaveRoom", () => {
160 | if (!room) {
161 | return;
162 | }
163 | socket.leave(room.id);
164 | room.characters.splice(
165 | room.characters.findIndex((character) => character.id === socket.id),
166 | 1
167 | );
168 | onRoomUpdate();
169 | room = null;
170 | });
171 |
172 | socket.on("characterAvatarUpdate", (avatarUrl) => {
173 | character.avatarUrl = avatarUrl;
174 | io.to(room.id).emit("characters", room.characters);
175 | });
176 |
177 | socket.on("move", (from, to) => {
178 | const path = findPath(room, from, to);
179 | if (!path) {
180 | return;
181 | }
182 | character.position = from;
183 | character.path = path;
184 | io.to(room.id).emit("playerMove", character);
185 | });
186 |
187 | socket.on("dance", () => {
188 | io.to(room.id).emit("playerDance", {
189 | id: socket.id,
190 | });
191 | });
192 |
193 | socket.on("chatMessage", (message) => {
194 | io.to(room.id).emit("playerChatMessage", {
195 | id: socket.id,
196 | message,
197 | });
198 | });
199 |
200 | socket.on("passwordCheck", (password) => {
201 | if (password === room.password) {
202 | socket.emit("passwordCheckSuccess");
203 | character.canUpdateRoom = true;
204 | } else {
205 | socket.emit("passwordCheckFail");
206 | }
207 | });
208 |
209 | socket.on("itemsUpdate", async (items) => {
210 | if (!character.canUpdateRoom) {
211 | return;
212 | }
213 | if (!items || items.length === 0) {
214 | return; // security
215 | }
216 | room.items = items;
217 | updateGrid(room);
218 | room.characters.forEach((character) => {
219 | character.path = [];
220 | character.position = generateRandomPosition(room);
221 | });
222 | io.to(room.id).emit("mapUpdate", {
223 | map: {
224 | gridDivision: room.gridDivision,
225 | size: room.size,
226 | items: room.items,
227 | },
228 | characters: room.characters,
229 | });
230 |
231 | fs.writeFileSync("rooms.json", JSON.stringify(rooms, null, 2));
232 | });
233 |
234 | socket.on("disconnect", () => {
235 | console.log("User disconnected");
236 | if (room) {
237 | room.characters.splice(
238 | room.characters.findIndex((character) => character.id === socket.id),
239 | 1
240 | );
241 | onRoomUpdate();
242 | room = null;
243 | }
244 | });
245 | } catch (ex) {
246 | console.log(ex); // Big try catch to avoid crashing the server (best would be to handle all errors properly...)
247 | }
248 | });
249 |
250 | // ROOMS
251 |
252 | // SHOP ITEMS
253 | const items = {
254 | washer: {
255 | name: "washer",
256 | size: [2, 2],
257 | },
258 | toiletSquare: {
259 | name: "toiletSquare",
260 | size: [2, 2],
261 | },
262 | trashcan: {
263 | name: "trashcan",
264 | size: [1, 1],
265 | },
266 | bathroomCabinetDrawer: {
267 | name: "bathroomCabinetDrawer",
268 | size: [2, 2],
269 | },
270 | bathtub: {
271 | name: "bathtub",
272 | size: [4, 2],
273 | },
274 | bathroomMirror: {
275 | name: "bathroomMirror",
276 | size: [2, 1],
277 | wall: true,
278 | },
279 | bathroomCabinet: {
280 | name: "bathroomCabinet",
281 | size: [2, 1],
282 | wall: true,
283 | },
284 | bathroomSink: {
285 | name: "bathroomSink",
286 | size: [2, 2],
287 | },
288 | showerRound: {
289 | name: "showerRound",
290 | size: [2, 2],
291 | },
292 | tableCoffee: {
293 | name: "tableCoffee",
294 | size: [4, 2],
295 | },
296 | loungeSofaCorner: {
297 | name: "loungeSofaCorner",
298 | size: [5, 5],
299 | rotation: 2,
300 | },
301 | bear: {
302 | name: "bear",
303 | size: [2, 1],
304 | wall: true,
305 | },
306 | loungeSofaOttoman: {
307 | name: "loungeSofaOttoman",
308 | size: [2, 2],
309 | },
310 | tableCoffeeGlassSquare: {
311 | name: "tableCoffeeGlassSquare",
312 | size: [2, 2],
313 | },
314 | loungeDesignSofaCorner: {
315 | name: "loungeDesignSofaCorner",
316 | size: [5, 5],
317 | rotation: 2,
318 | },
319 | loungeDesignSofa: {
320 | name: "loungeDesignSofa",
321 | size: [5, 2],
322 | rotation: 2,
323 | },
324 | loungeSofa: {
325 | name: "loungeSofa",
326 | size: [5, 2],
327 | rotation: 2,
328 | },
329 | bookcaseOpenLow: {
330 | name: "bookcaseOpenLow",
331 | size: [2, 1],
332 | },
333 | bookcaseClosedWide: {
334 | name: "bookcaseClosedWide",
335 | size: [3, 1],
336 | rotation: 2,
337 | },
338 | bedSingle: {
339 | name: "bedSingle",
340 | size: [3, 6],
341 | rotation: 2,
342 | },
343 | bench: {
344 | name: "bench",
345 | size: [2, 1],
346 | rotation: 2,
347 | },
348 | bedDouble: {
349 | name: "bedDouble",
350 | size: [5, 5],
351 | rotation: 2,
352 | },
353 | benchCushionLow: {
354 | name: "benchCushionLow",
355 | size: [2, 1],
356 | },
357 | loungeChair: {
358 | name: "loungeChair",
359 | size: [2, 2],
360 | rotation: 2,
361 | },
362 | cabinetBedDrawer: {
363 | name: "cabinetBedDrawer",
364 | size: [1, 1],
365 | rotation: 2,
366 | },
367 | cabinetBedDrawerTable: {
368 | name: "cabinetBedDrawerTable",
369 | size: [1, 1],
370 | rotation: 2,
371 | },
372 | table: {
373 | name: "table",
374 | size: [4, 2],
375 | },
376 | tableCrossCloth: {
377 | name: "tableCrossCloth",
378 | size: [4, 2],
379 | },
380 | plant: {
381 | name: "plant",
382 | size: [1, 1],
383 | },
384 | plantSmall: {
385 | name: "plantSmall",
386 | size: [1, 1],
387 | },
388 | rugRounded: {
389 | name: "rugRounded",
390 | size: [6, 4],
391 | walkable: true,
392 | },
393 | rugRound: {
394 | name: "rugRound",
395 | size: [4, 4],
396 | walkable: true,
397 | },
398 | rugSquare: {
399 | name: "rugSquare",
400 | size: [4, 4],
401 | walkable: true,
402 | },
403 | rugRectangle: {
404 | name: "rugRectangle",
405 | size: [8, 4],
406 | walkable: true,
407 | },
408 | televisionVintage: {
409 | name: "televisionVintage",
410 | size: [4, 2],
411 | rotation: 2,
412 | },
413 | televisionModern: {
414 | name: "televisionModern",
415 | size: [4, 2],
416 | rotation: 2,
417 | },
418 | kitchenFridge: {
419 | name: "kitchenFridge",
420 | size: [2, 1],
421 | rotation: 2,
422 | },
423 | kitchenFridgeLarge: {
424 | name: "kitchenFridgeLarge",
425 | size: [2, 1],
426 | },
427 | kitchenBar: {
428 | name: "kitchenBar",
429 | size: [2, 1],
430 | },
431 | kitchenCabinetCornerRound: {
432 | name: "kitchenCabinetCornerRound",
433 | size: [2, 2],
434 | },
435 | kitchenCabinetCornerInner: {
436 | name: "kitchenCabinetCornerInner",
437 | size: [2, 2],
438 | },
439 | kitchenCabinet: {
440 | name: "kitchenCabinet",
441 | size: [2, 2],
442 | },
443 | kitchenBlender: {
444 | name: "kitchenBlender",
445 | size: [1, 1],
446 | },
447 | dryer: {
448 | name: "dryer",
449 | size: [2, 2],
450 | },
451 | chairCushion: {
452 | name: "chairCushion",
453 | size: [1, 1],
454 | rotation: 2,
455 | },
456 | chair: {
457 | name: "chair",
458 | size: [1, 1],
459 | rotation: 2,
460 | },
461 | deskComputer: {
462 | name: "deskComputer",
463 | size: [3, 2],
464 | },
465 | desk: {
466 | name: "desk",
467 | size: [3, 2],
468 | },
469 | chairModernCushion: {
470 | name: "chairModernCushion",
471 | size: [1, 1],
472 | rotation: 2,
473 | },
474 | chairModernFrameCushion: {
475 | name: "chairModernFrameCushion",
476 | size: [1, 1],
477 | rotation: 2,
478 | },
479 | kitchenMicrowave: {
480 | name: "kitchenMicrowave",
481 | size: [1, 1],
482 | },
483 | coatRackStanding: {
484 | name: "coatRackStanding",
485 | size: [1, 1],
486 | },
487 | kitchenSink: {
488 | name: "kitchenSink",
489 | size: [2, 2],
490 | },
491 | lampRoundFloor: {
492 | name: "lampRoundFloor",
493 | size: [1, 1],
494 | },
495 | lampRoundTable: {
496 | name: "lampRoundTable",
497 | size: [1, 1],
498 | },
499 | lampSquareFloor: {
500 | name: "lampSquareFloor",
501 | size: [1, 1],
502 | },
503 | lampSquareTable: {
504 | name: "lampSquareTable",
505 | size: [1, 1],
506 | },
507 | toaster: {
508 | name: "toaster",
509 | size: [1, 1],
510 | },
511 | kitchenStove: {
512 | name: "kitchenStove",
513 | size: [2, 2],
514 | },
515 | laptop: {
516 | name: "laptop",
517 | size: [1, 1],
518 | },
519 | radio: {
520 | name: "radio",
521 | size: [1, 1],
522 | },
523 | speaker: {
524 | name: "speaker",
525 | size: [1, 1],
526 | },
527 | speakerSmall: {
528 | name: "speakerSmall",
529 | size: [1, 1],
530 | rotation: 2,
531 | },
532 | stoolBar: {
533 | name: "stoolBar",
534 | size: [1, 1],
535 | },
536 | stoolBarSquare: {
537 | name: "stoolBarSquare",
538 | size: [1, 1],
539 | },
540 | };
541 |
--------------------------------------------------------------------------------
/client/src/components/UI.jsx:
--------------------------------------------------------------------------------
1 | import { atom, useAtom } from "jotai";
2 | import { useEffect, useRef, useState } from "react";
3 |
4 | import { AvatarCreator } from "@readyplayerme/react-avatar-creator";
5 | import { motion } from "framer-motion";
6 | import { roomItemsAtom } from "./Room";
7 | import { roomIDAtom, socket } from "./SocketManager";
8 | export const buildModeAtom = atom(false);
9 | export const shopModeAtom = atom(false);
10 | export const draggedItemAtom = atom(null);
11 | export const draggedItemRotationAtom = atom(0);
12 |
13 | export const avatarUrlAtom = atom(
14 | localStorage.getItem("avatarURL") ||
15 | "https://models.readyplayer.me/64f0265b1db75f90dcfd9e2c.glb?meshlod=1&quality=medium"
16 | );
17 |
18 | const PasswordInput = ({ onClose, onSuccess }) => {
19 | const [password, setPassword] = useState("");
20 | const [error, setError] = useState("");
21 | // TODO: To make things properly we should have a loading state 😊
22 |
23 | const checkPassword = () => {
24 | socket.emit("passwordCheck", password);
25 | };
26 |
27 | useEffect(() => {
28 | socket.on("passwordCheckSuccess", () => {
29 | onSuccess();
30 | onClose();
31 | });
32 | socket.on("passwordCheckFail", () => {
33 | setError("Wrong password");
34 | });
35 | return () => {
36 | socket.off("passwordCheckSuccess");
37 | socket.off("passwordCheckFail");
38 | };
39 | });
40 |
41 | return (
42 |
43 |
47 |
48 |
Password
49 |
setPassword(e.target.value)}
55 | />
56 |
57 |
63 | {error &&
{error}
}
64 |
65 |
66 |
67 | );
68 | };
69 |
70 | export const UI = () => {
71 | const [buildMode, setBuildMode] = useAtom(buildModeAtom);
72 | const [shopMode, setShopMode] = useAtom(shopModeAtom);
73 | const [draggedItem, setDraggedItem] = useAtom(draggedItemAtom);
74 | const [draggedItemRotation, setDraggedItemRotation] = useAtom(
75 | draggedItemRotationAtom
76 | );
77 | const [_roomItems, setRoomItems] = useAtom(roomItemsAtom);
78 | const [passwordMode, setPasswordMode] = useState(false);
79 | const [avatarMode, setAvatarMode] = useState(false);
80 | const [avatarUrl, setAvatarUrl] = useAtom(avatarUrlAtom);
81 | const [roomID, setRoomID] = useAtom(roomIDAtom);
82 | const [passwordCorrectForRoom, setPasswordCorrectForRoom] = useState(false);
83 | const leaveRoom = () => {
84 | socket.emit("leaveRoom");
85 | setRoomID(null);
86 | setBuildMode(false);
87 | setShopMode(false);
88 | };
89 | useEffect(() => {
90 | setPasswordCorrectForRoom(false); // PS: this is an ugly shortcut
91 | }, [roomID]);
92 |
93 | const ref = useRef();
94 | const [chatMessage, setChatMessage] = useState("");
95 | const sendChatMessage = () => {
96 | if (chatMessage.length > 0) {
97 | socket.emit("chatMessage", chatMessage);
98 | setChatMessage("");
99 | }
100 | };
101 |
102 | return (
103 | <>
104 |
110 | {avatarMode && (
111 | {
115 | let newAvatarUrl =
116 | event.data.url === avatarUrl.split("?")[0]
117 | ? event.data.url.split("?")[0] + "?" + new Date().getTime()
118 | : event.data.url;
119 | newAvatarUrl +=
120 | (newAvatarUrl.includes("?") ? "&" : "?") +
121 | "meshlod=1&quality=medium";
122 | setAvatarUrl(newAvatarUrl);
123 | localStorage.setItem("avatarURL", newAvatarUrl);
124 | if (roomID) {
125 | socket.emit("characterAvatarUpdate", newAvatarUrl);
126 | }
127 | setAvatarMode(false);
128 | }}
129 | />
130 | )}
131 | {passwordMode && (
132 | setPasswordMode(false)}
134 | onSuccess={() => {
135 | setBuildMode(true);
136 | setPasswordCorrectForRoom(true);
137 | }}
138 | />
139 | )}
140 |
141 | {roomID && !shopMode && !buildMode && (
142 |
143 |
{
148 | if (e.key === "Enter") {
149 | sendChatMessage();
150 | }
151 | }}
152 | value={chatMessage}
153 | onChange={(e) => setChatMessage(e.target.value)}
154 | />
155 |
174 |
175 | )}
176 |
177 | {roomID && !shopMode && !buildMode && (
178 |
184 | )}
185 | {/* BACK */}
186 | {(buildMode || shopMode) && draggedItem === null && (
187 |
208 | )}
209 | {/* AVATAR */}
210 | {!buildMode && !shopMode && (
211 |
230 | )}
231 | {/* DANCE */}
232 | {roomID && !buildMode && !shopMode && (
233 |
252 | )}
253 | {/* BUILD */}
254 | {roomID && !buildMode && !shopMode && (
255 |
280 | )}
281 | {/* SHOP */}
282 | {buildMode && !shopMode && draggedItem === null && (
283 |
302 | )}
303 |
304 | {/* ROTATE */}
305 | {buildMode && !shopMode && draggedItem !== null && (
306 |
329 | )}
330 | {/* CANCEL */}
331 | {buildMode && !shopMode && draggedItem !== null && (
332 |
351 | )}
352 | {/* REMOVE ITEM */}
353 | {buildMode && !shopMode && draggedItem !== null && (
354 |
380 | )}
381 |
382 |
383 |
384 | >
385 | );
386 | };
387 |
--------------------------------------------------------------------------------
/client/public/fonts/Inter_Bold.json:
--------------------------------------------------------------------------------
1 | {"glyphs":{"A":{"ha":1039,"x_min":33,"x_max":1005,"o":"m 262 0 l 33 0 l 382 1010 l 657 1010 l 1005 0 l 776 0 l 523 779 l 515 779 l 262 0 m 248 397 l 788 397 l 788 230 l 248 230 l 248 397 z "},"B":{"ha":918,"x_min":88,"x_max":867,"o":"m 88 0 l 88 1010 l 492 1010 q 678 977 604 1010 q 790 886 753 944 q 828 751 828 827 q 804 647 828 692 q 739 574 780 603 q 645 534 698 546 l 645 524 q 753 492 703 522 q 836 408 804 462 q 867 279 867 354 q 827 136 867 199 q 710 36 788 73 q 519 0 633 0 l 88 0 m 301 175 l 475 175 q 606 209 565 175 q 647 300 647 243 q 626 374 647 342 q 569 425 606 406 q 480 443 532 443 l 301 443 l 301 175 m 301 587 l 460 587 q 538 603 504 587 q 592 647 572 618 q 612 716 612 676 q 573 804 612 770 q 464 837 535 837 l 301 837 l 301 587 z "},"C":{"ha":1045,"x_min":70,"x_max":979,"o":"m 979 656 l 763 656 q 739 731 757 698 q 692 787 721 764 q 626 823 663 810 q 545 835 589 835 q 409 796 467 835 q 319 684 351 758 q 287 505 287 610 q 319 324 287 397 q 409 213 351 250 q 544 175 468 175 q 624 186 587 175 q 689 220 660 198 q 737 273 718 242 q 763 345 756 305 l 979 344 q 937 210 971 275 q 848 95 904 146 q 715 16 792 45 q 541 -14 638 -14 q 299 47 405 -14 q 131 224 193 109 q 70 505 70 340 q 132 786 70 670 q 301 963 194 902 q 541 1024 407 1024 q 704 999 628 1024 q 837 927 779 975 q 932 812 895 880 q 979 656 969 744 z "},"D":{"ha":1010,"x_min":88,"x_max":940,"o":"m 446 0 l 88 0 l 88 1010 l 449 1010 q 711 950 601 1010 q 881 776 821 889 q 940 506 940 663 q 881 235 940 348 q 710 61 821 121 q 446 0 600 0 m 301 183 l 437 183 q 597 217 532 183 q 694 322 661 251 q 727 506 727 393 q 694 689 727 618 q 597 794 661 760 q 437 827 532 827 l 301 827 l 301 183 z "},"E":{"ha":851,"x_min":88,"x_max":770,"o":"m 88 0 l 88 1010 l 768 1010 l 768 834 l 301 834 l 301 593 l 733 593 l 733 417 l 301 417 l 301 176 l 770 176 l 770 0 l 88 0 z "},"F":{"ha":812,"x_min":88,"x_max":757,"o":"m 88 0 l 88 1010 l 757 1010 l 757 834 l 301 834 l 301 593 l 712 593 l 712 417 l 301 417 l 301 0 l 88 0 z "},"G":{"ha":1056,"x_min":70,"x_max":984,"o":"m 758 684 q 728 747 747 720 q 683 795 710 775 q 622 825 656 814 q 546 835 587 835 q 410 797 469 835 q 319 685 352 758 q 287 506 287 612 q 319 327 287 400 q 409 214 351 253 q 548 175 468 175 q 672 201 620 175 q 751 274 724 227 q 778 386 778 322 l 822 380 l 561 380 l 561 541 l 984 541 l 984 413 q 928 185 984 280 q 773 38 872 89 q 547 -14 674 -14 q 297 49 405 -14 q 130 228 190 112 q 70 504 70 344 q 106 723 70 627 q 206 887 142 820 q 357 989 271 954 q 543 1024 442 1024 q 702 999 628 1024 q 834 929 776 974 q 928 821 891 883 q 975 684 964 759 l 758 684 z "},"H":{"ha":1036,"x_min":88,"x_max":948,"o":"m 88 0 l 88 1010 l 301 1010 l 301 593 l 735 593 l 735 1010 l 948 1010 l 948 0 l 735 0 l 735 417 l 301 417 l 301 0 l 88 0 z "},"I":{"ha":390,"x_min":88,"x_max":301,"o":"m 301 1010 l 301 0 l 88 0 l 88 1010 l 301 1010 z "},"J":{"ha":792,"x_min":32,"x_max":703,"o":"m 492 1010 l 703 1010 l 703 306 q 660 136 703 208 q 539 25 616 64 q 359 -14 461 -14 q 193 18 267 -14 q 75 117 119 51 q 33 284 32 183 l 245 284 q 262 216 246 244 q 305 172 277 187 q 369 157 332 157 q 436 174 409 157 q 478 224 464 191 q 492 306 492 257 l 492 1010 z "},"K":{"ha":958,"x_min":88,"x_max":939,"o":"m 88 0 l 88 1010 l 301 1010 l 301 565 l 315 565 l 678 1010 l 934 1010 l 559 558 l 939 0 l 683 0 l 406 415 l 301 287 l 301 0 l 88 0 z "},"L":{"ha":788,"x_min":88,"x_max":734,"o":"m 88 0 l 88 1010 l 301 1010 l 301 176 l 734 176 l 734 0 l 88 0 z "},"M":{"ha":1271,"x_min":88,"x_max":1183,"o":"m 88 1010 l 351 1010 l 629 331 l 641 331 l 919 1010 l 1183 1010 l 1183 0 l 976 0 l 976 657 l 967 657 l 706 5 l 565 5 l 303 660 l 295 660 l 295 0 l 88 0 l 88 1010 z "},"N":{"ha":1021,"x_min":88,"x_max":933,"o":"m 933 1010 l 933 0 l 748 0 l 309 636 l 301 636 l 301 0 l 88 0 l 88 1010 l 275 1010 l 711 375 l 720 375 l 720 1010 l 933 1010 z "},"O":{"ha":1086,"x_min":70,"x_max":1016,"o":"m 1016 505 q 954 224 1016 340 q 784 47 891 108 q 543 -14 677 -14 q 301 47 408 -14 q 132 224 194 109 q 70 505 70 340 q 132 786 70 670 q 301 963 194 902 q 543 1024 408 1024 q 784 963 677 1024 q 954 786 891 902 q 1016 505 1016 670 m 799 505 q 768 686 799 612 q 678 797 736 759 q 543 835 620 835 q 408 797 466 835 q 318 686 350 759 q 287 505 287 612 q 318 325 287 398 q 408 213 350 251 q 543 175 466 175 q 678 213 620 175 q 768 325 736 251 q 799 505 799 398 z "},"P":{"ha":900,"x_min":88,"x_max":848,"o":"m 88 0 l 88 1010 l 486 1010 q 682 966 601 1010 q 806 846 763 923 q 848 668 848 768 q 805 490 848 567 q 679 370 762 413 q 481 327 597 327 l 227 327 l 227 499 l 446 499 q 548 520 508 499 q 608 580 588 542 q 628 668 628 618 q 608 756 628 718 q 548 815 588 794 q 445 836 508 836 l 301 836 l 301 0 l 88 0 z "},"Q":{"ha":1087,"x_min":70,"x_max":1016,"o":"m 469 351 l 651 351 l 742 234 l 832 129 l 1001 -83 l 801 -83 l 685 60 l 625 145 l 469 351 m 1016 505 q 954 224 1016 340 q 784 47 891 108 q 543 -14 677 -14 q 301 47 408 -14 q 132 224 194 109 q 70 505 70 340 q 132 786 70 670 q 301 963 194 902 q 543 1024 408 1024 q 784 963 677 1024 q 954 786 891 902 q 1016 505 1016 670 m 799 505 q 768 686 799 612 q 678 797 736 759 q 543 835 620 835 q 408 797 466 835 q 318 686 350 759 q 287 505 287 612 q 318 325 287 398 q 408 213 350 251 q 543 175 466 175 q 678 213 620 175 q 768 325 736 251 q 799 505 799 398 z "},"R":{"ha":911,"x_min":88,"x_max":884,"o":"m 88 0 l 88 1010 l 486 1010 q 682 969 601 1010 q 806 854 763 929 q 848 680 848 780 q 805 507 848 580 q 679 397 762 435 q 481 358 597 358 l 214 358 l 214 530 l 446 530 q 548 546 508 530 q 608 597 588 563 q 628 680 628 630 q 608 765 628 730 q 548 818 588 799 q 445 836 507 836 l 301 836 l 301 0 l 88 0 m 633 460 l 884 0 l 649 0 l 403 460 l 633 460 z "},"S":{"ha":909,"x_min":55,"x_max":854,"o":"m 636 720 q 585 812 630 779 q 463 845 540 845 q 375 831 411 845 q 320 791 339 816 q 301 732 301 765 q 312 685 300 705 q 347 650 325 665 q 399 625 369 636 q 461 607 428 615 l 551 585 q 673 546 618 571 q 768 485 728 521 q 831 400 809 449 q 854 289 854 352 q 807 128 854 196 q 673 23 761 60 q 462 -14 585 -14 q 249 23 340 -14 q 108 134 159 61 q 55 317 58 208 l 262 317 q 291 233 265 266 q 361 182 317 199 q 460 165 404 165 q 554 181 514 165 q 617 224 594 196 q 639 289 639 253 q 619 346 639 323 q 561 386 599 369 q 467 415 522 402 l 357 443 q 155 540 229 474 q 82 718 81 606 q 131 878 81 810 q 267 985 181 947 q 465 1024 354 1024 q 661 985 577 1024 q 792 878 745 947 q 840 720 839 810 l 636 720 z "},"T":{"ha":928,"x_min":49,"x_max":879,"o":"m 49 834 l 49 1010 l 879 1010 l 879 834 l 570 834 l 570 0 l 359 0 l 359 834 l 49 834 z "},"U":{"ha":1013,"x_min":88,"x_max":925,"o":"m 712 1010 l 925 1010 l 925 354 q 873 161 925 244 q 726 32 820 78 q 507 -14 632 -14 q 287 32 381 -14 q 140 161 192 78 q 88 354 88 244 l 88 1010 l 301 1010 l 301 372 q 327 270 301 315 q 399 199 352 225 q 507 174 445 174 q 615 199 569 174 q 686 270 661 225 q 712 372 712 315 l 712 1010 z "},"V":{"ha":1039,"x_min":33,"x_max":1005,"o":"m 270 1010 l 514 243 l 524 243 l 768 1010 l 1005 1010 l 657 0 l 382 0 l 33 1010 l 270 1010 z "},"W":{"ha":1439,"x_min":26,"x_max":1413,"o":"m 315 0 l 26 1010 l 259 1010 l 427 308 l 435 308 l 619 1010 l 819 1010 l 1003 307 l 1012 307 l 1179 1010 l 1413 1010 l 1124 0 l 915 0 l 723 660 l 715 660 l 523 0 l 315 0 z "},"X":{"ha":992,"x_min":40,"x_max":952,"o":"m 288 1010 l 492 666 l 500 666 l 704 1010 l 945 1010 l 637 505 l 952 0 l 707 0 l 500 345 l 492 345 l 285 0 l 40 0 l 356 505 l 46 1010 l 288 1010 z "},"Y":{"ha":1006,"x_min":29,"x_max":978,"o":"m 29 1010 l 268 1010 l 498 575 l 508 575 l 738 1010 l 978 1010 l 609 357 l 609 0 l 397 0 l 397 357 l 29 1010 z "},"Z":{"ha":926,"x_min":76,"x_max":850,"o":"m 77 0 l 77 127 l 581 834 l 76 834 l 76 1010 l 849 1010 l 849 883 l 345 176 l 850 176 l 850 0 l 77 0 z "},"a":{"ha":806,"x_min":48,"x_max":727,"o":"m 300 -14 q 171 11 227 -14 q 81 87 114 36 q 48 212 48 137 q 72 318 48 275 q 135 387 95 361 q 226 426 175 413 q 333 445 277 439 q 439 458 399 452 q 498 476 480 464 q 516 513 516 489 l 516 516 q 487 588 516 563 q 404 614 458 614 q 314 589 347 614 q 269 527 280 564 l 75 543 q 133 662 90 612 q 245 740 177 713 q 405 767 314 767 q 526 753 468 767 q 629 707 584 738 q 700 627 674 676 q 727 511 727 579 l 727 0 l 527 0 l 527 105 l 521 105 q 472 43 503 70 q 399 1 442 16 q 300 -14 356 -14 m 360 131 q 442 149 406 131 q 498 199 477 168 q 518 271 518 231 l 518 351 q 491 340 508 345 q 453 330 474 334 q 410 323 432 326 q 372 317 389 320 q 307 300 335 312 q 264 268 280 288 q 249 218 249 248 q 280 153 249 176 q 360 131 312 131 z "},"b":{"ha":882,"x_min":88,"x_max":827,"o":"m 88 0 l 88 1010 l 298 1010 l 298 630 l 304 630 q 345 693 318 661 q 414 746 371 725 q 520 767 456 767 q 673 724 603 767 q 785 595 743 681 q 827 378 827 508 q 786 164 827 251 q 675 32 745 77 q 519 -12 606 -12 q 416 8 458 -12 q 346 59 373 28 q 304 121 319 90 l 295 121 l 295 0 l 88 0 m 293 379 q 312 261 293 311 q 366 183 331 211 q 453 155 402 155 q 540 183 504 155 q 594 262 575 212 q 612 379 612 313 q 594 494 612 444 q 540 572 576 544 q 453 600 505 600 q 366 573 401 600 q 312 496 331 546 q 293 379 293 446 z "},"c":{"ha":816,"x_min":53,"x_max":764,"o":"m 426 -15 q 226 35 310 -15 q 98 173 143 84 q 53 376 53 261 q 98 580 53 492 q 227 718 144 668 q 425 767 310 767 q 599 731 524 767 q 717 630 673 695 q 764 477 760 565 l 566 477 q 522 569 558 534 q 429 604 486 604 q 344 577 380 604 q 287 501 307 551 q 267 379 267 450 q 287 255 267 306 q 343 178 307 205 q 429 151 380 151 q 493 166 465 151 q 541 209 522 181 q 566 278 560 238 l 764 278 q 717 125 760 191 q 601 22 675 59 q 426 -15 527 -15 z "},"d":{"ha":882,"x_min":56,"x_max":794,"o":"m 363 -12 q 207 32 277 -12 q 96 164 137 77 q 56 378 56 251 q 98 595 56 508 q 209 724 140 681 q 363 767 279 767 q 469 746 426 767 q 538 693 511 725 q 578 630 564 661 l 584 630 l 584 1010 l 794 1010 l 794 0 l 587 0 l 587 121 l 578 121 q 536 59 563 90 q 467 8 509 28 q 363 -12 424 -12 m 430 155 q 516 183 480 155 q 570 261 551 211 q 589 379 589 311 q 570 496 589 446 q 516 573 551 546 q 430 600 480 600 q 342 572 378 600 q 289 494 307 544 q 270 379 270 444 q 289 262 270 313 q 343 183 307 212 q 430 155 378 155 z "},"e":{"ha":830,"x_min":53,"x_max":777,"o":"m 429 -15 q 228 33 312 -15 q 99 168 144 80 q 53 375 53 255 q 99 581 53 492 q 227 718 144 669 q 421 767 309 767 q 561 744 496 767 q 674 672 625 720 q 750 552 723 624 q 777 383 777 479 l 777 325 l 137 325 l 137 455 l 579 455 q 559 536 579 501 q 505 591 540 571 q 424 611 470 611 q 340 589 376 611 q 282 530 303 567 q 261 448 261 493 l 261 325 q 282 227 261 268 q 341 164 303 186 q 433 142 380 142 q 497 152 468 142 q 546 182 526 162 q 578 230 567 201 l 772 217 q 712 95 758 147 q 595 14 666 43 q 429 -15 523 -15 z "},"f":{"ha":536,"x_min":24,"x_max":528,"o":"m 491 758 l 491 600 l 24 600 l 24 758 l 491 758 m 131 0 l 131 812 q 163 949 131 895 q 252 1030 195 1003 q 379 1057 308 1057 q 468 1050 428 1057 q 528 1037 508 1043 l 490 879 q 460 886 478 883 q 423 890 442 890 q 359 868 377 890 q 340 808 340 847 l 340 0 l 131 0 z "},"g":{"ha":879,"x_min":56,"x_max":796,"o":"m 425 -300 q 250 -272 323 -300 q 135 -196 178 -244 q 79 -89 92 -148 l 273 -63 q 301 -105 282 -85 q 352 -137 321 -125 q 430 -149 384 -149 q 543 -116 499 -149 q 588 -4 588 -82 l 588 134 l 579 134 q 538 74 565 103 q 467 29 510 46 q 363 11 423 11 q 208 51 278 11 q 97 172 138 90 q 56 380 56 254 q 98 595 56 509 q 209 725 140 682 q 363 767 279 767 q 469 746 426 767 q 538 693 512 725 q 579 630 565 661 l 587 630 l 587 758 l 796 758 l 796 -7 q 748 -169 796 -104 q 617 -267 701 -234 q 425 -300 534 -300 m 430 169 q 516 194 480 169 q 570 267 551 219 q 589 381 589 315 q 570 497 589 448 q 516 573 551 546 q 430 600 480 600 q 342 572 378 600 q 289 495 307 545 q 270 381 270 446 q 289 268 270 316 q 343 195 307 220 q 430 169 378 169 z "},"h":{"ha":867,"x_min":84,"x_max":786,"o":"m 294 438 l 294 0 l 84 0 l 84 1010 l 288 1010 l 288 624 l 297 624 q 380 729 323 691 q 523 767 437 767 q 661 733 602 767 q 753 635 720 699 q 785 482 786 571 l 785 0 l 575 0 l 575 445 q 540 554 576 515 q 440 593 504 593 q 364 575 397 593 q 313 522 331 556 q 294 438 294 487 z "},"i":{"ha":378,"x_min":76,"x_max":303,"o":"m 84 0 l 84 758 l 294 758 l 294 0 l 84 0 m 189 855 q 109 887 143 855 q 76 962 76 918 q 109 1036 76 1005 q 189 1068 143 1068 q 270 1036 236 1068 q 303 962 303 1005 q 270 887 303 918 q 189 855 236 855 z "},"j":{"ha":378,"x_min":-36,"x_max":302,"o":"m 84 758 l 294 758 l 294 -37 q 259 -180 294 -125 q 161 -259 225 -234 q 7 -284 96 -284 q -14 -284 -4 -284 q -36 -283 -24 -284 l -36 -119 q -21 -120 -27 -119 q -8 -120 -15 -120 q 63 -98 43 -120 q 84 -34 84 -77 l 84 758 m 188 855 q 109 887 142 855 q 75 962 75 918 q 109 1036 75 1005 q 188 1068 142 1068 q 269 1036 236 1068 q 302 962 302 1005 q 269 887 302 918 q 188 855 236 855 z "},"k":{"ha":808,"x_min":84,"x_max":803,"o":"m 274 218 l 275 470 l 305 470 l 548 758 l 789 758 l 463 377 l 413 377 l 274 218 m 84 0 l 84 1010 l 294 1010 l 294 0 l 84 0 m 557 0 l 334 330 l 474 478 l 803 0 l 557 0 z "},"l":{"ha":378,"x_min":84,"x_max":294,"o":"m 294 1010 l 294 0 l 84 0 l 84 1010 l 294 1010 z "},"m":{"ha":1267,"x_min":84,"x_max":1185,"o":"m 84 0 l 84 758 l 284 758 l 284 624 l 293 624 q 372 729 317 690 q 504 767 427 767 q 637 729 582 767 q 710 624 691 690 l 718 624 q 802 728 741 689 q 946 767 863 767 q 1118 700 1052 767 q 1185 509 1185 633 l 1185 0 l 975 0 l 975 468 q 942 563 975 531 q 858 594 908 594 q 768 558 800 594 q 736 463 736 522 l 736 0 l 533 0 l 533 472 q 501 561 533 528 q 417 594 469 594 q 354 577 382 594 q 310 528 327 559 q 294 455 294 497 l 294 0 l 84 0 z "},"n":{"ha":864,"x_min":84,"x_max":782,"o":"m 294 438 l 294 0 l 84 0 l 84 758 l 284 758 l 284 624 l 293 624 q 377 729 318 690 q 521 767 436 767 q 658 733 600 767 q 750 635 717 698 q 782 482 782 571 l 782 0 l 572 0 l 572 445 q 537 554 573 514 q 437 593 501 593 q 363 575 395 593 q 312 522 330 556 q 294 438 294 487 z "},"o":{"ha":852,"x_min":53,"x_max":799,"o":"m 426 -15 q 228 34 311 -15 q 99 171 144 83 q 53 376 53 259 q 99 581 53 493 q 228 718 144 669 q 426 767 311 767 q 625 718 541 767 q 754 581 708 669 q 799 376 799 493 q 754 171 799 259 q 625 34 708 83 q 426 -15 541 -15 m 427 148 q 514 178 479 148 q 567 259 549 208 q 585 377 585 311 q 567 495 585 443 q 514 577 549 547 q 427 607 479 607 q 339 577 374 607 q 285 495 303 547 q 267 377 267 443 q 285 259 267 311 q 339 178 303 208 q 427 148 374 148 z "},"p":{"ha":878,"x_min":84,"x_max":823,"o":"m 84 -284 l 84 758 l 291 758 l 291 630 l 300 630 q 341 693 314 661 q 410 746 367 725 q 516 767 452 767 q 669 724 599 767 q 781 595 739 681 q 823 378 823 508 q 782 164 823 251 q 672 32 741 77 q 515 -12 602 -12 q 412 8 454 -12 q 342 59 369 28 q 300 121 315 90 l 294 121 l 294 -284 l 84 -284 m 290 379 q 308 261 290 311 q 363 183 327 211 q 449 155 398 155 q 536 183 500 155 q 590 262 571 212 q 608 379 608 313 q 590 494 608 444 q 536 572 572 544 q 449 600 501 600 q 362 573 398 600 q 308 496 327 546 q 290 379 290 446 z "},"q":{"ha":878,"x_min":56,"x_max":794,"o":"m 584 -284 l 584 121 l 578 121 q 536 59 563 90 q 467 8 509 28 q 363 -12 424 -12 q 207 32 277 -12 q 96 164 137 77 q 56 378 56 251 q 98 595 56 508 q 209 724 140 681 q 363 767 279 767 q 469 746 426 767 q 538 693 511 725 q 578 630 564 661 l 587 630 l 587 758 l 794 758 l 794 -284 l 584 -284 m 430 155 q 516 183 480 155 q 570 261 551 211 q 589 379 589 311 q 570 496 589 446 q 516 573 551 546 q 430 600 480 600 q 342 572 378 600 q 289 494 307 544 q 270 379 270 444 q 289 262 270 313 q 343 183 307 212 q 430 155 378 155 z "},"r":{"ha":568,"x_min":84,"x_max":544,"o":"m 84 0 l 84 758 l 288 758 l 288 625 l 295 625 q 365 732 316 696 q 477 768 414 768 q 511 766 493 768 q 544 761 530 764 l 544 575 q 503 582 529 579 q 455 586 476 586 q 372 566 408 586 q 315 510 336 546 q 294 429 294 475 l 294 0 l 84 0 z "},"s":{"ha":780,"x_min":50,"x_max":731,"o":"m 714 542 l 522 530 q 501 574 517 554 q 458 606 484 594 q 395 618 432 618 q 313 598 346 618 q 279 544 279 578 q 301 498 279 516 q 375 468 323 479 l 512 440 q 677 367 623 417 q 731 235 731 317 q 688 104 731 160 q 568 17 644 48 q 394 -15 493 -15 q 155 48 244 -15 q 50 219 66 111 l 257 230 q 302 161 266 184 q 395 137 338 137 q 484 158 450 137 q 518 214 517 180 q 494 261 517 242 q 421 289 470 279 l 290 315 q 125 392 179 337 q 71 532 71 447 q 110 657 71 605 q 222 739 150 710 q 392 767 294 767 q 618 707 535 767 q 714 542 700 646 z "},"t":{"ha":540,"x_min":31,"x_max":501,"o":"m 487 758 l 487 600 l 31 600 l 31 758 l 487 758 m 134 939 l 344 939 l 344 233 q 353 188 344 204 q 378 165 362 172 q 415 159 394 159 q 445 162 430 159 q 468 166 460 164 l 501 9 q 456 -2 485 4 q 387 -10 428 -9 q 254 10 311 -13 q 165 82 197 33 q 134 205 134 131 l 134 939 z "},"u":{"ha":864,"x_min":84,"x_max":780,"o":"m 570 323 l 570 758 l 780 758 l 780 0 l 578 0 l 578 138 l 570 138 q 485 31 545 71 q 340 -10 426 -10 q 207 25 264 -10 q 117 123 149 59 q 84 275 84 186 l 84 758 l 294 758 l 294 313 q 330 207 294 246 q 425 168 365 168 q 496 185 463 168 q 550 237 529 203 q 570 323 570 272 z "},"v":{"ha":814,"x_min":24,"x_max":790,"o":"m 790 758 l 525 0 l 289 0 l 24 758 l 246 758 l 403 216 l 411 216 l 568 758 l 790 758 z "},"w":{"ha":1181,"x_min":27,"x_max":1153,"o":"m 233 0 l 27 758 l 240 758 l 357 249 l 364 249 l 486 758 l 695 758 l 819 252 l 826 252 l 941 758 l 1153 758 l 947 0 l 725 0 l 595 476 l 585 476 l 455 0 l 233 0 z "},"x":{"ha":797,"x_min":35,"x_max":763,"o":"m 259 758 l 399 493 l 541 758 l 757 758 l 537 379 l 763 0 l 548 0 l 399 262 l 252 0 l 35 0 l 259 379 l 42 758 l 259 758 z "},"y":{"ha":814,"x_min":24,"x_max":790,"o":"m 214 -284 q 139 -278 174 -284 q 81 -262 104 -272 l 129 -106 q 196 -118 166 -117 q 247 -104 225 -119 q 283 -54 269 -89 l 295 -22 l 24 758 l 245 758 l 401 201 l 409 201 l 568 758 l 790 758 l 496 -82 q 438 -189 474 -143 q 347 -259 402 -234 q 214 -284 291 -284 z "},"z":{"ha":794,"x_min":80,"x_max":717,"o":"m 80 0 l 80 125 l 451 584 l 451 590 l 93 590 l 93 758 l 704 758 l 704 621 l 356 173 l 356 168 l 717 168 l 717 0 l 80 0 z "}},"familyName":"Inter","ascender":1345,"descender":-335,"underlinePosition":-229,"underlineThickness":95,"boundingBox":{"yMin":-444,"xMin":-1026,"yMax":1515,"xMax":3588},"resolution":1000,"original_font_information":{"format":0,"copyright":"Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)","fontFamily":"Inter","fontSubfamily":"Bold","uniqueID":"3.019;RSMS;Inter-Bold","fullName":"Inter Bold","version":"Version 3.019;git-0a5106e0b","postScriptName":"Inter-Bold","trademark":"Inter UI and Inter is a trademark of rsms.","manufacturer":"rsms","designer":"Rasmus Andersson","manufacturerURL":"https://rsms.me/","designerURL":"https://rsms.me/","licence":"This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: http://scripts.sil.org/OFL","licenceURL":"http://scripts.sil.org/OFL","compatibleFullName":"Inter","unknown1":"Open digits","unknown2":"Disambiguation","unknown3":"r curves into round neighbors","unknown4":"Disambiguation without slashed zero","unknown5":"Alternate one","unknown6":"Open four","unknown7":"Open six","unknown8":"Open nine","unknown9":"Lower-case L with tail","unknown10":"r with curved tail","unknown11":"Alternate German double s","unknown12":"Upper-case i with serif","unknown13":"Flat-top three","unknown14":"Captital G with spur","unknown15":"Single-storey a","unknown16":"Weight","unknown17":"Slant","unknown18":"Regular","unknown19":"Bold"},"cssFontWeight":"bold","cssFontStyle":"normal"}
--------------------------------------------------------------------------------
/server/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@socket.io/component-emitter@~3.1.0":
6 | version "3.1.0"
7 | resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
8 | integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
9 |
10 | "@types/cookie@^0.4.1":
11 | version "0.4.1"
12 | resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
13 | integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
14 |
15 | "@types/cors@^2.8.12":
16 | version "2.8.13"
17 | resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
18 | integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==
19 | dependencies:
20 | "@types/node" "*"
21 |
22 | "@types/node@*", "@types/node@>=10.0.0":
23 | version "20.4.6"
24 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.6.tgz#b66b66c9bb5d49b199f03399e341c9d6036e9e88"
25 | integrity sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA==
26 |
27 | abbrev@1:
28 | version "1.1.1"
29 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
30 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
31 |
32 | accepts@~1.3.4:
33 | version "1.3.8"
34 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
35 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
36 | dependencies:
37 | mime-types "~2.1.34"
38 | negotiator "0.6.3"
39 |
40 | anymatch@~3.1.2:
41 | version "3.1.3"
42 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
43 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
44 | dependencies:
45 | normalize-path "^3.0.0"
46 | picomatch "^2.0.4"
47 |
48 | balanced-match@^1.0.0:
49 | version "1.0.2"
50 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
51 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
52 |
53 | base64id@2.0.0, base64id@~2.0.0:
54 | version "2.0.0"
55 | resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
56 | integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
57 |
58 | binary-extensions@^2.0.0:
59 | version "2.2.0"
60 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
61 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
62 |
63 | brace-expansion@^1.1.7:
64 | version "1.1.11"
65 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
66 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
67 | dependencies:
68 | balanced-match "^1.0.0"
69 | concat-map "0.0.1"
70 |
71 | braces@~3.0.2:
72 | version "3.0.2"
73 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
74 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
75 | dependencies:
76 | fill-range "^7.0.1"
77 |
78 | chokidar@^3.5.2:
79 | version "3.5.3"
80 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
81 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
82 | dependencies:
83 | anymatch "~3.1.2"
84 | braces "~3.0.2"
85 | glob-parent "~5.1.2"
86 | is-binary-path "~2.1.0"
87 | is-glob "~4.0.1"
88 | normalize-path "~3.0.0"
89 | readdirp "~3.6.0"
90 | optionalDependencies:
91 | fsevents "~2.3.2"
92 |
93 | concat-map@0.0.1:
94 | version "0.0.1"
95 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
96 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
97 |
98 | cookie@~0.4.1:
99 | version "0.4.2"
100 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
101 | integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
102 |
103 | cors@~2.8.5:
104 | version "2.8.5"
105 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
106 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
107 | dependencies:
108 | object-assign "^4"
109 | vary "^1"
110 |
111 | debug@^3.2.7:
112 | version "3.2.7"
113 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
114 | integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
115 | dependencies:
116 | ms "^2.1.1"
117 |
118 | debug@~4.3.1, debug@~4.3.2:
119 | version "4.3.4"
120 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
121 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
122 | dependencies:
123 | ms "2.1.2"
124 |
125 | engine.io-parser@~5.2.1:
126 | version "5.2.1"
127 | resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.1.tgz#9f213c77512ff1a6cc0c7a86108a7ffceb16fcfb"
128 | integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==
129 |
130 | engine.io@~6.5.2:
131 | version "6.5.2"
132 | resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.2.tgz#769348ced9d56bd47bd83d308ec1c3375e85937c"
133 | integrity sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==
134 | dependencies:
135 | "@types/cookie" "^0.4.1"
136 | "@types/cors" "^2.8.12"
137 | "@types/node" ">=10.0.0"
138 | accepts "~1.3.4"
139 | base64id "2.0.0"
140 | cookie "~0.4.1"
141 | cors "~2.8.5"
142 | debug "~4.3.1"
143 | engine.io-parser "~5.2.1"
144 | ws "~8.11.0"
145 |
146 | fill-range@^7.0.1:
147 | version "7.0.1"
148 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
149 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
150 | dependencies:
151 | to-regex-range "^5.0.1"
152 |
153 | fsevents@~2.3.2:
154 | version "2.3.2"
155 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
156 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
157 |
158 | glob-parent@~5.1.2:
159 | version "5.1.2"
160 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
161 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
162 | dependencies:
163 | is-glob "^4.0.1"
164 |
165 | has-flag@^3.0.0:
166 | version "3.0.0"
167 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
168 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
169 |
170 | heap@0.2.5:
171 | version "0.2.5"
172 | resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.5.tgz#713b65590ebcc40fcbeeaf55e851694092b39af1"
173 | integrity sha512-G7HLD+WKcrOyJP5VQwYZNC3Z6FcQ7YYjEFiFoIj8PfEr73mu421o8B1N5DKUcc8K37EsJ2XXWA8DtrDz/2dReg==
174 |
175 | ignore-by-default@^1.0.1:
176 | version "1.0.1"
177 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
178 | integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
179 |
180 | is-binary-path@~2.1.0:
181 | version "2.1.0"
182 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
183 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
184 | dependencies:
185 | binary-extensions "^2.0.0"
186 |
187 | is-extglob@^2.1.1:
188 | version "2.1.1"
189 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
190 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
191 |
192 | is-glob@^4.0.1, is-glob@~4.0.1:
193 | version "4.0.3"
194 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
195 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
196 | dependencies:
197 | is-extglob "^2.1.1"
198 |
199 | is-number@^7.0.0:
200 | version "7.0.0"
201 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
202 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
203 |
204 | lru-cache@^6.0.0:
205 | version "6.0.0"
206 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
207 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
208 | dependencies:
209 | yallist "^4.0.0"
210 |
211 | mime-db@1.52.0:
212 | version "1.52.0"
213 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
214 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
215 |
216 | mime-types@~2.1.34:
217 | version "2.1.35"
218 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
219 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
220 | dependencies:
221 | mime-db "1.52.0"
222 |
223 | minimatch@^3.1.2:
224 | version "3.1.2"
225 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
226 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
227 | dependencies:
228 | brace-expansion "^1.1.7"
229 |
230 | ms@2.1.2:
231 | version "2.1.2"
232 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
233 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
234 |
235 | ms@^2.1.1:
236 | version "2.1.3"
237 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
238 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
239 |
240 | negotiator@0.6.3:
241 | version "0.6.3"
242 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
243 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
244 |
245 | nodemon@^3.0.1:
246 | version "3.0.1"
247 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.0.1.tgz#affe822a2c5f21354466b2fc8ae83277d27dadc7"
248 | integrity sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==
249 | dependencies:
250 | chokidar "^3.5.2"
251 | debug "^3.2.7"
252 | ignore-by-default "^1.0.1"
253 | minimatch "^3.1.2"
254 | pstree.remy "^1.1.8"
255 | semver "^7.5.3"
256 | simple-update-notifier "^2.0.0"
257 | supports-color "^5.5.0"
258 | touch "^3.1.0"
259 | undefsafe "^2.0.5"
260 |
261 | nopt@~1.0.10:
262 | version "1.0.10"
263 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
264 | integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
265 | dependencies:
266 | abbrev "1"
267 |
268 | normalize-path@^3.0.0, normalize-path@~3.0.0:
269 | version "3.0.0"
270 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
271 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
272 |
273 | object-assign@^4:
274 | version "4.1.1"
275 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
276 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
277 |
278 | pathfinding@^0.4.18:
279 | version "0.4.18"
280 | resolved "https://registry.yarnpkg.com/pathfinding/-/pathfinding-0.4.18.tgz#a9990f6fa22b7ef196e5651b049165403a045fe8"
281 | integrity sha512-R0TGEQ9GRcFCDvAWlJAWC+KGJ9SLbW4c0nuZRcioVlXVTlw+F5RvXQ8SQgSqI9KXWC1ew95vgmIiyaWTlCe9Ag==
282 | dependencies:
283 | heap "0.2.5"
284 |
285 | picomatch@^2.0.4, picomatch@^2.2.1:
286 | version "2.3.1"
287 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
288 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
289 |
290 | pstree.remy@^1.1.8:
291 | version "1.1.8"
292 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
293 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
294 |
295 | readdirp@~3.6.0:
296 | version "3.6.0"
297 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
298 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
299 | dependencies:
300 | picomatch "^2.2.1"
301 |
302 | semver@^7.5.3:
303 | version "7.5.4"
304 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
305 | integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
306 | dependencies:
307 | lru-cache "^6.0.0"
308 |
309 | simple-update-notifier@^2.0.0:
310 | version "2.0.0"
311 | resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb"
312 | integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==
313 | dependencies:
314 | semver "^7.5.3"
315 |
316 | socket.io-adapter@~2.5.2:
317 | version "2.5.2"
318 | resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
319 | integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
320 | dependencies:
321 | ws "~8.11.0"
322 |
323 | socket.io-parser@~4.2.4:
324 | version "4.2.4"
325 | resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
326 | integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
327 | dependencies:
328 | "@socket.io/component-emitter" "~3.1.0"
329 | debug "~4.3.1"
330 |
331 | socket.io@^4.7.2:
332 | version "4.7.2"
333 | resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.2.tgz#22557d76c3f3ca48f82e73d68b7add36a22df002"
334 | integrity sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==
335 | dependencies:
336 | accepts "~1.3.4"
337 | base64id "~2.0.0"
338 | cors "~2.8.5"
339 | debug "~4.3.2"
340 | engine.io "~6.5.2"
341 | socket.io-adapter "~2.5.2"
342 | socket.io-parser "~4.2.4"
343 |
344 | supports-color@^5.5.0:
345 | version "5.5.0"
346 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
347 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
348 | dependencies:
349 | has-flag "^3.0.0"
350 |
351 | to-regex-range@^5.0.1:
352 | version "5.0.1"
353 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
354 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
355 | dependencies:
356 | is-number "^7.0.0"
357 |
358 | touch@^3.1.0:
359 | version "3.1.0"
360 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
361 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
362 | dependencies:
363 | nopt "~1.0.10"
364 |
365 | undefsafe@^2.0.5:
366 | version "2.0.5"
367 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
368 | integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
369 |
370 | vary@^1:
371 | version "1.1.2"
372 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
373 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
374 |
375 | ws@~8.11.0:
376 | version "8.11.0"
377 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
378 | integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
379 |
380 | yallist@^4.0.0:
381 | version "4.0.0"
382 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
383 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
384 |
--------------------------------------------------------------------------------