diff --git a/back/src/App.ts b/back/src/App.ts index ac681ba3..a2aa91a5 100644 --- a/back/src/App.ts +++ b/back/src/App.ts @@ -18,6 +18,7 @@ class App { public mapController: MapController; public prometheusController: PrometheusController; private adminController: AdminController; + private debugController: DebugController; constructor() { this.app = express(); diff --git a/back/src/Model/Group.ts b/back/src/Model/Group.ts index d08e6d90..f2e5feb1 100644 --- a/back/src/Model/Group.ts +++ b/back/src/Model/Group.ts @@ -57,8 +57,9 @@ export class Group implements Movable { let y = 0; // Let's compute the barycenter of all users. this.users.forEach((user: User) => { - x += user.position.x; - y += user.position.y; + const position = user.getPosition(); + x += position.x; + y += position.y; }); x /= this.users.size; y /= this.users.size; @@ -69,8 +70,7 @@ export class Group implements Movable { this.y = y; if (oldX === undefined) { - // TODO: do we need a "create" - this.positionNotifier.updatePosition(this, {x, y}, {x, y}); + this.positionNotifier.enter(this); } else { this.positionNotifier.updatePosition(this, {x, y}, {x: oldX, y: oldY}); } diff --git a/back/src/Model/PositionNotifier.ts b/back/src/Model/PositionNotifier.ts index 0c30fe30..215d6ee6 100644 --- a/back/src/Model/PositionNotifier.ts +++ b/back/src/Model/PositionNotifier.ts @@ -74,6 +74,13 @@ export class PositionNotifier { return things; } + public enter(thing: Movable): void { + const position = thing.getPosition(); + const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y); + const zone = this.getZone(zoneDesc.i, zoneDesc.j); + zone.enter(thing, null, position); + } + public updatePosition(thing: Movable, newPosition: PositionInterface, oldPosition: PositionInterface): void { // Did we change zone? const oldZoneDesc = this.getZoneDescriptorFromCoordinates(oldPosition.x, oldPosition.y); diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index b147e4be..2396c4d8 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -3,6 +3,7 @@ import { PointInterface } from "./Websocket/PointInterface"; import {Zone} from "_Model/Zone"; import {Movable} from "_Model/Movable"; import {PositionInterface} from "_Model/PositionInterface"; +import {PositionNotifier} from "_Model/PositionNotifier"; export class User implements Movable { public listenedZones: Set; @@ -10,14 +11,22 @@ export class User implements Movable { public constructor( public id: number, - public position: PointInterface, + private position: PointInterface, public silent: boolean, - + private positionNotifier: PositionNotifier ) { this.listenedZones = new Set(); + + this.positionNotifier.enter(this); } - public getPosition(): PositionInterface { + public getPosition(): PointInterface { return this.position; } + + public setPosition(position: PointInterface): void { + const oldPosition = this.position; + this.position = position; + this.positionNotifier.updatePosition(this, position, oldPosition); + } } diff --git a/back/src/Model/World.ts b/back/src/Model/World.ts index bbc472a0..75ac1bdc 100644 --- a/back/src/Model/World.ts +++ b/back/src/Model/World.ts @@ -56,9 +56,11 @@ export class World { } public join(socket : Identificable, userPosition: PointInterface): void { - this.users.set(socket.userId, new User(socket.userId, userPosition, false)); + const user = new User(socket.userId, userPosition, false, this.positionNotifier); + this.users.set(socket.userId, user); // Let's call update position to trigger the join / leave room - this.updatePosition(socket, userPosition); + //this.updatePosition(socket, userPosition); + this.updateUserGroup(user); } public leave(user : Identificable){ @@ -87,16 +89,13 @@ export class World { return; } - this.positionNotifier.updatePosition(user, userPosition, user.position); + user.setPosition(userPosition); - const oldGroupPosition = user.group?.getPosition(); + this.updateUserGroup(user); + } - user.position = userPosition; + private updateUserGroup(user: User): void { user.group?.updatePosition(); - /*if (user.group !== undefined) { - // TODO: positionNotifier should be notified by the group itself when it moves!!! - this.positionNotifier.updatePosition(user.group, user.group.getPosition(), oldGroupPosition ? oldGroupPosition : user.group.getPosition()); - }*/ if (user.silent) { return; @@ -124,16 +123,11 @@ export class World { } else { // If the user is part of a group: // should he leave the group? - const distance = World.computeDistanceBetweenPositions(user.position, user.group.getPosition()); + const distance = World.computeDistanceBetweenPositions(user.getPosition(), user.group.getPosition()); if (distance > this.groupRadius) { this.leaveGroup(user); } } - - // At the very end, if the user is part of a group, let's call the callback to update group position - /*if (user.group !== undefined) { - this.positionNotifier.updatePosition(user.group, user.group.getPosition(), oldGroupPosition ? oldGroupPosition : user.group.getPosition()); - }*/ } setSilent(socket: Identificable, silent: boolean) { @@ -152,7 +146,7 @@ export class World { } if (!silent) { // If we are back to life, let's trigger a position update to see if we can join some group. - this.updatePosition(socket, user.position); + this.updatePosition(socket, user.getPosition()); } } @@ -251,7 +245,7 @@ export class World { if (group.isFull()) { return; } - const distance = World.computeDistanceBetweenPositions(user.position, group.getPosition()); + const distance = World.computeDistanceBetweenPositions(user.getPosition(), group.getPosition()); if(distance <= minimumDistanceFound && distance <= this.groupRadius) { minimumDistanceFound = distance; matchingItem = group; @@ -263,7 +257,9 @@ export class World { public static computeDistance(user1: User, user2: User): number { - return Math.sqrt(Math.pow(user2.position.x - user1.position.x, 2) + Math.pow(user2.position.y - user1.position.y, 2)); + const user1Position = user1.getPosition(); + const user2Position = user2.getPosition(); + return Math.sqrt(Math.pow(user2Position.x - user1Position.x, 2) + Math.pow(user2Position.y - user1Position.y, 2)); } public static computeDistanceBetweenPositions(position1: PositionInterface, position2: PositionInterface): number diff --git a/back/src/Model/Zone.ts b/back/src/Model/Zone.ts index 36551b39..4266c892 100644 --- a/back/src/Model/Zone.ts +++ b/back/src/Model/Zone.ts @@ -25,10 +25,10 @@ export class Zone { const result = this.things.delete(thing); if (!result) { if (thing instanceof User) { - console.error('Could not find user in zone '+thing.id); + throw new Error('Could not find user in zone '+thing.id); } if (thing instanceof Group) { - console.error('Could not find group '+thing.getId()+' in zone ('+this.x+','+this.y+'). Position of group: ('+thing.getPosition().x+','+thing.getPosition().y+')'); + throw new Error('Could not find group '+thing.getId()+' in zone ('+this.x+','+this.y+'). Position of group: ('+thing.getPosition().x+','+thing.getPosition().y+')'); } } diff --git a/back/tests/PositionNotifierTest.ts b/back/tests/PositionNotifierTest.ts index 643dd938..e65d025d 100644 --- a/back/tests/PositionNotifierTest.ts +++ b/back/tests/PositionNotifierTest.ts @@ -9,14 +9,6 @@ import {Zone} from "_Model/Zone"; import {Movable} from "_Model/Movable"; import {PositionInterface} from "_Model/PositionInterface"; -function move(user: User, x: number, y: number, positionNotifier: PositionNotifier): void { - positionNotifier.updatePosition(user, { - x, - y - }, user.position); - user.position.x = x; - user.position.y = y; -} describe("PositionNotifier", () => { it("should receive notifications when player moves", () => { @@ -37,14 +29,14 @@ describe("PositionNotifier", () => { y: 500, moving: false, direction: 'down' - }, false); + }, false, positionNotifier); const user2 = new User(2, { x: -9999, y: -9999, moving: false, direction: 'down' - }, false); + }, false, positionNotifier); positionNotifier.setViewport(user1, { left: 200, @@ -53,21 +45,21 @@ describe("PositionNotifier", () => { bottom: 500 }); - move(user2, 500, 500, positionNotifier); + user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); expect(enterTriggered).toBe(true); expect(moveTriggered).toBe(false); enterTriggered = false; // Move inside the zone - move(user2, 501, 500, positionNotifier); + user2.setPosition({x:501, y:500, direction: 'down', moving: false}); expect(enterTriggered).toBe(false); expect(moveTriggered).toBe(true); moveTriggered = false; // Move out of the zone in a zone that we don't track - move(user2, 901, 500, positionNotifier); + user2.setPosition({x: 901, y: 500, direction: 'down', moving: false}); expect(enterTriggered).toBe(false); expect(moveTriggered).toBe(false); @@ -75,14 +67,14 @@ describe("PositionNotifier", () => { leaveTriggered = false; // Move back in - move(user2, 500, 500, positionNotifier); + user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); expect(enterTriggered).toBe(true); expect(moveTriggered).toBe(false); expect(leaveTriggered).toBe(false); enterTriggered = false; // Move out of the zone in a zone that we do track - move(user2, 200, 500, positionNotifier); + user2.setPosition({x: 200, y: 500, direction: 'down', moving: false}); expect(enterTriggered).toBe(false); expect(moveTriggered).toBe(true); expect(leaveTriggered).toBe(false); @@ -115,14 +107,14 @@ describe("PositionNotifier", () => { y: 500, moving: false, direction: 'down' - }, false); + }, false, positionNotifier); const user2 = new User(2, { - x: -9999, - y: -9999, + x: 0, + y: 0, moving: false, direction: 'down' - }, false); + }, false, positionNotifier); let newUsers = positionNotifier.setViewport(user1, { left: 200, @@ -131,14 +123,16 @@ describe("PositionNotifier", () => { bottom: 500 }); - expect(newUsers.length).toBe(0); - - move(user2, 500, 500, positionNotifier); - + expect(newUsers.length).toBe(2); expect(enterTriggered).toBe(true); - expect(moveTriggered).toBe(false); enterTriggered = false; + user2.setPosition({x: 500, y: 500, direction: 'down', moving: false}); + + expect(enterTriggered).toBe(false); + expect(moveTriggered).toBe(true); + moveTriggered = false; + // Move the viewport but the user stays inside. positionNotifier.setViewport(user1, { left: 201, @@ -176,6 +170,6 @@ describe("PositionNotifier", () => { expect(moveTriggered).toBe(false); expect(leaveTriggered).toBe(false); enterTriggered = false; - expect(newUsers.length).toBe(1); + expect(newUsers.length).toBe(2); }); })