├── .gitignore ├── README.md ├── arena.env ├── development.env ├── package.json ├── src ├── arena.config.ts ├── index.ts └── rooms │ ├── MyRoom.ts │ └── schema │ └── MyRoomState.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .vscode 4 | package-lock.json 5 | .idea/ 6 | lib 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # (Server-side) BabylonJS: Real-time Multiplayer with Colyseus 2 | 3 | This is the server code for a step-by-step tutorial on how to use BabylonJS + Colyseus together. 4 | 5 | - [See step-by-step Tutorial](https://doc.babylonjs.com/guidedLearning/multiplayer/Colyseus) 6 | - [See client-side Project](https://github.com/colyseus/tutorial-babylonjs-client) 7 | - [See Colyseus documentation](https://docs.colyseus.io/) 8 | 9 | ## How to run the server 10 | 11 | - Download and install [Node.js LTS](https://nodejs.org/en/download/) 12 | - Clone or download this repository. 13 | - Run `npm install` 14 | - Run `npm start` 15 | 16 | The WebSocket server should be available locally at `ws://localhost:2567`, and [http://localhost:2567](http://localhost:2567) should be accessible. 17 | 18 | ## License 19 | 20 | MIT -------------------------------------------------------------------------------- /arena.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=production -------------------------------------------------------------------------------- /development.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-app", 4 | "version": "1.0.0", 5 | "description": "npm init template for bootstrapping an empty Colyseus project", 6 | "main": "lib/index.js", 7 | "scripts": { 8 | "start": "ts-node-dev --respawn --transpile-only src/index.ts", 9 | "loadtest": "colyseus-loadtest loadtest/example.ts --room my_room --numClients 2", 10 | "build": "npm run clean && tsc && node node_modules/copyfiles/copyfiles package.json ./lib && node node_modules/copyfiles/copyfiles arena.env ./lib", 11 | "clean": "node node_modules/rimraf/bin lib", 12 | "test": "mocha --require ts-node/register test/**_test.ts --exit --timeout 15000" 13 | }, 14 | "author": "", 15 | "license": "UNLICENSED", 16 | "bugs": { 17 | "url": "https://github.com/colyseus/create-colyseus/issues" 18 | }, 19 | "homepage": "https://github.com/colyseus/create-colyseus#readme", 20 | "devDependencies": { 21 | "@colyseus/loadtest": "0.15.0-preview.0", 22 | "@colyseus/testing": "0.15.0-preview.0", 23 | "@types/cors": "^2.8.6", 24 | "@types/express": "^4.17.1", 25 | "@types/mocha": "^8.2.3", 26 | "copyfiles": "^2.4.1", 27 | "mocha": "^9.0.2", 28 | "rimraf": "^2.7.1", 29 | "ts-node": "^8.1.0", 30 | "ts-node-dev": "^1.0.0-pre.63", 31 | "typescript": "^3.4.5" 32 | }, 33 | "dependencies": { 34 | "@colyseus/arena": "0.15.0-preview.0", 35 | "@colyseus/monitor": "0.15.0-preview.0", 36 | "colyseus": "0.15.0-preview.0", 37 | "cors": "^2.8.5", 38 | "express": "^4.16.4" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/arena.config.ts: -------------------------------------------------------------------------------- 1 | import Arena from "@colyseus/arena"; 2 | import { monitor } from "@colyseus/monitor"; 3 | 4 | import { MyRoom } from "./rooms/MyRoom"; 5 | 6 | export default Arena({ 7 | getId: () => "BabylonJS and Colyseus Demo Server", 8 | 9 | initializeGameServer: (gameServer) => { 10 | gameServer.define('my_room', MyRoom); 11 | }, 12 | 13 | initializeExpress: (app) => { 14 | app.get("/", (req, res) => { 15 | res.send("Server ready!"); 16 | }); 17 | 18 | app.use("/colyseus", monitor()); 19 | }, 20 | 21 | beforeListen: () => { 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * IMPORTANT: 3 | * --------- 4 | * Do not manually edit this file if you'd like to use Colyseus Arena 5 | * 6 | * If you're self-hosting (without Arena), you can manually instantiate a 7 | * Colyseus Server as documented here: 👉 https://docs.colyseus.io/server/api/#constructor-options 8 | */ 9 | import { listen } from "@colyseus/arena"; 10 | 11 | // Import arena config 12 | import arenaConfig from "./arena.config"; 13 | 14 | // Create and listen on 2567 (or PORT environment variable.) 15 | listen(arenaConfig); 16 | -------------------------------------------------------------------------------- /src/rooms/MyRoom.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "@colyseus/core"; 2 | import { MyRoomState, Player } from "./schema/MyRoomState"; 3 | 4 | export class MyRoom extends Room { 5 | maxClients = 5; 6 | 7 | onCreate(options: any) { 8 | console.log("MyRoom created."); 9 | this.setState(new MyRoomState()); 10 | 11 | this.onMessage("updatePosition", (client, data) => { 12 | console.log("update received -> "); 13 | console.debug(JSON.stringify(data)); 14 | const player = this.state.players.get(client.sessionId); 15 | player.x = data["x"]; 16 | player.y = data['y']; 17 | player.z = data["z"]; 18 | }); 19 | } 20 | 21 | onJoin(client: Client, options: any) { 22 | console.log(client.sessionId, "joined!"); 23 | 24 | // create Player instance 25 | const player = new Player(); 26 | 27 | // place Player at a random position in the floor 28 | const FLOOR_SIZE = 500; 29 | player.x = -(FLOOR_SIZE/2) + (Math.random() * FLOOR_SIZE); 30 | player.y = -1; 31 | player.z = -(FLOOR_SIZE/2) + (Math.random() * FLOOR_SIZE); 32 | 33 | // place player in the map of players by its sessionId 34 | // (client.sessionId is unique per connection!) 35 | this.state.players.set(client.sessionId, player); 36 | 37 | console.log("new player =>", player.toJSON()); 38 | } 39 | 40 | onLeave(client: Client, consented: boolean) { 41 | this.state.players.delete(client.sessionId); 42 | console.log(client.sessionId, "left!"); 43 | } 44 | 45 | onDispose() { 46 | console.log("room", this.roomId, "disposing..."); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/rooms/schema/MyRoomState.ts: -------------------------------------------------------------------------------- 1 | import { MapSchema, Schema, type } from "@colyseus/schema"; 2 | 3 | export class Player extends Schema { 4 | 5 | @type("number") x: number; 6 | @type("number") y: number; 7 | @type("number") z: number; 8 | } 9 | 10 | export class MyRoomState extends Schema { 11 | @type({ map: Player }) players = new MapSchema(); 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "lib", 4 | "target": "es6", 5 | "module": "commonjs", 6 | "strict": true, 7 | "allowJs": true, 8 | "strictNullChecks": false, 9 | "esModuleInterop": true, 10 | "experimentalDecorators": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true 13 | }, 14 | "include": [ 15 | "src" 16 | ] 17 | } --------------------------------------------------------------------------------