Add basic multiplayer

This commit is contained in:
schmelczerandras 2020-10-05 19:07:17 +02:00
commit 46a48e7c15
46 changed files with 1361 additions and 753 deletions

1
shared/.eslintignore Normal file
View file

@ -0,0 +1 @@
**/*.js

29
shared/.eslintrc.json Normal file
View 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
shared/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
dist
node_modules
package-lock.json
.firebase

7
shared/.prettierrc Normal file
View file

@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"printWidth": 90,
"tabWidth": 2,
"singleQuote": true,
"endOfLine": "lf"
}

16
shared/firebase.json Normal file
View file

@ -0,0 +1,16 @@
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}

17
shared/package.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "shared",
"version": "0.0.0",
"description": "Shared library between backend and frontend",
"main": "src/main.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/gl-matrix": "^3.2.0",
"@types/uuid": "^8.0.0",
"gl-matrix": "^3.3.0",
"uuid": "^8.2.0"
}
}

View file

@ -0,0 +1,7 @@
import { CommandReceiver } from './command-receiver';
import { CommandGenerator } from './command-generator';
export const broadcastCommands = (
commandGenerators: Array<CommandGenerator>,
commandReceivers: Array<CommandReceiver>
) => commandReceivers.forEach((r) => commandGenerators.forEach((g) => g.subscribe(r)));

View file

@ -0,0 +1,14 @@
import { CommandReceiver } from './command-receiver';
import { Command } from './command';
export class CommandGenerator {
private subscribers: Array<CommandReceiver> = [];
public subscribe(subscriber: CommandReceiver): void {
this.subscribers.push(subscriber);
}
protected sendCommandToSubcribers(command: Command): void {
this.subscribers.forEach((s) => s.sendCommand(command));
}
}

View file

@ -0,0 +1,25 @@
import { Command } from './command';
export type CommandExecutors = {
[type: string]: (command: Command) => void;
};
export abstract class CommandReceiver {
protected commandExecutors: CommandExecutors = {};
protected defaultCommandExecutor(command: Command) {}
public reactsToCommand(commandType: string): boolean {
return Object.prototype.hasOwnProperty.call(this.commandExecutors, commandType);
}
public sendCommand(command: Command) {
const commandType = command.type;
if (Object.prototype.hasOwnProperty.call(this.commandExecutors, commandType)) {
this.commandExecutors[commandType](command);
} else {
this.defaultCommandExecutor(command);
}
}
}

View file

@ -0,0 +1,7 @@
import { Id } from '../transport/identity';
export abstract class Command {
public get type(): string {
return (this as any).constructor.type;
}
}

View file

@ -0,0 +1,13 @@
import { Command } from '../command';
export class CreateObjectsCommand extends Command {
public static readonly type = 'CreateObjectsCommand';
public constructor(public readonly serializedObjects: string) {
super();
}
public toJSON(): any {
return [this.type, this.serializedObjects];
}
}

View file

@ -0,0 +1,13 @@
import { Command } from '../command';
export class CreatePlayerCommand extends Command {
public static readonly type = 'CreatePlayerCommand';
public constructor(public readonly serializedPlayer: string) {
super();
}
public toJSON(): any {
return [this.type, this.serializedPlayer];
}
}

View file

@ -0,0 +1,14 @@
import { Id } from '../../transport/identity';
import { Command } from '../command';
export class DeleteObjectsCommand extends Command {
public static readonly type = 'DeleteObjectsCommand';
public constructor(public readonly ids: Array<Id>) {
super();
}
public toJSON(): any {
return [this.type, this.ids];
}
}

View file

@ -0,0 +1,14 @@
import { vec2 } from 'gl-matrix';
import { Command } from '../command';
export class MoveActionCommand extends Command {
public static readonly type = 'MoveActionCommand';
public constructor(public readonly delta: vec2) {
super();
}
public toJSON(): any {
return [this.type, this.delta];
}
}

View file

@ -0,0 +1,14 @@
import { vec2 } from 'gl-matrix';
import { Command } from '../command';
export class PrimaryActionCommand extends Command {
public static readonly type = 'PrimaryActionCommand';
public constructor(public readonly position: vec2) {
super();
}
public toJSON(): any {
return [this.type, this.position];
}
}

View file

@ -0,0 +1,14 @@
import { vec2 } from 'gl-matrix';
import { Command } from '../command';
export class SecondaryActionCommand extends Command {
public static readonly type = 'SecondaryActionCommand';
public constructor(public readonly position: vec2) {
super();
}
public toJSON(): any {
return [this.type, this.position];
}
}

View file

@ -0,0 +1,14 @@
import { Rectangle } from '../../helper/rectangle';
import { Command } from '../command';
export class SetViewAreaActionCommand extends Command {
public static readonly type = 'SetViewAreaAction';
public constructor(public readonly viewArea: Rectangle) {
super();
}
public toJSON(): any {
return [this.type, this.viewArea];
}
}

View file

@ -0,0 +1,14 @@
import { vec2 } from 'gl-matrix';
import { Command } from '../command';
export class TernaryActionCommand extends Command {
public static readonly type = 'TernaryActionCommand';
public constructor(public readonly position: vec2) {
super();
}
public toJSON(): any {
return [this.type, this.position];
}
}

View file

@ -0,0 +1,13 @@
import { Command } from '../command';
export class UpdateObjectsCommand extends Command {
public static readonly type = 'UpdateObjectsCommand';
public constructor(public readonly serializedObjects: string) {
super();
}
public toJSON(): any {
return [this.type, this.serializedObjects];
}
}

View file

@ -0,0 +1,31 @@
declare global {
interface Array<T> {
x: number;
y: number;
}
interface Float32Array {
x: number;
y: number;
}
}
const setIndexAlias = (name: string, index: number, type: any) => {
if (!Object.prototype.hasOwnProperty.call(type.prototype, name)) {
Object.defineProperty(type.prototype, name, {
get() {
return this[index];
},
set(value) {
this[index] = value;
},
});
}
};
export const applyArrayPlugins = () => {
setIndexAlias('x', 0, Array);
setIndexAlias('y', 1, Array);
setIndexAlias('x', 0, Float32Array);
setIndexAlias('y', 1, Float32Array);
};

Some files were not shown because too many files have changed in this diff Show more