diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index 5667146a..74849fe0 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -181,6 +181,7 @@ export class GameRoom { private updateUserGroup(user: User): void { user.group?.updatePosition(); + user.group?.searchForNearbyUsers(); if (user.silent) { return; @@ -206,6 +207,7 @@ export class GameRoom { const group: Group = new Group( this.roomUrl, [user, closestUser], + this.groupRadius, this.connectCallback, this.disconnectCallback, this.positionNotifier diff --git a/back/src/Model/Group.ts b/back/src/Model/Group.ts index 5a0f3be6..931ddda5 100644 --- a/back/src/Model/Group.ts +++ b/back/src/Model/Group.ts @@ -1,10 +1,10 @@ -import { ConnectCallback, DisconnectCallback } from "./GameRoom"; +import { ConnectCallback, DisconnectCallback, GameRoom } from "./GameRoom"; import { User } from "./User"; import { PositionInterface } from "_Model/PositionInterface"; import { Movable } from "_Model/Movable"; import { PositionNotifier } from "_Model/PositionNotifier"; -import { gaugeManager } from "../Services/GaugeManager"; import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable"; +import type { Zone } from "../Model/Zone"; export class Group implements Movable { private static nextId: number = 1; @@ -13,13 +13,14 @@ export class Group implements Movable { private users: Set; private x!: number; private y!: number; - private hasEditedGauge: boolean = false; private wasDestroyed: boolean = false; private roomId: string; + private currentZone: Zone | null = null; constructor( roomId: string, users: User[], + private groupRadius: number, private connectCallback: ConnectCallback, private disconnectCallback: DisconnectCallback, private positionNotifier: PositionNotifier @@ -28,13 +29,6 @@ export class Group implements Movable { this.users = new Set(); this.id = Group.nextId; Group.nextId++; - //we only send a event for prometheus metrics if the group lives more than 5 seconds - setTimeout(() => { - if (!this.wasDestroyed) { - this.hasEditedGauge = true; - gaugeManager.incNbGroupsPerRoomGauge(roomId); - } - }, 5000); users.forEach((user: User) => { this.join(user); @@ -85,9 +79,22 @@ export class Group implements Movable { this.y = y; if (oldX === undefined) { - this.positionNotifier.enter(this); + this.currentZone = this.positionNotifier.enter(this); } else { - this.positionNotifier.updatePosition(this, { x, y }, { x: oldX, y: oldY }); + this.currentZone = this.positionNotifier.updatePosition(this, { x, y }, { x: oldX, y: oldY }); + } + } + + searchForNearbyUsers(): void { + if (!this.currentZone) return; + + for (const user of this.positionNotifier.getAllUsersInSquareAroundZone(this.currentZone)) { + if (user.group || this.isFull()) return; //we ignore users that are already in a group. + const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), this.getPosition()); + if (distance < this.groupRadius) { + this.join(user); + this.updatePosition(); + } } } @@ -126,7 +133,6 @@ export class Group implements Movable { * Usually used when there is only one user left. */ destroy(): void { - if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId); for (const user of this.users) { this.leave(user); } diff --git a/back/src/Model/PositionNotifier.ts b/back/src/Model/PositionNotifier.ts index 4f911637..2052f229 100644 --- a/back/src/Model/PositionNotifier.ts +++ b/back/src/Model/PositionNotifier.ts @@ -12,7 +12,7 @@ import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback, Zone } fr import { Movable } from "_Model/Movable"; import { PositionInterface } from "_Model/PositionInterface"; import { ZoneSocket } from "../RoomManager"; -import { User } from "_Model/User"; +import { User } from "../Model/User"; import { EmoteEventMessage } from "../Messages/generated/messages_pb"; interface ZoneDescriptor { @@ -20,6 +20,17 @@ interface ZoneDescriptor { j: number; } +export function* getNearbyDescriptorsMatrix(middleZoneDescriptor: ZoneDescriptor): Generator { + for (let n = 0; n < 9; n++) { + const i = middleZoneDescriptor.i + ((n % 3) - 1); + const j = middleZoneDescriptor.j + (Math.floor(n / 3) - 1); + + if (i >= 0 && j >= 0) { + yield { i, j }; + } + } +} + export class PositionNotifier { // TODO: we need a way to clean the zones if no one is in the zone and no one listening (to free memory!) @@ -41,14 +52,15 @@ export class PositionNotifier { }; } - public enter(thing: Movable): void { + public enter(thing: Movable): Zone { 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); + return zone; } - public updatePosition(thing: Movable, newPosition: PositionInterface, oldPosition: PositionInterface): void { + public updatePosition(thing: Movable, newPosition: PositionInterface, oldPosition: PositionInterface): Zone { // Did we change zone? const oldZoneDesc = this.getZoneDescriptorFromCoordinates(oldPosition.x, oldPosition.y); const newZoneDesc = this.getZoneDescriptorFromCoordinates(newPosition.x, newPosition.y); @@ -62,9 +74,11 @@ export class PositionNotifier { // Enter new zone newZone.enter(thing, oldZone, newPosition); + return newZone; } else { const zone = this.getZone(oldZoneDesc.i, oldZoneDesc.j); zone.move(thing, newPosition); + return zone; } } @@ -106,4 +120,16 @@ export class PositionNotifier { const zone = this.getZone(zoneDesc.i, zoneDesc.j); zone.emitEmoteEvent(emoteEventMessage); } + + public *getAllUsersInSquareAroundZone(zone: Zone): Generator { + const zoneDescriptor = this.getZoneDescriptorFromCoordinates(zone.x, zone.y); + for (const d of getNearbyDescriptorsMatrix(zoneDescriptor)) { + const zone = this.getZone(d.i, d.j); + for (const thing of zone.getThings()) { + if (thing instanceof User) { + yield thing; + } + } + } + } } diff --git a/back/src/Services/GaugeManager.ts b/back/src/Services/GaugeManager.ts index 6d2183d8..740692a8 100644 --- a/back/src/Services/GaugeManager.ts +++ b/back/src/Services/GaugeManager.ts @@ -52,15 +52,6 @@ class GaugeManager { this.nbClientsGauge.dec(); this.nbClientsPerRoomGauge.dec({ room: roomId }); } - - incNbGroupsPerRoomGauge(roomId: string): void { - this.nbGroupsPerRoomCounter.inc({ room: roomId }); - this.nbGroupsPerRoomGauge.inc({ room: roomId }); - } - - decNbGroupsPerRoomGauge(roomId: string): void { - this.nbGroupsPerRoomGauge.dec({ room: roomId }); - } } export const gaugeManager = new GaugeManager(); diff --git a/back/tests/getNearbyDescriptorsMatrixTest.ts b/back/tests/getNearbyDescriptorsMatrixTest.ts new file mode 100644 index 00000000..6c81db76 --- /dev/null +++ b/back/tests/getNearbyDescriptorsMatrixTest.ts @@ -0,0 +1,67 @@ +import "jasmine"; +import { getNearbyDescriptorsMatrix } from "../src/Model/PositionNotifier"; + +describe("getNearbyDescriptorsMatrix", () => { + it("should create a matrix of coordinates in a square around the parameter", () => { + const matrix = []; + for (const d of getNearbyDescriptorsMatrix({ i: 1, j: 1 })) { + matrix.push(d); + } + + expect(matrix).toEqual([ + { i: 0, j: 0 }, + { i: 1, j: 0 }, + { i: 2, j: 0 }, + { i: 0, j: 1 }, + { i: 1, j: 1 }, + { i: 2, j: 1 }, + { i: 0, j: 2 }, + { i: 1, j: 2 }, + { i: 2, j: 2 }, + ]); + }); + + it("should create a matrix of coordinates in a square around the parameter bis", () => { + const matrix = []; + for (const d of getNearbyDescriptorsMatrix({ i: 8, j: 3 })) { + matrix.push(d); + } + + expect(matrix).toEqual([ + { i: 7, j: 2 }, + { i: 8, j: 2 }, + { i: 9, j: 2 }, + { i: 7, j: 3 }, + { i: 8, j: 3 }, + { i: 9, j: 3 }, + { i: 7, j: 4 }, + { i: 8, j: 4 }, + { i: 9, j: 4 }, + ]); + }); + + it("should not create a matrix with negative coordinates", () => { + const matrix = []; + for (const d of getNearbyDescriptorsMatrix({ i: 0, j: 0 })) { + matrix.push(d); + } + + expect(matrix).toEqual([ + { i: 0, j: 0 }, + { i: 1, j: 0 }, + { i: 0, j: 1 }, + { i: 1, j: 1 }, + ]); + }); + + /*it("should not create a matrix with coordinates bigger than its dimmensions", () => { + const matrix = getNearbyDescriptorsMatrix({i: 4, j: 4}, 5, 5); + + expect(matrix).toEqual([ + {i: 3,j: 3}, + {i: 4,j: 3}, + {i: 3,j: 4}, + {i: 4,j: 4}, + ]) + });*/ +});