Making groups part of zones

This commit is contained in:
David Négrier 2020-09-16 16:06:43 +02:00
parent 3ca2a5bf68
commit f5f9dcac04
12 changed files with 245 additions and 188 deletions

View file

@ -2,27 +2,28 @@ import {MessageUserPosition, Point} from "./Websocket/MessageUserPosition";
import {PointInterface} from "./Websocket/PointInterface";
import {Group} from "./Group";
import {Distance} from "./Distance";
import {UserInterface} from "./UserInterface";
import {User} from "./User";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
import {PositionInterface} from "_Model/PositionInterface";
import {Identificable} from "_Model/Websocket/Identificable";
import {UserEntersCallback, UserLeavesCallback, UserMovesCallback, Zone} from "_Model/Zone";
import {EntersCallback, LeavesCallback, MovesCallback, Zone} from "_Model/Zone";
import {PositionNotifier} from "./PositionNotifier";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {Movable} from "_Model/Movable";
export type ConnectCallback = (user: string, group: Group) => void;
export type DisconnectCallback = (user: string, group: Group) => void;
// callback called when a group is created or moved or changes users
export type GroupUpdatedCallback = (group: Group) => void;
export type GroupDeletedCallback = (uuid: string, lastUser: UserInterface) => void;
export type GroupDeletedCallback = (uuid: string, lastUser: User) => void;
export class World {
private readonly minDistance: number;
private readonly groupRadius: number;
// Users, sorted by ID
private readonly users: Map<string, UserInterface>;
private readonly users: Map<string, User>;
private readonly groups: Set<Group>;
private readonly connectCallback: ConnectCallback;
@ -40,11 +41,11 @@ export class World {
groupRadius: number,
groupUpdatedCallback: GroupUpdatedCallback,
groupDeletedCallback: GroupDeletedCallback,
onUserEnters: UserEntersCallback,
onUserMoves: UserMovesCallback,
onUserLeaves: UserLeavesCallback)
onEnters: EntersCallback,
onMoves: MovesCallback,
onLeaves: LeavesCallback)
{
this.users = new Map<string, UserInterface>();
this.users = new Map<string, User>();
this.groups = new Set<Group>();
this.connectCallback = connectCallback;
this.disconnectCallback = disconnectCallback;
@ -53,24 +54,19 @@ export class World {
this.groupUpdatedCallback = groupUpdatedCallback;
this.groupDeletedCallback = groupDeletedCallback;
// A zone is 10 sprites wide.
this.positionNotifier = new PositionNotifier(320, 320, onUserEnters, onUserMoves, onUserLeaves);
this.positionNotifier = new PositionNotifier(320, 320, onEnters, onMoves, onLeaves);
}
public getGroups(): Group[] {
return Array.from(this.groups.values());
}
public getUsers(): Map<string, UserInterface> {
public getUsers(): Map<string, User> {
return this.users;
}
public join(socket : Identificable, userPosition: PointInterface): void {
this.users.set(socket.userId, {
id: socket.userId,
position: userPosition,
silent: false, // FIXME: silent should be set at the correct value when joining a room.
listenedZones: new Set<Zone>()
});
this.users.set(socket.userId, new User(socket.userId, userPosition, false));
// Let's call update position to trigger the join / leave room
this.updatePosition(socket, userPosition);
}
@ -87,6 +83,7 @@ export class World {
if (userObj !== undefined) {
this.positionNotifier.leave(userObj);
this.positionNotifier.removeViewport(userObj);
}
}
@ -100,7 +97,9 @@ export class World {
return;
}
this.positionNotifier.updatePosition(user, userPosition);
this.positionNotifier.updatePosition(user, userPosition, user.position);
const oldGroupPosition = user.group?.getPosition();
user.position = userPosition;
@ -108,17 +107,17 @@ export class World {
return;
}
if (typeof user.group === 'undefined') {
if (user.group === undefined) {
// If the user is not part of a group:
// should he join a group?
const closestItem: UserInterface|Group|null = this.searchClosestAvailableUserOrGroup(user);
const closestItem: User|Group|null = this.searchClosestAvailableUserOrGroup(user);
if (closestItem !== null) {
if (closestItem instanceof Group) {
// Let's join the group!
closestItem.join(user);
} else {
const closestUser : UserInterface = closestItem;
const closestUser : User = closestItem;
const group: Group = new Group([
user,
closestUser
@ -138,7 +137,8 @@ export class World {
// At the very end, if the user is part of a group, let's call the callback to update group position
if (typeof user.group !== 'undefined') {
this.groupUpdatedCallback(user.group);
this.positionNotifier.updatePosition(user.group, user.group.getPosition(), oldGroupPosition ? oldGroupPosition : user.group.getPosition());
//this.groupUpdatedCallback(user.group);
}
}
@ -167,21 +167,23 @@ export class World {
*
* @param user
*/
private leaveGroup(user: UserInterface): void {
private leaveGroup(user: User): void {
const group = user.group;
if (typeof group === 'undefined') {
throw new Error("The user is part of no group");
}
group.leave(user);
if (group.isEmpty()) {
this.groupDeletedCallback(group.getId(), user);
//this.groupDeletedCallback(group.getId(), user);
this.positionNotifier.leave(group);
group.destroy();
if (!this.groups.has(group)) {
throw new Error("Could not find group "+group.getId()+" referenced by user "+user.id+" in World.");
}
this.groups.delete(group);
} else {
this.groupUpdatedCallback(group);
this.positionNotifier.updatePosition(group, group.getPosition(), group.getPosition());
//this.groupUpdatedCallback(group);
}
}
@ -193,10 +195,10 @@ export class World {
* OR
* - close enough to a group (distance <= groupRadius)
*/
private searchClosestAvailableUserOrGroup(user: UserInterface): UserInterface|Group|null
private searchClosestAvailableUserOrGroup(user: User): User|Group|null
{
let minimumDistanceFound: number = Math.max(this.minDistance, this.groupRadius);
let matchingItem: UserInterface | Group | null = null;
let matchingItem: User | Group | null = null;
this.users.forEach((currentUser, userId) => {
// Let's only check users that are not part of a group
if (typeof currentUser.group !== 'undefined') {
@ -265,7 +267,7 @@ export class World {
return matchingItem;
}
public static computeDistance(user1: UserInterface, user2: UserInterface): number
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));
}
@ -343,7 +345,7 @@ export class World {
}
return 0;
}*/
setViewport(socket : Identificable, viewport: ViewportInterface): UserInterface[] {
setViewport(socket : Identificable, viewport: ViewportInterface): Movable[] {
const user = this.users.get(socket.userId);
if(typeof user === 'undefined') {
console.warn('In setViewport, could not find user with ID "'+socket.userId+'" in world.');