Add basic multiplayer
This commit is contained in:
parent
0f0a1eaf67
commit
46a48e7c15
39 changed files with 1361 additions and 753 deletions
7
shared/src/commands/broadcast-commands.ts
Normal file
7
shared/src/commands/broadcast-commands.ts
Normal 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)));
|
||||
14
shared/src/commands/command-generator.ts
Normal file
14
shared/src/commands/command-generator.ts
Normal 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));
|
||||
}
|
||||
}
|
||||
25
shared/src/commands/command-receiver.ts
Normal file
25
shared/src/commands/command-receiver.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
shared/src/commands/command.ts
Normal file
7
shared/src/commands/command.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { Id } from '../transport/identity';
|
||||
|
||||
export abstract class Command {
|
||||
public get type(): string {
|
||||
return (this as any).constructor.type;
|
||||
}
|
||||
}
|
||||
13
shared/src/commands/types/create-objects.ts
Normal file
13
shared/src/commands/types/create-objects.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
13
shared/src/commands/types/create-player.ts
Normal file
13
shared/src/commands/types/create-player.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/delete-objects.ts
Normal file
14
shared/src/commands/types/delete-objects.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/move-action.ts
Normal file
14
shared/src/commands/types/move-action.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/primary-action.ts
Normal file
14
shared/src/commands/types/primary-action.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/secondary-action.ts
Normal file
14
shared/src/commands/types/secondary-action.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/set-view-area-action.ts
Normal file
14
shared/src/commands/types/set-view-area-action.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
14
shared/src/commands/types/ternary-action.ts
Normal file
14
shared/src/commands/types/ternary-action.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
13
shared/src/commands/types/update-objects.ts
Normal file
13
shared/src/commands/types/update-objects.ts
Normal 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];
|
||||
}
|
||||
}
|
||||
31
shared/src/helper/array.ts
Normal file
31
shared/src/helper/array.ts
Normal 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);
|
||||
};
|
||||
5
shared/src/helper/circle.ts
Normal file
5
shared/src/helper/circle.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
|
||||
export class Circle {
|
||||
constructor(public center: vec2, public radius: number) {}
|
||||
}
|
||||
4
shared/src/helper/clamp.ts
Normal file
4
shared/src/helper/clamp.ts
Normal 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));
|
||||
23
shared/src/helper/delta-time-calculator.ts
Normal file
23
shared/src/helper/delta-time-calculator.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
shared/src/helper/last.ts
Normal file
3
shared/src/helper/last.ts
Normal 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
1
shared/src/helper/mix.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const mix = (from: number, to: number, q: number) => from + (to - from) * q;
|
||||
4
shared/src/helper/pretty-print.ts
Normal file
4
shared/src/helper/pretty-print.ts
Normal 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
Loading…
Reference in a new issue