Merge pull request #1509 from thecodingmachine/fixGroupCreation

FIX: if a conversion group move to another user, this user will be added to the group
This commit is contained in:
Kharhamel 2021-10-08 14:25:21 +02:00 committed by GitHub
commit 72583a58d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 25 deletions

View File

@ -181,6 +181,7 @@ export class GameRoom {
private updateUserGroup(user: User): void { private updateUserGroup(user: User): void {
user.group?.updatePosition(); user.group?.updatePosition();
user.group?.searchForNearbyUsers();
if (user.silent) { if (user.silent) {
return; return;
@ -206,6 +207,7 @@ export class GameRoom {
const group: Group = new Group( const group: Group = new Group(
this.roomUrl, this.roomUrl,
[user, closestUser], [user, closestUser],
this.groupRadius,
this.connectCallback, this.connectCallback,
this.disconnectCallback, this.disconnectCallback,
this.positionNotifier this.positionNotifier

View File

@ -1,10 +1,10 @@
import { ConnectCallback, DisconnectCallback } from "./GameRoom"; import { ConnectCallback, DisconnectCallback, GameRoom } from "./GameRoom";
import { User } from "./User"; import { User } from "./User";
import { PositionInterface } from "_Model/PositionInterface"; import { PositionInterface } from "_Model/PositionInterface";
import { Movable } from "_Model/Movable"; import { Movable } from "_Model/Movable";
import { PositionNotifier } from "_Model/PositionNotifier"; import { PositionNotifier } from "_Model/PositionNotifier";
import { gaugeManager } from "../Services/GaugeManager";
import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable"; import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable";
import type { Zone } from "../Model/Zone";
export class Group implements Movable { export class Group implements Movable {
private static nextId: number = 1; private static nextId: number = 1;
@ -13,13 +13,14 @@ export class Group implements Movable {
private users: Set<User>; private users: Set<User>;
private x!: number; private x!: number;
private y!: number; private y!: number;
private hasEditedGauge: boolean = false;
private wasDestroyed: boolean = false; private wasDestroyed: boolean = false;
private roomId: string; private roomId: string;
private currentZone: Zone | null = null;
constructor( constructor(
roomId: string, roomId: string,
users: User[], users: User[],
private groupRadius: number,
private connectCallback: ConnectCallback, private connectCallback: ConnectCallback,
private disconnectCallback: DisconnectCallback, private disconnectCallback: DisconnectCallback,
private positionNotifier: PositionNotifier private positionNotifier: PositionNotifier
@ -28,13 +29,6 @@ export class Group implements Movable {
this.users = new Set<User>(); this.users = new Set<User>();
this.id = Group.nextId; this.id = Group.nextId;
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) => { users.forEach((user: User) => {
this.join(user); this.join(user);
@ -85,9 +79,22 @@ export class Group implements Movable {
this.y = y; this.y = y;
if (oldX === undefined) { if (oldX === undefined) {
this.positionNotifier.enter(this); this.currentZone = this.positionNotifier.enter(this);
} else { } 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. * Usually used when there is only one user left.
*/ */
destroy(): void { destroy(): void {
if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId);
for (const user of this.users) { for (const user of this.users) {
this.leave(user); this.leave(user);
} }

View File

@ -12,7 +12,7 @@ import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback, Zone } fr
import { Movable } from "_Model/Movable"; import { Movable } from "_Model/Movable";
import { PositionInterface } from "_Model/PositionInterface"; import { PositionInterface } from "_Model/PositionInterface";
import { ZoneSocket } from "../RoomManager"; import { ZoneSocket } from "../RoomManager";
import { User } from "_Model/User"; import { User } from "../Model/User";
import { EmoteEventMessage } from "../Messages/generated/messages_pb"; import { EmoteEventMessage } from "../Messages/generated/messages_pb";
interface ZoneDescriptor { interface ZoneDescriptor {
@ -20,6 +20,17 @@ interface ZoneDescriptor {
j: number; j: number;
} }
export function* getNearbyDescriptorsMatrix(middleZoneDescriptor: ZoneDescriptor): Generator<ZoneDescriptor> {
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 { 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!) // 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 position = thing.getPosition();
const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y); const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y);
const zone = this.getZone(zoneDesc.i, zoneDesc.j); const zone = this.getZone(zoneDesc.i, zoneDesc.j);
zone.enter(thing, null, position); 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? // Did we change zone?
const oldZoneDesc = this.getZoneDescriptorFromCoordinates(oldPosition.x, oldPosition.y); const oldZoneDesc = this.getZoneDescriptorFromCoordinates(oldPosition.x, oldPosition.y);
const newZoneDesc = this.getZoneDescriptorFromCoordinates(newPosition.x, newPosition.y); const newZoneDesc = this.getZoneDescriptorFromCoordinates(newPosition.x, newPosition.y);
@ -62,9 +74,11 @@ export class PositionNotifier {
// Enter new zone // Enter new zone
newZone.enter(thing, oldZone, newPosition); newZone.enter(thing, oldZone, newPosition);
return newZone;
} else { } else {
const zone = this.getZone(oldZoneDesc.i, oldZoneDesc.j); const zone = this.getZone(oldZoneDesc.i, oldZoneDesc.j);
zone.move(thing, newPosition); zone.move(thing, newPosition);
return zone;
} }
} }
@ -106,4 +120,16 @@ export class PositionNotifier {
const zone = this.getZone(zoneDesc.i, zoneDesc.j); const zone = this.getZone(zoneDesc.i, zoneDesc.j);
zone.emitEmoteEvent(emoteEventMessage); zone.emitEmoteEvent(emoteEventMessage);
} }
public *getAllUsersInSquareAroundZone(zone: Zone): Generator<User> {
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;
}
}
}
}
} }

View File

@ -52,15 +52,6 @@ class GaugeManager {
this.nbClientsGauge.dec(); this.nbClientsGauge.dec();
this.nbClientsPerRoomGauge.dec({ room: roomId }); 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(); export const gaugeManager = new GaugeManager();

View File

@ -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},
])
});*/
});