From efa838a2add11ebf27d693090a4fb8fc9de36521 Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Sun, 25 Oct 2020 17:54:45 +0100 Subject: [PATCH] Add npcs --- backend/src/default-options.ts | 4 +- backend/src/game-server.ts | 39 +- backend/src/objects/planet-physical.ts | 2 +- .../src/objects/player-character-physical.ts | 103 +- backend/src/players/npc.ts | 132 ++ backend/src/players/player-base.ts | 78 + backend/src/players/player-container.ts | 64 +- backend/src/players/player.ts | 104 +- frontend/package-lock.json | 1367 +++++++++++++++-- frontend/package.json | 2 +- frontend/src/index.ts | 3 - frontend/src/main.scss | 2 +- frontend/src/scripts/game.ts | 7 +- .../src/scripts/objects/character-view.ts | 35 - .../scripts/objects/player-character-view.ts | 15 +- frontend/src/scripts/sound-handler.ts | 1 + shared/src/main.ts | 1 - shared/src/objects/types/character-base.ts | 26 - .../objects/types/player-character-base.ts | 16 +- shared/src/settings.ts | 58 + 20 files changed, 1691 insertions(+), 368 deletions(-) create mode 100644 backend/src/players/npc.ts create mode 100644 backend/src/players/player-base.ts delete mode 100644 frontend/src/scripts/objects/character-view.ts delete mode 100644 shared/src/objects/types/character-base.ts diff --git a/backend/src/default-options.ts b/backend/src/default-options.ts index 975cc84..fd2b28d 100644 --- a/backend/src/default-options.ts +++ b/backend/src/default-options.ts @@ -3,8 +3,8 @@ import { Options } from './options'; export const defaultOptions: Options = { port: 3000, name: 'Test server', - playerLimit: 16, - seed: Math.random(), + playerLimit: 8, + seed: 0, scoreLimit: 500, worldSize: 15000, }; diff --git a/backend/src/game-server.ts b/backend/src/game-server.ts index 6d6c047..0133f7c 100644 --- a/backend/src/game-server.ts +++ b/backend/src/game-server.ts @@ -6,7 +6,6 @@ import { settings, ServerInformation, PlayerInformation, - serializable, UpdateGameState, serialize, CharacterTeam, @@ -18,7 +17,7 @@ import { DeltaTimeCalculator } from './helper/delta-time-calculator'; import { Options } from './options'; import { PlayerContainer } from './players/player-container'; -const playerCountSubscribedRoom = 'playerCountUpdates'; +const gameStateSubscribedRoom = 'gameStateSubscribedRoom'; export class GameServer { private objects!: PhysicalContainer; @@ -38,15 +37,15 @@ export class GameServer { private initialize() { const previousPlayers = this.players; this.objects = new PhysicalContainer(); - this.players = new PlayerContainer(this.objects); + createWorld(this.objects, this.options.worldSize); + this.objects.initialize(); + this.players = new PlayerContainer(this.objects, this.options.playerLimit); this.deltaTimeCalculator = new DeltaTimeCalculator(); this.deltaTimes = []; this.declaPoints = 0; this.redPoints = 0; this.isInEndGame = false; this.timeScaling = 1; - createWorld(this.objects, this.options.worldSize); - this.objects.initialize(); previousPlayers?.sendOnSocket(serialize(new GameStart())); } @@ -58,23 +57,27 @@ export class GameServer { io.on('connection', (socket: SocketIO.Socket) => { socket.on(TransportEvents.PlayerJoining, (playerInfo: PlayerInformation) => { - const player = this.players.createPlayer(playerInfo, socket); - socket.on(TransportEvents.PlayerToServer, (json: string) => { - const command = deserialize(json); - player.sendCommand(command); - }); + try { + const player = this.players.createPlayer(playerInfo, socket); + socket.on(TransportEvents.PlayerToServer, (json: string) => { + const command = deserialize(json); + player.sendCommand(command); + }); - this.sendServerStateUpdate(); - - socket.on('disconnect', () => { - player.destroy(); - this.players.deletePlayer(player); this.sendServerStateUpdate(); - }); + + socket.on('disconnect', () => { + player.destroy(); + this.players.deletePlayer(player); + this.sendServerStateUpdate(); + }); + } catch { + socket.disconnect(); + } }); socket.on(TransportEvents.SubscribeForServerInfoUpdates, () => { - socket.join(playerCountSubscribedRoom); + socket.join(gameStateSubscribedRoom); }); }); } @@ -82,7 +85,7 @@ export class GameServer { private timeSinceLastServerStateUpdate = 0; public sendServerStateUpdate() { this.io - .to(playerCountSubscribedRoom) + .to(gameStateSubscribedRoom) .emit(TransportEvents.ServerInfoUpdate, [this.players.count, this.gameProgress]); } diff --git a/backend/src/objects/planet-physical.ts b/backend/src/objects/planet-physical.ts index 38d29bd..3027af5 100644 --- a/backend/src/objects/planet-physical.ts +++ b/backend/src/objects/planet-physical.ts @@ -69,7 +69,7 @@ export class PlanetPhysical } public get team(): CharacterTeam { - return this.ownership === 0.5 + return Math.abs(this.ownership - 0.5) < 0.1 ? CharacterTeam.neutral : this.ownership < 0.5 ? CharacterTeam.decla diff --git a/backend/src/objects/player-character-physical.ts b/backend/src/objects/player-character-physical.ts index d14971c..44b7494 100644 --- a/backend/src/objects/player-character-physical.ts +++ b/backend/src/objects/player-character-physical.ts @@ -190,7 +190,9 @@ export class PlayerCharacterPhysical } public get center(): vec2 { - return this.head.center; + const bodyCenter = vec2.add(vec2.create(), this.head.center, this.leftFoot.center); + vec2.add(bodyCenter, bodyCenter, this.rightFoot.center); + return vec2.scale(bodyCenter, bodyCenter, 1 / 3); } public distance(target: vec2): number { @@ -199,7 +201,7 @@ export class PlayerCharacterPhysical this.head.distance(target), this.leftFoot.distance(target), this.rightFoot.distance(target), - ) - 20 + ) - 5 ); } @@ -222,7 +224,7 @@ export class PlayerCharacterPhysical this.movementActions = []; } - return direction; + return vec2.normalize(direction, direction); } public step(deltaTime: number) { @@ -251,16 +253,28 @@ export class PlayerCharacterPhysical this.rightFoot.center, ); vec2.scale(feetCenter, feetCenter, 0.5); - const actualGravity = forceAtPosition(feetCenter, intersectingWithForcefield); + const leftFootGravity = forceAtPosition( + this.leftFoot.center, + intersectingWithForcefield, + ); + const rightFootGravity = forceAtPosition( + this.rightFoot.center, + intersectingWithForcefield, + ); const direction = this.averageAndResetMovementActions(); const movementForce = vec2.scale(direction, direction, settings.maxAcceleration); if (!this.currentPlanet) { - this.applyForce(this.leftFoot, actualGravity, deltaTime); - this.applyForce(this.rightFoot, actualGravity, deltaTime); + this.applyForce(this.leftFoot, leftFootGravity, deltaTime); + this.applyForce(this.rightFoot, rightFootGravity, deltaTime); - const sumForce = vec2.subtract(vec2.create(), actualGravity, movementForce); + const sumForce = vec2.subtract( + vec2.create(), + // the next line is intentional + vec2.add(vec2.create(), leftFootGravity, rightFootGravity), + movementForce, + ); this.setDirection( vec2.length(sumForce) === 0 ? vec2.fromValues(0, -1) : sumForce, @@ -274,7 +288,7 @@ export class PlayerCharacterPhysical vec2.rotate(movementForce, movementForce, vec2.create(), this.direction); } - if (vec2.dot(movementForce, actualGravity) < -vec2.length(movementForce) * 0.8) { + if (vec2.dot(movementForce, leftFootGravity) < -vec2.length(movementForce) * 0.8) { vec2.scale(leftFootGravity, leftFootGravity, 0.35); vec2.scale(rightFootGravity, rightFootGravity, 0.35); } @@ -283,7 +297,7 @@ export class PlayerCharacterPhysical const headGravity = this.currentPlanet!.getForce(this.head.center); - if (vec2.length(headGravity) < vec2.length(actualGravity) / 2) { + if (vec2.length(headGravity) < vec2.length(leftFootGravity) / 2) { this.currentPlanet = undefined; } this.setDirection(headGravity, deltaTime); @@ -294,7 +308,9 @@ export class PlayerCharacterPhysical this.stepBodyPart(this.leftFoot, deltaTime); this.stepBodyPart(this.rightFoot, deltaTime); - this.keepPosture(); + + this.keepPosture(deltaTime); + this.remoteCall('updateCircles', this.head, this.leftFoot, this.rightFoot); } @@ -302,27 +318,68 @@ export class PlayerCharacterPhysical this.direction = interpolateAngles( this.direction, Math.atan2(direction.y, direction.x) + Math.PI / 2, - Math.pow(4, deltaTime), + Math.pow(2, deltaTime), ); } - private keepPosture() { - const bodyCenter = vec2.add(vec2.create(), this.head.center, this.leftFoot.center); - vec2.add(bodyCenter, bodyCenter, this.rightFoot.center); - vec2.scale(bodyCenter, bodyCenter, 1 / 3); - this.springMove(this.leftFoot, bodyCenter, PlayerCharacterPhysical.leftFootOffset); - this.springMove(this.rightFoot, bodyCenter, PlayerCharacterPhysical.rightFootOffset); - this.springMove(this.head, bodyCenter, PlayerCharacterPhysical.headOffset); + private keepPosture(deltaTime: number) { + const center = this.center; + this.springMove( + this.leftFoot, + center, + PlayerCharacterPhysical.leftFootOffset, + deltaTime, + ); + this.springMove( + this.rightFoot, + center, + PlayerCharacterPhysical.rightFootOffset, + deltaTime, + ); + /* + const feetDelta = vec2.subtract( + vec2.create(), + this.leftFoot.center, + this.rightFoot.center, + ); + const desiredDistance = vec2.dist( + PlayerCharacterPhysical.desiredLeftFootOffset, + PlayerCharacterPhysical.desiredRightFootOffset, + ); + const actualDistance = vec2.length(feetDelta); + const delta = vec2.normalize(feetDelta, feetDelta); + vec2.scale(delta, delta, Math.min(actualDistance / 2, deltaTime * 200)); + let hitObject = this.rightFoot.tryMove(delta); + if (hitObject instanceof PlanetPhysical) { + this.secondsSinceOnSurface = 0; + this.currentPlanet = hitObject; + } + vec2.scale(delta, delta, -1); + hitObject = this.leftFoot.tryMove(delta); + if (hitObject instanceof PlanetPhysical) { + this.secondsSinceOnSurface = 0; + this.currentPlanet = hitObject; + }*/ + + this.springMove(this.head, center, PlayerCharacterPhysical.headOffset, deltaTime); } - private springMove(object: CirclePhysical, center: vec2, offset: vec2) { - // todo: make time-independent - const springConstant = 0.55; - + private springMove( + object: CirclePhysical, + center: vec2, + offset: vec2, + deltaTime: number, + ) { const desiredPosition = vec2.add(vec2.create(), center, offset); vec2.rotate(desiredPosition, desiredPosition, center, this.direction); const positionDelta = vec2.subtract(desiredPosition, desiredPosition, object.center); - vec2.scale(positionDelta, positionDelta, springConstant); + const positionDeltaDirection = vec2.normalize(vec2.create(), positionDelta); + const positionDeltaLength = vec2.length(positionDelta); + vec2.scale( + positionDelta, + positionDeltaDirection, + Math.min(positionDeltaLength, (positionDeltaLength / 50) * deltaTime * 800), + ); const hitObject = object.tryMove(positionDelta); if (hitObject instanceof PlanetPhysical) { diff --git a/backend/src/players/npc.ts b/backend/src/players/npc.ts new file mode 100644 index 0000000..acd4ed7 --- /dev/null +++ b/backend/src/players/npc.ts @@ -0,0 +1,132 @@ +import { vec2 } from 'gl-matrix'; +import { + PlayerInformation, + CharacterTeam, + settings, + Circle, + Random, + MoveActionCommand, +} from 'shared'; +import { PhysicalContainer } from '../physics/containers/physical-container'; +import { PlayerContainer } from './player-container'; +import { PlayerBase } from './player-base'; +import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; +import { PlayerCharacterPhysical } from '../objects/player-character-physical'; +import { PlanetPhysical } from '../objects/planet-physical'; + +export class NPC extends PlayerBase { + private moveTarget: vec2 = vec2.create(); + private planet?: PlanetPhysical; + private timeSinceLastFindTarget = 10000; + private timeSinceLastFindShootTarget = 10000; + + constructor( + playerInfo: PlayerInformation, + playerContainer: PlayerContainer, + objectContainer: PhysicalContainer, + team: CharacterTeam, + ) { + super(playerInfo, playerContainer, objectContainer, team); + this.createCharacter(); + this.step(0); + } + + private findTarget() { + const observableArea = getBoundingBoxOfCircle(new Circle(this.center, 100)); + const nearObjects = this.objectContainer.findIntersecting(observableArea); + + const enemies = nearObjects.filter( + (o) => + o.gameObject instanceof PlayerCharacterPhysical && + o.gameObject.team !== this.team, + ); + const allies = nearObjects.filter( + (o) => + o.gameObject instanceof PlayerCharacterPhysical && + o.gameObject.team === this.team, + ); + const notControlledPlanets = nearObjects.filter( + (o) => o.gameObject instanceof PlanetPhysical && o.gameObject.team !== this.team, + ); + + if (enemies.length > allies.length) { + console.log('fleeing'); + const enemiesCenter = enemies.reduce( + (sum, e) => vec2.add(sum, sum, (e.gameObject as PlayerCharacterPhysical).center), + vec2.create(), + ); + vec2.scale(enemiesCenter, enemiesCenter, 1 / enemies.length); + const enemiesDelta = vec2.subtract(enemiesCenter, this.center, enemiesCenter); + if (vec2.length(enemiesDelta) > 0) { + vec2.scale(enemiesDelta, enemiesDelta, 200 / vec2.length(enemiesDelta)); + } + vec2.add(this.moveTarget, this.center, enemiesDelta); + } else if (!this.planet) { + if (notControlledPlanets.length > 0) { + this.planet = notControlledPlanets[0] as PlanetPhysical; + this.moveTarget = this.planet.center; + } else { + this.moveTarget = vec2.fromValues( + Random.getRandomInRange(-5000, 5000), + Random.getRandomInRange(-5000, 5000), + ); + } + } + } + + private findShootTarget(): vec2 | undefined { + const observableArea = getBoundingBoxOfCircle(new Circle(this.center, 1000)); + const nearObjects = this.objectContainer.findIntersecting(observableArea); + + const enemies = nearObjects.filter( + (o) => + o.gameObject instanceof PlayerCharacterPhysical && + o.gameObject.team !== this.team, + ); + if (enemies.length > 0) { + return (enemies[0].gameObject as PlayerCharacterPhysical).center; + } + } + + private timeUntilRespawn = 0; + public step(deltaTimeInSeconds: number) { + if (this.character) { + this.center = this.character?.center; + + if (!this.character.isAlive) { + this.sumDeaths++; + this.sumKills = this.character.killCount; + + this.character = null; + this.timeUntilRespawn = settings.playerDiedTimeout; + } + } else { + if ((this.timeUntilRespawn -= deltaTimeInSeconds) < 0) { + this.createCharacter(); + this.center = this.character!.center; + } + } + + if (this.planet && Math.abs(this.planet.ownership - 0.5) > 0.3) { + this.planet = undefined; + this.findTarget(); + } else { + if ((this.timeSinceLastFindTarget += deltaTimeInSeconds) > 1) { + this.timeSinceLastFindTarget = 0; + this.findTarget(); + } + } + + if ((this.timeSinceLastFindShootTarget += deltaTimeInSeconds) > 0.5) { + const shootTarget = this.findShootTarget(); + if (shootTarget) { + this.character?.shootTowards(shootTarget); + } + this.timeSinceLastFindShootTarget = 0; + } + + const targetDelta = vec2.subtract(vec2.create(), this.moveTarget, this.center); + vec2.normalize(targetDelta, targetDelta); + this.character?.handleMovementAction(new MoveActionCommand(targetDelta, false)); + } +} diff --git a/backend/src/players/player-base.ts b/backend/src/players/player-base.ts new file mode 100644 index 0000000..d37a60e --- /dev/null +++ b/backend/src/players/player-base.ts @@ -0,0 +1,78 @@ +import { vec2 } from 'gl-matrix'; +import { CommandReceiver, Circle, PlayerInformation, CharacterTeam } from 'shared'; +import { PhysicalContainer } from '../physics/containers/physical-container'; +import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; +import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting'; +import { PlayerCharacterPhysical } from '../objects/player-character-physical'; +import { PlayerContainer } from './player-container'; + +export abstract class PlayerBase extends CommandReceiver { + public character?: PlayerCharacterPhysical | null; + public center: vec2 = vec2.create(); + + protected sumKills = 0; + protected sumDeaths = 0; + + constructor( + protected readonly playerInfo: PlayerInformation, + protected readonly playerContainer: PlayerContainer, + protected readonly objectContainer: PhysicalContainer, + public readonly team: CharacterTeam, + ) { + super(); + } + + protected createCharacter() { + this.character = new PlayerCharacterPhysical( + this.playerInfo.name.slice(0, 20), + this.sumKills, + this.sumDeaths, + this.team, + this.objectContainer, + this.findEmptyPositionForPlayer(), + ); + + this.objectContainer.addObject(this.character); + } + + public abstract step(deltaTimeInSeconds: number): void; + + protected findEmptyPositionForPlayer(): vec2 { + let possibleCenter = this.playerContainer.players.find( + (p) => p.character?.isAlive && p.team === this.team, + )?.center; + + if (!possibleCenter) { + possibleCenter = vec2.create(); + } + + let rotation = 0; + let radius = 0; + for (;;) { + const playerPosition = vec2.fromValues( + radius * Math.cos(rotation) + possibleCenter.x, + radius * Math.sin(rotation) + possibleCenter.y, + ); + + const playerBoundingCircle = new Circle( + playerPosition, + PlayerCharacterPhysical.boundRadius, + ); + + const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle); + const possibleIntersectors = this.objectContainer.findIntersecting( + playerBoundingBox, + ); + if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) { + return playerPosition; + } + + rotation += Math.PI / 8; + radius += 30; + } + } + + public destroy() { + this.character?.destroy(); + } +} diff --git a/backend/src/players/player-container.ts b/backend/src/players/player-container.ts index ec42e1c..1d9f8e9 100644 --- a/backend/src/players/player-container.ts +++ b/backend/src/players/player-container.ts @@ -1,31 +1,61 @@ -import { CharacterTeam, PlayerInformation, Random, TransportEvents } from 'shared'; +import { + CharacterTeam, + PlayerInformation, + Random, + TransportEvents, + settings, +} from 'shared'; import { PhysicalContainer } from '../physics/containers/physical-container'; +import { NPC } from './npc'; import { Player } from './player'; +import { PlayerBase } from './player-base'; export class PlayerContainer { private _players: Array = []; + private _npcs: Array = []; - constructor(private readonly objects: PhysicalContainer) {} + constructor( + private readonly objects: PhysicalContainer, + private readonly playerMaxCount: number, + ) { + this.createNPCs(); + } + + public createNPCs() { + const newNpcCount = this.playerMaxCount - this._players.length - this._npcs.length; + for (let i = 0; i < newNpcCount; i++) { + const name = `BOT ${Random.choose(settings.npcNames)}`; + this._npcs.push( + new NPC({ name }, this, this.objects, this.getTeamOfNextPlayer(true)), + ); + } + } public createPlayer(playerInfo: PlayerInformation, socket: SocketIO.Socket): Player { - const player = new Player( - playerInfo, - this, - this.objects, - socket, - this.getTeamOfNextPlayer(), - ); + if (this._players.length === this.playerMaxCount) { + throw new Error('Too many players'); + } + + const team = this.getTeamOfNextPlayer(); + let npcToReplace = this._npcs.find((n) => n.team === team); + if (!npcToReplace) { + npcToReplace = this._npcs.find((n) => n.team !== team); + } + npcToReplace?.destroy(); + this._npcs = this._npcs.filter((n) => n !== npcToReplace); + + const player = new Player(playerInfo, this, this.objects, team, socket); this._players.push(player); return player; } - public get players(): Array { - return this._players; + public get players(): Array { + return [...this._players, ...this._npcs]; } public get count(): number { - return this.players.length; + return this._players.length; } public step(deltaTimeInSeconds: number) { @@ -33,12 +63,13 @@ export class PlayerContainer { } public sendOnSocket(message: any) { - this.players.forEach((p) => p.socket.emit(TransportEvents.ServerToPlayer, message)); + this._players.forEach((p) => p.socket.emit(TransportEvents.ServerToPlayer, message)); } - private getTeamOfNextPlayer(): CharacterTeam { - const declaCount = this._players.filter((p) => p.team === CharacterTeam.decla).length; - const redCount = this._players.filter((p) => p.team === CharacterTeam.red).length; + private getTeamOfNextPlayer(isNpc = false): CharacterTeam { + const players = isNpc ? this.players : this._players; + const declaCount = players.filter((p) => p.team === CharacterTeam.decla).length; + const redCount = players.filter((p) => p.team === CharacterTeam.red).length; if ((declaCount === redCount && Random.getRandom() >= 0.5) || declaCount < redCount) { return CharacterTeam.decla; @@ -49,5 +80,6 @@ export class PlayerContainer { public deletePlayer(player: Player) { this._players = this._players.filter((p) => p !== player); + this.createNPCs(); } } diff --git a/backend/src/players/player.ts b/backend/src/players/player.ts index 5cc3649..e1eb9b7 100644 --- a/backend/src/players/player.ts +++ b/backend/src/players/player.ts @@ -27,35 +27,18 @@ import { import { getTimeInMilliseconds } from '../helper/get-time-in-milliseconds'; import { BoundingBox } from '../physics/bounding-boxes/bounding-box'; import { PhysicalContainer } from '../physics/containers/physical-container'; -import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; -import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting'; import { PlayerCharacterPhysical } from '../objects/player-character-physical'; -import { PlanetPhysical } from '../objects/planet-physical'; import { PlayerContainer } from './player-container'; +import { PlayerBase } from './player-base'; -export class Player extends CommandReceiver { - private character?: PlayerCharacterPhysical | null; +export class Player extends PlayerBase { private aspectRatio: number = 16 / 9; private isActive = true; - private sumKills = 0; - private sumDeaths = 0; - private objectsPreviouslyInViewArea: Array = []; private pingTime?: number; private _latency?: number; - public measureLatency() { - this.pingTime = getTimeInMilliseconds(); - this.socket.emit(TransportEvents.Ping); - if (this.isActive) { - setTimeout(this.measureLatency.bind(this), 10000); - } - } - - public get latency(): number | undefined { - return this._latency; - } protected commandExecutors: CommandExecutors = { [SetAspectRatioActionCommand.type]: (v: SetAspectRatioActionCommand) => @@ -68,14 +51,13 @@ export class Player extends CommandReceiver { }; constructor( - private readonly playerInfo: PlayerInformation, - private readonly playerContainer: PlayerContainer, - private readonly objectContainer: PhysicalContainer, + playerInfo: PlayerInformation, + playerContainer: PlayerContainer, + objectContainer: PhysicalContainer, + team: CharacterTeam, public readonly socket: SocketIO.Socket, - public readonly team: CharacterTeam, ) { - super(); - this.team = team; + super(playerInfo, playerContainer, objectContainer, team); this.createCharacter(); @@ -88,26 +70,25 @@ export class Player extends CommandReceiver { this.step(0); } - private createCharacter() { - this.character = new PlayerCharacterPhysical( - this.playerInfo.name.slice(0, 20), - this.sumKills, - this.sumDeaths, - this.team, - this.objectContainer, - this.findEmptyPositionForPlayer(), - ); - - this.objectContainer.addObject(this.character); - this.objectsPreviouslyInViewArea.push(this.character); - - this.socket.emit( - TransportEvents.ServerToPlayer, - serialize(new CreatePlayerCommand(this.character)), - ); + public measureLatency() { + this.pingTime = getTimeInMilliseconds(); + this.socket.emit(TransportEvents.Ping); + if (this.isActive) { + setTimeout(this.measureLatency.bind(this), 10000); + } + } + + public get latency(): number | undefined { + return this._latency; + } + + protected createCharacter() { + super.createCharacter(); + + this.objectsPreviouslyInViewArea.push(this.character!); + this.sendToPlayer(new CreatePlayerCommand(this.character!)); } - private center: vec2 = vec2.create(); private timeUntilRespawn = 0; public step(deltaTimeInSeconds: number) { if (this.character) { @@ -173,41 +154,6 @@ export class Player extends CommandReceiver { this.sendToPlayer(new UpdateOtherPlayerDirections(this.getOtherPlayers())); } - private findEmptyPositionForPlayer(): vec2 { - let possibleCenter = this.playerContainer.players.find( - (p) => p.character?.isAlive && p.team === this.team, - )?.center; - - if (!possibleCenter) { - possibleCenter = vec2.create(); - } - - let rotation = 0; - let radius = 0; - for (;;) { - const playerPosition = vec2.fromValues( - radius * Math.cos(rotation) + possibleCenter.x, - radius * Math.sin(rotation) + possibleCenter.y, - ); - - const playerBoundingCircle = new Circle( - playerPosition, - PlayerCharacterPhysical.boundRadius, - ); - - const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle); - const possibleIntersectors = this.objectContainer.findIntersecting( - playerBoundingBox, - ); - if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) { - return playerPosition; - } - - rotation += Math.PI / 8; - radius += 30; - } - } - private getOtherPlayers(): Array { if (!this.character) { return []; @@ -244,7 +190,7 @@ export class Player extends CommandReceiver { } public destroy() { + super.destroy(); this.isActive = false; - this.character?.destroy(); } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f6c8e9d..3b23147 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@typescript-eslint/parser": "^3.9.1", "clean-webpack-plugin": "^3.0.0", "common-config-webpack-plugin": "^2.0.1", + "css-loader": "^1.0.1", "eslint": "^7.2.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-import": "^2.21.2", @@ -21,16 +22,23 @@ "eslint-plugin-unused-imports": "^0.1.3", "firebase": "^7.22.0", "gl-matrix": "^3.3.0", + "html-webpack-inline-source-plugin": "^1.0.0-beta.2", "html-webpack-inline-svg-plugin": "^2.3.0", "html-webpack-plugin": "^4.5.0", "image-config-webpack-plugin": "^2.0.0", + "mini-css-extract-plugin": "^0.9.0", + "postcss-loader": "^3.0.0", "prettier": "^2.0.5", "resize-observer-polyfill": "^1.5.1", "resolve-url-loader": "^3.1.1", - "scss-config-webpack-plugin": "^2.0.0", - "sdf-2d": "^0.6.0", + "sass": "^1.27.0", + "sass-loader": "^8.0.2", + "sdf-2d": "file:..\\..\\sdf-2d", + "shared": "file:../shared", "socket.io-client": "^2.3.1", "source-map-loader": "^1.1.1", + "svg-url-loader": "^6.0.0", + "terser-webpack-plugin": "^4.2.2", "ts-config-webpack-plugin": "^2.0.0", "typescript": "^4.0.3", "webpack": "^4.43.0", @@ -38,6 +46,55 @@ "webpack-dev-server": "^3.11.0" } }, + "../../sdf-2d": { + "version": "0.6.1", + "dev": true, + "license": "ISC", + "dependencies": { + "gl-matrix": "^3.3.0" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^3.10.1", + "@typescript-eslint/parser": "^3.10.1", + "eslint": "^7.9.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^0.1.3", + "prettier": "^2.1.2", + "raw-loader": "^4.0.1", + "terser-webpack-plugin": "^2.3.8", + "ts-loader": "^8.0.3", + "typedoc": "^0.19.2", + "typedoc-plugin-extras": "^1.1.6", + "typescript": "^3.9.7", + "webpack": "^4.44.2", + "webpack-cli": "^3.3.11" + } + }, + "../shared": { + "version": "0.0.0", + "dev": true, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^3.9.1", + "@typescript-eslint/parser": "^3.9.1", + "clean-webpack-plugin": "^3.0.0", + "eslint": "^7.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.21.2", + "eslint-plugin-json-format": "^2.0.1", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^0.1.3", + "file-loader": "^6.1.0", + "gl-matrix": "^3.3.0", + "prettier": "^2.0.5", + "terser-webpack-plugin": "^2.3.8", + "ts-loader": "^8.0.3", + "typescript": "^4.0.3", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12" + } + }, "node_modules/@babel/code-frame": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", @@ -2111,6 +2168,30 @@ "node": ">= 8" } }, + "node_modules/@npmcli/move-file": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", + "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -2743,6 +2824,28 @@ "node": ">= 6.0.0" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3900,42 +4003,91 @@ } }, "node_modules/cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", + "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", "dev": true, "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "rimraf": "^3.0.2", + "ssri": "^8.0.0", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "dependencies": { - "yallist": "^3.0.2" + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cacache/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", + "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } }, "node_modules/cache-base": { "version": "1.0.1", @@ -4202,10 +4354,13 @@ } }, "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/chrome-trace-event": { "version": "1.0.2", @@ -4348,6 +4503,15 @@ "node": ">= 4.0" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/clean-webpack-plugin": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz", @@ -8087,6 +8251,18 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -8818,6 +8994,26 @@ "node": ">=6" } }, + "node_modules/html-webpack-inline-source-plugin": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/html-webpack-inline-source-plugin/-/html-webpack-inline-source-plugin-1.0.0-beta.2.tgz", + "integrity": "sha512-ydsEKdp0tnbmnqRAH2WSSMXerCNYhjes5b79uvP2BU3p6cyk+6ucNMsw5b5xD1QxphgvBBA3QqVmdcpu8QLlRQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "slash": "^1.0.0", + "source-map-url": "^0.4.0" + } + }, + "node_modules/html-webpack-inline-source-plugin/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/html-webpack-inline-svg-plugin": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/html-webpack-inline-svg-plugin/-/html-webpack-inline-svg-plugin-2.3.0.tgz", @@ -9961,6 +10157,20 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "node_modules/jest-worker": { + "version": "26.6.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.1.tgz", + "integrity": "sha512-R5IE3qSGz+QynJx8y+ICEkdI2OJ3RJjRQVEyCcFAd3yVhQSEtquziPO29Mlzgn07LOVE8u8jhJ1FqcwegiXWOw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -10653,6 +10863,12 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -10849,6 +11065,67 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -14627,6 +14904,21 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sass": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.27.0.tgz", + "integrity": "sha512-0gcrER56OkzotK/GGwgg4fPrKuiFlPNitO7eUJ18Bs+/NBlofJfMxmxqpqJxjae9vu0Wq8TZzrSyxZal00WDig==", + "dev": true, + "dependencies": { + "chokidar": ">=2.0.0 <4.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/sass-graph": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", @@ -14855,13 +15147,8 @@ } }, "node_modules/sdf-2d": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/sdf-2d/-/sdf-2d-0.6.0.tgz", - "integrity": "sha512-k6osouD30i1/sLCYJeAINwKe159SCwM4JQJMw3YIY2MxvKKrxQy2+djTIfUd8YvBQCHN4u/0bULmNBmw9DDO6w==", - "dev": true, - "dependencies": { - "gl-matrix": "^3.3.0" - } + "resolved": "../../sdf-2d", + "link": true }, "node_modules/select-hose": { "version": "2.0.0", @@ -14948,9 +15235,9 @@ "dev": true }, "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -15089,6 +15376,10 @@ "node": ">=8" } }, + "node_modules/shared": { + "resolved": "../shared", + "link": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15838,12 +16129,15 @@ } }, "node_modules/ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz", + "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==", "dev": true, "dependencies": { - "figgy-pudding": "^3.5.1" + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" } }, "node_modules/stable": { @@ -16391,6 +16685,86 @@ "node": ">=6.9.5" } }, + "node_modules/svg-url-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-6.0.0.tgz", + "integrity": "sha512-Qr5SCKxyxKcRnvnVrO3iQj9EX/v40UiGEMshgegzV7vpo3yc+HexELOdtWcA3MKjL8IyZZ1zOdcILmDEa/8JJQ==", + "dev": true, + "dependencies": { + "file-loader": "~6.0.0", + "loader-utils": "~2.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/svg-url-loader/node_modules/file-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz", + "integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/svg-url-loader/node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/svg-url-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/svg-url-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/svg2ttf": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/svg2ttf/-/svg2ttf-4.3.0.tgz", @@ -16700,40 +17074,218 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", + "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", "dev": true, "dependencies": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.5.0", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" + "terser": "^5.3.4", + "webpack-sources": "^1.4.3" }, "engines": { - "node": ">= 6.9.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0" + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", "dev": true, "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">= 4" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/terser-webpack-plugin/node_modules/terser": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", + "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" } }, "node_modules/terser/node_modules/commander": { @@ -18322,6 +18874,35 @@ "node": ">=0.4.0" } }, + "node_modules/webpack/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/webpack/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "node_modules/webpack/node_modules/eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -18335,6 +18916,15 @@ "node": ">=4.0.0" } }, + "node_modules/webpack/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/webpack/node_modules/memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -18380,6 +18970,24 @@ "node": ">= 4" } }, + "node_modules/webpack/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/webpack/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, "node_modules/webpack/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -18389,6 +18997,35 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/webpack/node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/webpack/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -20082,15 +20719,13 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.5.tgz", "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/auth-types": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.10.1.tgz", "integrity": "sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/component": { "version": "0.1.19", @@ -20147,8 +20782,7 @@ "version": "1.14.0", "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.14.0.tgz", "integrity": "sha512-WF8IBwHzZDhwyOgQnmB0pheVrLNP78A8PGxk1nxb/Nrgh1amo4/zYvFMGgSsTeaQK37xMYS/g7eS948te/dJxw==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/functions": { "version": "0.5.1", @@ -20186,8 +20820,7 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.3.4.tgz", "integrity": "sha512-RfePJFovmdIXb6rYwtngyxuEcWnOrzdZd9m7xAW0gRxDIjBT20n3BOhjpmgRWXo/DAxRmS7bRjWAyTHY9cqN7Q==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/logger": { "version": "0.2.6", @@ -20213,8 +20846,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@firebase/messaging-types/-/messaging-types-0.5.0.tgz", "integrity": "sha512-QaaBswrU6umJYb/ZYvjR5JDSslCGOH6D9P136PhabFAHLTR4TWjsaACvbBXuvwrfCXu10DtcjMxqfhdNIB1Xfg==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/performance": { "version": "0.4.2", @@ -20283,8 +20915,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.13.tgz", "integrity": "sha512-pL7b8d5kMNCCL0w9hF7pr16POyKkb3imOW7w0qYrhBnbyJTdVxMWZhb0HxCFyQWC0w3EiIFFmxoz8NTFZDEFog==", - "dev": true, - "requires": {} + "dev": true }, "@firebase/util": { "version": "0.3.2", @@ -20493,6 +21124,23 @@ "fastq": "^1.6.0" } }, + "@npmcli/move-file": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", + "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -20980,8 +21628,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true, - "requires": {} + "dev": true }, "adjust-sourcemap-loader": { "version": "3.0.0", @@ -21030,6 +21677,24 @@ "debug": "4" } }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "dependencies": { + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + } + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -21046,15 +21711,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true, - "requires": {} + "dev": true }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "alphanum-sort": { "version": "1.0.2", @@ -21992,42 +22655,67 @@ "dev": true }, "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", + "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", "dev": true, "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "rimraf": "^3.0.2", + "ssri": "^8.0.0", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" }, "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "requires": { - "yallist": "^3.0.2" + "aggregate-error": "^3.0.0" } }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "tar": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", + "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } } } }, @@ -22259,9 +22947,9 @@ } }, "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true }, "chrome-trace-event": { @@ -22378,6 +23066,12 @@ "source-map": "~0.6.0" } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "clean-webpack-plugin": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz", @@ -25466,6 +26160,15 @@ } } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -26077,6 +26780,25 @@ "terser": "^4.6.3" } }, + "html-webpack-inline-source-plugin": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/html-webpack-inline-source-plugin/-/html-webpack-inline-source-plugin-1.0.0-beta.2.tgz", + "integrity": "sha512-ydsEKdp0tnbmnqRAH2WSSMXerCNYhjes5b79uvP2BU3p6cyk+6ucNMsw5b5xD1QxphgvBBA3QqVmdcpu8QLlRQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "slash": "^1.0.0", + "source-map-url": "^0.4.0" + }, + "dependencies": { + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } + } + }, "html-webpack-inline-svg-plugin": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/html-webpack-inline-svg-plugin/-/html-webpack-inline-svg-plugin-2.3.0.tgz", @@ -26971,6 +27693,17 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "jest-worker": { + "version": "26.6.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.1.tgz", + "integrity": "sha512-R5IE3qSGz+QynJx8y+ICEkdI2OJ3RJjRQVEyCcFAd3yVhQSEtquziPO29Mlzgn07LOVE8u8jhJ1FqcwegiXWOw==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, "js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -27561,6 +28294,12 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -27718,6 +28457,52 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -30878,6 +31663,15 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sass": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.27.0.tgz", + "integrity": "sha512-0gcrER56OkzotK/GGwgg4fPrKuiFlPNitO7eUJ18Bs+/NBlofJfMxmxqpqJxjae9vu0Wq8TZzrSyxZal00WDig==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, "sass-graph": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", @@ -31057,12 +31851,25 @@ } }, "sdf-2d": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/sdf-2d/-/sdf-2d-0.6.0.tgz", - "integrity": "sha512-k6osouD30i1/sLCYJeAINwKe159SCwM4JQJMw3YIY2MxvKKrxQy2+djTIfUd8YvBQCHN4u/0bULmNBmw9DDO6w==", - "dev": true, + "version": "file:../../sdf-2d", "requires": { - "gl-matrix": "^3.3.0" + "@typescript-eslint/eslint-plugin": "^3.10.1", + "@typescript-eslint/parser": "^3.10.1", + "eslint": "^7.9.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^0.1.3", + "gl-matrix": "^3.3.0", + "prettier": "^2.1.2", + "raw-loader": "^4.0.1", + "terser-webpack-plugin": "^2.3.8", + "ts-loader": "^8.0.3", + "typedoc": "^0.19.2", + "typedoc-plugin-extras": "^1.1.6", + "typescript": "^3.9.7", + "webpack": "^4.44.2", + "webpack-cli": "^3.3.11" } }, "select-hose": { @@ -31139,9 +31946,9 @@ } }, "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -31264,6 +32071,28 @@ "kind-of": "^6.0.2" } }, + "shared": { + "version": "file:../shared", + "requires": { + "@typescript-eslint/eslint-plugin": "^3.9.1", + "@typescript-eslint/parser": "^3.9.1", + "clean-webpack-plugin": "^3.0.0", + "eslint": "^7.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.21.2", + "eslint-plugin-json-format": "^2.0.1", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^0.1.3", + "file-loader": "^6.1.0", + "gl-matrix": "^3.3.0", + "prettier": "^2.0.5", + "terser-webpack-plugin": "^2.3.8", + "ts-loader": "^8.0.3", + "typescript": "^4.0.3", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -31905,12 +32734,12 @@ } }, "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz", + "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==", "dev": true, "requires": { - "figgy-pudding": "^3.5.1" + "minipass": "^3.1.1" } }, "stable": { @@ -32372,6 +33201,59 @@ "integrity": "sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow==", "dev": true }, + "svg-url-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-6.0.0.tgz", + "integrity": "sha512-Qr5SCKxyxKcRnvnVrO3iQj9EX/v40UiGEMshgegzV7vpo3yc+HexELOdtWcA3MKjL8IyZZ1zOdcILmDEa/8JJQ==", + "dev": true, + "requires": { + "file-loader": "~6.0.0", + "loader-utils": "~2.0.0" + }, + "dependencies": { + "file-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz", + "integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.6.5" + } + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + } + } + }, "svg2ttf": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/svg2ttf/-/svg2ttf-4.3.0.tgz", @@ -32638,31 +33520,151 @@ } }, "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", + "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", "dev": true, "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", + "cacache": "^15.0.5", + "find-cache-dir": "^3.3.1", + "jest-worker": "^26.5.0", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" + "terser": "^5.3.4", + "webpack-sources": "^1.4.3" }, "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "terser": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", + "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } } } @@ -33615,6 +34617,35 @@ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -33625,6 +34656,15 @@ "estraverse": "^4.1.1" } }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -33667,6 +34707,24 @@ "ajv-keywords": "^3.1.0" } }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -33675,6 +34733,29 @@ "requires": { "safe-buffer": "~5.1.0" } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } }, diff --git a/frontend/package.json b/frontend/package.json index 708b320..5ae62dd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -47,7 +47,7 @@ "resolve-url-loader": "^3.1.1", "sass": "^1.27.0", "sass-loader": "^8.0.2", - "sdf-2d": "^0.6.0", + "sdf-2d": "^0.6.2", "shared": "file:../shared", "socket.io-client": "^2.3.1", "source-map-loader": "^1.1.1", diff --git a/frontend/src/index.ts b/frontend/src/index.ts index ea1fe20..97afc7b 100644 --- a/frontend/src/index.ts +++ b/frontend/src/index.ts @@ -1,13 +1,11 @@ import { glMatrix } from 'gl-matrix'; import { - CharacterBase, LampBase, overrideDeserialization, PlanetBase, PlayerCharacterBase, ProjectileBase, } from 'shared'; -import { CharacterView } from './scripts/objects/character-view'; import { LampView } from './scripts/objects/lamp-view'; import { ProjectileView } from './scripts/objects/projectile-view'; import { PlanetView } from './scripts/objects/planet-view'; @@ -33,7 +31,6 @@ import { SoundHandler, Sounds } from './scripts/sound-handler'; glMatrix.setMatrixArrayType(Array); -overrideDeserialization(CharacterBase, CharacterView); overrideDeserialization(PlayerCharacterBase, PlayerCharacterView); overrideDeserialization(PlanetBase, PlanetView); overrideDeserialization(LampBase, LampView); diff --git a/frontend/src/main.scss b/frontend/src/main.scss index 52be356..a1f3d0d 100644 --- a/frontend/src/main.scss +++ b/frontend/src/main.scss @@ -115,7 +115,7 @@ body { .player-tag { transform: translateX(-50%) translateY(-50%) rotate(-15deg); - transition: left 200ms, top 200ms; + transition: left 150ms, top 150ms; border-radius: 1000px; &.decla { diff --git a/frontend/src/scripts/game.ts b/frontend/src/scripts/game.ts index d26fa09..7ee58c2 100644 --- a/frontend/src/scripts/game.ts +++ b/frontend/src/scripts/game.ts @@ -155,7 +155,12 @@ export class Game extends CommandReceiver { const angle = Math.atan2(direction.y, direction.x); e.className = 'other-player-arrow ' + team; - const { width, height } = this.overlay.getBoundingClientRect(); + if (!this.renderer) { + return; + } + + const width = this.renderer.canvasSize.x; + const height = this.renderer.canvasSize.y; const aspectRatio = width / height; const directionRatio = direction.x / direction.y; diff --git a/frontend/src/scripts/objects/character-view.ts b/frontend/src/scripts/objects/character-view.ts deleted file mode 100644 index 8270fa2..0000000 --- a/frontend/src/scripts/objects/character-view.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { vec2 } from 'gl-matrix'; -import { Renderer } from 'sdf-2d'; -import { CharacterBase, CharacterTeam, Circle, Id, settings } from 'shared'; - -import { BlobShape } from '../shapes/blob-shape'; -import { ViewObject } from './view-object'; - -export class CharacterView extends CharacterBase implements ViewObject { - private shape: BlobShape; - - constructor( - id: Id, - team: CharacterTeam, - health: number, - head?: Circle, - leftFoot?: Circle, - rightFoot?: Circle, - ) { - super(id, team, health, head, leftFoot, rightFoot); - this.shape = new BlobShape(settings.colorIndices[team]); - } - - public get position(): vec2 { - return this.head!.center; - } - - public beforeDestroy(): void {} - - public step(deltaTimeInSeconds: number): void {} - - public draw(renderer: Renderer, overlay: HTMLElement): void { - this.shape.setCircles([this.head!, this.leftFoot!, this.rightFoot!]); - renderer.addDrawable(this.shape); - } -} diff --git a/frontend/src/scripts/objects/player-character-view.ts b/frontend/src/scripts/objects/player-character-view.ts index 4560a08..75db37a 100644 --- a/frontend/src/scripts/objects/player-character-view.ts +++ b/frontend/src/scripts/objects/player-character-view.ts @@ -12,7 +12,6 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje private nameElement: HTMLElement = document.createElement('div'); private statsElement: HTMLElement = document.createElement('div'); private healthElement: HTMLElement = document.createElement('div'); - private timeSinceLastNameElementUpdate = 0; private previousHealth; constructor( @@ -50,7 +49,6 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje } public step(deltaTimeInSeconds: number): void { - this.timeSinceLastNameElementUpdate += deltaTimeInSeconds; this.healthElement.style.width = (50 * this.health) / settings.playerMaxHealth + 'px'; this.statsElement.innerText = this.getStatsText(); if (this.previousHealth > this.health) { @@ -75,14 +73,11 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje overlay.appendChild(this.nameElement); } - if (this.timeSinceLastNameElementUpdate > 0.15) { - const screenPosition = renderer.worldToDisplayCoordinates( - this.calculateTextPosition(), - ); - this.nameElement.style.left = screenPosition.x + 'px'; - this.nameElement.style.top = screenPosition.y + 'px'; - this.timeSinceLastNameElementUpdate = 0; - } + const screenPosition = renderer.worldToDisplayCoordinates( + this.calculateTextPosition(), + ); + this.nameElement.style.left = screenPosition.x + 'px'; + this.nameElement.style.top = screenPosition.y + 'px'; this.shape.setCircles([this.head!, this.leftFoot!, this.rightFoot!]); renderer.addDrawable(this.shape); diff --git a/frontend/src/scripts/sound-handler.ts b/frontend/src/scripts/sound-handler.ts index bfab026..c17b5ec 100644 --- a/frontend/src/scripts/sound-handler.ts +++ b/frontend/src/scripts/sound-handler.ts @@ -33,6 +33,7 @@ export abstract class SoundHandler { setTimeout(() => { this.ambientSound.muted = false; this.ambientSound.volume = 0.5; + this.ambientSound.loop = true; if (!this.isAmbientPlaying) { this.ambientSound.pause(); } diff --git a/shared/src/main.ts b/shared/src/main.ts index f00b11c..2c35c0a 100644 --- a/shared/src/main.ts +++ b/shared/src/main.ts @@ -44,7 +44,6 @@ export * from './transport/serialization/serialize'; export * from './transport/serialization/serializes-to'; export * from './transport/serialization/serializable'; export * from './transport/serialization/override-deserialization'; -export * from './objects/types/character-base'; export * from './objects/types/character-team'; export * from './objects/types/player-character-base'; export * from './objects/types/lamp-base'; diff --git a/shared/src/objects/types/character-base.ts b/shared/src/objects/types/character-base.ts deleted file mode 100644 index b9d0607..0000000 --- a/shared/src/objects/types/character-base.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Circle } from '../../helper/circle'; -import { Id } from '../../transport/identity'; -import { serializable } from '../../transport/serialization/serializable'; -import { GameObject } from '../game-object'; -import { CharacterTeam } from './character-team'; - -@serializable -export class CharacterBase extends GameObject { - constructor( - id: Id, - public team: CharacterTeam, - public health: number, - public head?: Circle, - public leftFoot?: Circle, - public rightFoot?: Circle, - ) { - super(id); - } - - public onShoot(strength: number) {} - - public toArray(): Array { - const { id, team, health, head, leftFoot, rightFoot } = this; - return [id, team, health, head, leftFoot, rightFoot]; - } -} diff --git a/shared/src/objects/types/player-character-base.ts b/shared/src/objects/types/player-character-base.ts index 5fec1ad..35581cd 100644 --- a/shared/src/objects/types/player-character-base.ts +++ b/shared/src/objects/types/player-character-base.ts @@ -1,23 +1,23 @@ -import { CharacterBase } from './character-base'; import { Circle } from '../../helper/circle'; import { Id } from '../../transport/identity'; import { serializable } from '../../transport/serialization/serializable'; +import { GameObject } from '../game-object'; import { CharacterTeam } from './character-team'; @serializable -export class PlayerCharacterBase extends CharacterBase { +export class PlayerCharacterBase extends GameObject { constructor( id: Id, public name: string, public killCount: number, public deathCount: number, - team: CharacterTeam, - health: number, - head?: Circle, - leftFoot?: Circle, - rightFoot?: Circle, + public team: CharacterTeam, + public health: number, + public head?: Circle, + public leftFoot?: Circle, + public rightFoot?: Circle, ) { - super(id, team, health, head, leftFoot, rightFoot); + super(id); } public onShoot(strength: number) {} diff --git a/shared/src/settings.ts b/shared/src/settings.ts index 679a51a..fbc7e9d 100644 --- a/shared/src/settings.ts +++ b/shared/src/settings.ts @@ -44,6 +44,64 @@ export const settings = { backgroundGradient: [rgb255(90, 38, 43), rgb255(43, 39, 73)], declaColor, declaPlanetColor, + npcNames: [ + 'Adam', + 'Clarence', + 'Elliot', + 'Elmer', + 'Ernie', + 'Eugene', + 'Fergus', + 'Ferris', + 'Frank', + 'Frasier', + 'Fred', + 'George', + 'Graham', + 'Harvey', + 'Irwin', + 'Larry', + 'Lester', + 'Marvin', + 'Neil', + 'Niles', + 'Oliver', + 'Blaise', + 'Andrew', + 'Opie', + 'Ryan', + 'Toby', + 'Ulric', + 'Ulysses', + 'Uri', + 'Waldo', + 'Wally', + 'Walt', + 'Wesley', + 'Yanni', + 'Yogi', + 'Yuri', + 'Dean', + 'Dustin', + 'Ethan', + 'Harold', + 'Henry', + 'Irving', + 'Jason', + 'Jenssen', + 'Josh', + 'Martin', + 'Nick', + 'Norm', + 'Orin', + 'Pat', + 'Perry', + 'Ron', + 'Shawn', + 'Tim', + 'Will', + 'Wyatt', + ], redColor, redPlanetColor, colorIndices: {