Add basic multiplayer

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

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);
};

View file

@ -0,0 +1,5 @@
import { vec2 } from 'gl-matrix';
export class Circle {
constructor(public center: vec2, public radius: number) {}
}

View file

@ -0,0 +1,4 @@
export const clamp = (value: number, min: number, max: number): number =>
Math.min(max, Math.max(min, value));
export const clamp01 = (value: number): number => Math.min(1, Math.max(0, value));

View file

@ -0,0 +1,23 @@
export class DeltaTimeCalculator {
private previousTime: DOMHighResTimeStamp | null = null;
constructor() {
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
}
public getNextDeltaTime(currentTime: DOMHighResTimeStamp): DOMHighResTimeStamp {
if (this.previousTime === null) {
this.previousTime = currentTime;
}
const delta = currentTime - this.previousTime;
this.previousTime = currentTime;
return delta;
}
private handleVisibilityChange() {
if (!document.hidden) {
this.previousTime = null;
}
}
}

View file

@ -0,0 +1,3 @@
export function last<T>(a: Array<T>): T | null {
return a.length > 0 ? a[a.length - 1] : null;
}

1
shared/src/helper/mix.ts Normal file
View file

@ -0,0 +1 @@
export const mix = (from: number, to: number, q: number) => from + (to - from) * q;

View file

@ -0,0 +1,4 @@
export const prettyPrint = (o: any): string =>
JSON.stringify(o, (_, v) => (v.toFixed ? Number(v.toFixed(3)) : v), ' ')
.replace(/("|,|{|^\n)/g, '')
.replace(/(\W*}\n?)+/g, '\n\n');

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