Add backend
This commit is contained in:
parent
4ad60813c9
commit
0f0a1eaf67
19 changed files with 355 additions and 45 deletions
0
frontend/.gitattributes → .gitattributes
vendored
0
frontend/.gitattributes → .gitattributes
vendored
1
backend/.eslintignore
Normal file
1
backend/.eslintignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
**/*.js
|
||||||
29
backend/.eslintrc.json
Normal file
29
backend/.eslintrc.json
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2020": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 11,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["unused-imports", "@typescript-eslint", "prettier"],
|
||||||
|
"rules": {
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"unused-imports/no-unused-imports-ts": "error",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
|
"@typescript-eslint/no-non-null-assertion": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
4
backend/.gitignore
vendored
Normal file
4
backend/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
package-lock.json
|
||||||
|
.firebase
|
||||||
7
backend/.prettierrc
Normal file
7
backend/.prettierrc
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"printWidth": 90,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
51
backend/package.json
Normal file
51
backend/package.json
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "decla.red-server",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Game server for decla.red",
|
||||||
|
"private": true,
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "concurrently --kill-others \"webpack --mode development -w\" \"npx nodemon dist/main.js\"",
|
||||||
|
"lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"",
|
||||||
|
"build": "webpack --mode production"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.8",
|
||||||
|
"@types/gl-matrix": "^2.4.5",
|
||||||
|
"@types/node": "^14.11.2",
|
||||||
|
"@types/uuid": "^8.0.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^3.9.1",
|
||||||
|
"@typescript-eslint/parser": "^3.9.1",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"concurrently": "^5.3.0",
|
||||||
|
"eslint": "^7.2.0",
|
||||||
|
"eslint-config-prettier": "^6.11.0",
|
||||||
|
"eslint-plugin-import": "^2.21.2",
|
||||||
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
|
"eslint-plugin-unused-imports": "^0.1.3",
|
||||||
|
"firebase": "^7.22.0",
|
||||||
|
"gl-matrix": "^3.3.0",
|
||||||
|
"nodemon": "^2.0.4",
|
||||||
|
"prettier": "^2.0.5",
|
||||||
|
"terser-webpack-plugin": "^2.3.5",
|
||||||
|
"ts-loader": "^8.0.1",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"uuid": "^8.2.0",
|
||||||
|
"webpack": "^4.43.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-dev-server": "^3.10.3",
|
||||||
|
"file-loader": "^6.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/cors": "^2.8.7",
|
||||||
|
"@types/socket.io": "^2.1.11",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"http": "0.0.1-security",
|
||||||
|
"socket.io": "^2.3.0",
|
||||||
|
"uws": "^10.148.1",
|
||||||
|
"webpack-node-externals": "^2.5.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
backend/src/index.html
Normal file
29
backend/src/index.html
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<script
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.1/socket.io.js"
|
||||||
|
integrity="sha512-AcZyhRP/tbAEsXCCGlziPun5iFvcSUpEz2jKkx0blkYKbxU81F+iq8FURwPn1sYFeksJ+sDDrI5XujsqSobWdQ=="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
<title>Server info</title>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
<script>
|
||||||
|
const socket = io({
|
||||||
|
transports: ['websocket'],
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('reconnect_attempt', () => {
|
||||||
|
socket.io.opts.transports = ['polling', 'websocket'];
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit('join', 'insights');
|
||||||
|
|
||||||
|
socket.on('insights', (message) => {
|
||||||
|
document.body.innerText += message;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
61
backend/src/main.ts
Normal file
61
backend/src/main.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import ioserver, { Socket } from 'socket.io';
|
||||||
|
import express from 'express';
|
||||||
|
import { Server } from 'http';
|
||||||
|
import cors from 'cors';
|
||||||
|
|
||||||
|
import { PlayerContainer } from './players/player-container';
|
||||||
|
import './index.html';
|
||||||
|
import { TransportEvents } from '../../shared/src/transport/transport-events';
|
||||||
|
import { Player } from './players/player';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
cors({
|
||||||
|
origin: (origin, callback) => {
|
||||||
|
callback(null, true);
|
||||||
|
},
|
||||||
|
credentials: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const port = 3000;
|
||||||
|
const server = new Server(app);
|
||||||
|
const io = ioserver(server);
|
||||||
|
|
||||||
|
const players = new PlayerContainer();
|
||||||
|
|
||||||
|
const log = (text: string) => {
|
||||||
|
io.to('insights').emit('insights', text + '\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
app.get('/', function (req, res) {
|
||||||
|
res.sendFile('dist/index.html', { root: '.' });
|
||||||
|
});
|
||||||
|
|
||||||
|
io.on('connection', (socket: SocketIO.Socket) => {
|
||||||
|
socket.on(TransportEvents.PlayerJoining, () => {
|
||||||
|
log('player joined');
|
||||||
|
|
||||||
|
const player = new Player(socket);
|
||||||
|
players.addPlayer(player);
|
||||||
|
|
||||||
|
socket.on(TransportEvents.PlayerSendingInfo, () => {});
|
||||||
|
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
log('player disconnected');
|
||||||
|
|
||||||
|
players.removePlayerBySocketId(player.socketId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('join', (room_name: string) => {
|
||||||
|
socket.join(room_name);
|
||||||
|
});
|
||||||
|
|
||||||
|
//socket.on('disconnect', () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(`server started at http://localhost:${port}`);
|
||||||
|
});
|
||||||
13
backend/src/players/player-container.ts
Normal file
13
backend/src/players/player-container.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Player } from './player';
|
||||||
|
|
||||||
|
export class PlayerContainer {
|
||||||
|
private socketIdToPlayer = new Map<string, Player>();
|
||||||
|
|
||||||
|
public addPlayer(player: Player) {
|
||||||
|
this.socketIdToPlayer.set(player.socketId, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removePlayerBySocketId(socketId: string) {
|
||||||
|
this.socketIdToPlayer.delete(socketId);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
backend/src/players/player.ts
Normal file
9
backend/src/players/player.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Socket } from 'dgram';
|
||||||
|
|
||||||
|
export class Player {
|
||||||
|
constructor(private readonly socket: SocketIO.Socket) {}
|
||||||
|
|
||||||
|
public get socketId(): string {
|
||||||
|
return this.socket.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/tsconfig.json
Normal file
19
backend/tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/",
|
||||||
|
"sourceMap": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"target": "es6",
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": ["node_modules/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
75
backend/webpack.config.js
Normal file
75
backend/webpack.config.js
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
const path = require('path');
|
||||||
|
const TerserJSPlugin = require('terser-webpack-plugin');
|
||||||
|
const nodeExternals = require('webpack-node-externals');
|
||||||
|
|
||||||
|
const PATHS = {
|
||||||
|
entryPoint: path.resolve(__dirname, 'src/main.ts'),
|
||||||
|
bundles: path.resolve(__dirname, 'dist'),
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
main: [PATHS.entryPoint],
|
||||||
|
},
|
||||||
|
externals: [nodeExternals()],
|
||||||
|
target: 'node',
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: PATHS.bundles,
|
||||||
|
},
|
||||||
|
devtool: 'source-map',
|
||||||
|
watchOptions: {
|
||||||
|
aggregateTimeout: 600,
|
||||||
|
ignored: /node_modules/,
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
usedExports: true,
|
||||||
|
minimizer: [
|
||||||
|
new TerserJSPlugin({
|
||||||
|
sourceMap: true,
|
||||||
|
cache: true,
|
||||||
|
test: /\.ts$/i,
|
||||||
|
terserOptions: {
|
||||||
|
ecma: 5,
|
||||||
|
warnings: true,
|
||||||
|
parse: {},
|
||||||
|
compress: { defaults: true },
|
||||||
|
mangle: true,
|
||||||
|
module: false,
|
||||||
|
output: null,
|
||||||
|
toplevel: true,
|
||||||
|
nameCache: null,
|
||||||
|
ie8: false,
|
||||||
|
keep_classnames: false,
|
||||||
|
keep_fnames: false,
|
||||||
|
safari10: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.html$/i,
|
||||||
|
use: {
|
||||||
|
loader: 'file-loader',
|
||||||
|
query: {
|
||||||
|
outputPath: '/',
|
||||||
|
name: '[name].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
},
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
version: "3.8"
|
|
||||||
|
|
||||||
services:
|
|
||||||
declared-frontend:
|
|
||||||
init: true
|
|
||||||
image: schmelczera/declared-frontend
|
|
||||||
networks:
|
|
||||||
- network
|
|
||||||
deploy:
|
|
||||||
replicas: 2
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: "0.1"
|
|
||||||
memory: 16M
|
|
||||||
reservations:
|
|
||||||
cpus: "0.1"
|
|
||||||
memory: 16M
|
|
||||||
update_config:
|
|
||||||
parallelism: 1
|
|
||||||
failure_action: rollback
|
|
||||||
delay: 10s
|
|
||||||
monitor: 10s
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
window: 30s
|
|
||||||
|
|
||||||
networks:
|
|
||||||
network:
|
|
||||||
driver: overlay
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
"css-loader": "^3.5.2",
|
"css-loader": "^3.5.2",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"eslint": "^7.2.0",
|
"eslint": "^7.2.0",
|
||||||
"sdf-2d": "^0.3.4",
|
"sdf-2d": "^0.4.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-plugin-import": "^2.21.2",
|
"eslint-plugin-import": "^2.21.2",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
|
|
@ -57,11 +57,12 @@
|
||||||
"ts-loader": "^8.0.1",
|
"ts-loader": "^8.0.1",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
"uuid": "^8.2.0",
|
"uuid": "^8.2.0",
|
||||||
|
"file-loader": "^6.1.0",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
"webpack-dev-server": "^3.10.3"
|
"webpack-dev-server": "^3.10.3",
|
||||||
},
|
"firebase": "^7.22.0",
|
||||||
"dependencies": {
|
"@types/socket.io-client": "^1.4.34",
|
||||||
"firebase": "^7.22.0"
|
"socket.io-client": "^2.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import { glMatrix } from 'gl-matrix';
|
import { glMatrix } from 'gl-matrix';
|
||||||
|
import io from 'socket.io-client';
|
||||||
|
import { TransportEvents } from '../../shared/src/transport/transport-events';
|
||||||
import { Configuration } from './scripts/config/configuration';
|
import { Configuration } from './scripts/config/configuration';
|
||||||
import { Game } from './scripts/game';
|
import { Game } from './scripts/game';
|
||||||
import { Random } from './scripts/helper/random';
|
import { Random } from './scripts/helper/random';
|
||||||
|
|
@ -9,6 +11,17 @@ glMatrix.setMatrixArrayType(Array);
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
await Configuration.initialize();
|
await Configuration.initialize();
|
||||||
|
|
||||||
|
const socket = io(Configuration.servers[0], {
|
||||||
|
reconnectionDelayMax: 10000,
|
||||||
|
transports: ['websocket'],
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('reconnect_attempt', () => {
|
||||||
|
socket.io.opts.transports = ['polling', 'websocket'];
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit(TransportEvents.PlayerJoining, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Random.seed = 42;
|
Random.seed = 42;
|
||||||
await new Game().start();
|
await new Game().start();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import * as firebase from 'firebase/app';
|
import firebase from 'firebase/app';
|
||||||
import 'firebase/firebase-remote-config';
|
import 'firebase/firebase-remote-config';
|
||||||
|
|
||||||
export class Configuration {
|
export abstract class Configuration {
|
||||||
|
private static remoteConfig: firebase.remoteConfig.RemoteConfig;
|
||||||
|
private static initialized = false;
|
||||||
|
|
||||||
public static async initialize(): Promise<void> {
|
public static async initialize(): Promise<void> {
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
apiKey: 'AIzaSyBG85dp-AhaCW-qi_6mu77wDPSipzipIF4',
|
apiKey: 'AIzaSyBG85dp-AhaCW-qi_6mu77wDPSipzipIF4',
|
||||||
|
|
@ -12,19 +15,24 @@ export class Configuration {
|
||||||
|
|
||||||
firebase.initializeApp(firebaseConfig);
|
firebase.initializeApp(firebaseConfig);
|
||||||
|
|
||||||
const remoteConfig = firebase.remoteConfig();
|
this.remoteConfig = firebase.remoteConfig();
|
||||||
remoteConfig.defaultConfig = {
|
|
||||||
online_servers: 'hi',
|
|
||||||
};
|
|
||||||
|
|
||||||
remoteConfig.settings = {
|
this.remoteConfig.settings = {
|
||||||
minimumFetchIntervalMillis: 3600 * 1000,
|
minimumFetchIntervalMillis: 0, // todo: 3600 * 1000,
|
||||||
fetchTimeoutMillis: 15 * 1000,
|
fetchTimeoutMillis: 15 * 1000,
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
await remoteConfig.ensureInitialized();
|
await this.remoteConfig.ensureInitialized();
|
||||||
await remoteConfig.fetchAndActivate();
|
await this.remoteConfig.fetchAndActivate();
|
||||||
|
|
||||||
console.log(remoteConfig.getValue('online_servers'));
|
this.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get servers(): Array<string> {
|
||||||
|
if (!this.initialized) {
|
||||||
|
throw new Error('Configuration should be initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(this.remoteConfig.getValue('online_servers').asString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@ import {
|
||||||
Circle,
|
Circle,
|
||||||
CircleLight,
|
CircleLight,
|
||||||
compile,
|
compile,
|
||||||
|
FilteringOptions,
|
||||||
Flashlight,
|
Flashlight,
|
||||||
InvertedTunnel,
|
InvertedTunnel,
|
||||||
Renderer,
|
Renderer,
|
||||||
|
renderNoise,
|
||||||
|
WrapOptions,
|
||||||
} from 'sdf-2d';
|
} from 'sdf-2d';
|
||||||
import { CommandBroadcaster } from './commands/command-broadcaster';
|
import { CommandBroadcaster } from './commands/command-broadcaster';
|
||||||
import { MoveToCommand } from './commands/move-to';
|
import { MoveToCommand } from './commands/move-to';
|
||||||
|
|
@ -82,6 +85,8 @@ export class Game implements IGame {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start(): Promise<void> {
|
public async start(): Promise<void> {
|
||||||
|
const noiseTexture = await renderNoise([1024, 1], 60, 1 / 8);
|
||||||
|
|
||||||
this.renderer = await this.rendererPromise;
|
this.renderer = await this.rendererPromise;
|
||||||
this.renderer.setRuntimeSettings({
|
this.renderer.setRuntimeSettings({
|
||||||
isWorldInverted: true,
|
isWorldInverted: true,
|
||||||
|
|
@ -97,6 +102,15 @@ export class Game implements IGame {
|
||||||
],
|
],
|
||||||
enableHighDpiRendering: false,
|
enableHighDpiRendering: false,
|
||||||
lightCutoffDistance: settings.lightCutoffDistance,
|
lightCutoffDistance: settings.lightCutoffDistance,
|
||||||
|
textures: {
|
||||||
|
noiseTexture: {
|
||||||
|
source: noiseTexture,
|
||||||
|
overrides: {
|
||||||
|
maxFilter: FilteringOptions.LINEAR,
|
||||||
|
wrapS: WrapOptions.MIRRORED_REPEAT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.initializeScene();
|
this.initializeScene();
|
||||||
this.physics.start();
|
this.physics.start();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"module": "es6",
|
"module": "es6",
|
||||||
"lib": ["es2015", "dom"]
|
"lib": ["es2015", "dom"]
|
||||||
|
|
|
||||||
4
shared/src/transport/transport-events.ts
Normal file
4
shared/src/transport/transport-events.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum TransportEvents {
|
||||||
|
PlayerJoining = "PlayerJoining",
|
||||||
|
PlayerSendingInfo = "PlayerSendingInfo",
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue