Plugin PositionNotifier into the main application.

This commit is contained in:
David Négrier 2020-09-15 16:21:41 +02:00
parent f8d462b0d7
commit d24ec0bd75
10 changed files with 170 additions and 62 deletions

View file

@ -34,10 +34,14 @@ export class PositionNotifier {
}
}
public setViewport(user: UserInterface, viewport: ViewportInterface): void {
/**
* Sets the viewport coordinates.
* Returns the list of new users to add
*/
public setViewport(user: UserInterface, viewport: ViewportInterface): UserInterface[] {
if (viewport.left > viewport.right || viewport.top > viewport.bottom) {
console.warn('Invalid viewport received: ', viewport);
return;
return [];
}
const oldZones = user.listenedZones;
@ -55,12 +59,17 @@ export class PositionNotifier {
const addedZones = [...newZones].filter(x => !oldZones.has(x));
const removedZones = [...oldZones].filter(x => !newZones.has(x));
let users: UserInterface[] = [];
for (const zone of addedZones) {
zone.startListening(user);
users = users.concat(Array.from(zone.getPlayers()))
}
for (const zone of removedZones) {
zone.stopListening(user);
}
return users;
}
public updatePosition(user: UserInterface, userPosition: PointInterface): void {
@ -87,6 +96,11 @@ export class PositionNotifier {
const oldZoneDesc = this.getZoneDescriptorFromCoordinates(user.position.x, user.position.y);
const oldZone = this.getZone(oldZoneDesc.i, oldZoneDesc.j);
oldZone.leave(user, null);
// Also, let's stop listening on viewports
for (const zone of user.listenedZones) {
zone.stopListening(user);
}
}
private getZone(i: number, j: number): Zone {

View file

@ -1,9 +1,11 @@
import * as tg from "generic-type-guard";
import {isPointInterface} from "./PointInterface";
import {isViewport} from "./ViewportMessage";
export const isJoinRoomMessageInterface =
new tg.IsInterface().withProperties({
roomId: tg.isString,
position: isPointInterface,
viewport: isViewport
}).get();
export type JoinRoomMessageInterface = tg.GuardedType<typeof isJoinRoomMessageInterface>;

View file

@ -6,7 +6,9 @@ import {UserInterface} from "./UserInterface";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
import {PositionInterface} from "_Model/PositionInterface";
import {Identificable} from "_Model/Websocket/Identificable";
import {Zone} from "_Model/Zone";
import {UserEntersCallback, UserLeavesCallback, UserMovesCallback, Zone} from "_Model/Zone";
import {PositionNotifier} from "./PositionNotifier";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
export type ConnectCallback = (user: string, group: Group) => void;
export type DisconnectCallback = (user: string, group: Group) => void;
@ -28,12 +30,17 @@ export class World {
private readonly groupUpdatedCallback: GroupUpdatedCallback;
private readonly groupDeletedCallback: GroupDeletedCallback;
private readonly positionNotifier: PositionNotifier;
constructor(connectCallback: ConnectCallback,
disconnectCallback: DisconnectCallback,
minDistance: number,
groupRadius: number,
groupUpdatedCallback: GroupUpdatedCallback,
groupDeletedCallback: GroupDeletedCallback)
groupDeletedCallback: GroupDeletedCallback,
onUserEnters: UserEntersCallback,
onUserMoves: UserMovesCallback,
onUserLeaves: UserLeavesCallback)
{
this.users = new Map<string, UserInterface>();
this.groups = new Set<Group>();
@ -43,6 +50,8 @@ export class World {
this.groupRadius = groupRadius;
this.groupUpdatedCallback = groupUpdatedCallback;
this.groupDeletedCallback = groupDeletedCallback;
// A zone is 10 sprites wide.
this.positionNotifier = new PositionNotifier(320, 320, onUserEnters, onUserMoves, onUserLeaves);
}
public getGroups(): Group[] {
@ -73,6 +82,10 @@ export class World {
this.leaveGroup(userObj);
}
this.users.delete(user.userId);
if (userObj !== undefined) {
this.positionNotifier.leave(userObj);
}
}
public isEmpty(): boolean {
@ -85,6 +98,8 @@ export class World {
return;
}
this.positionNotifier.updatePosition(user, userPosition);
user.position = userPosition;
if (user.silent) {
@ -318,4 +333,12 @@ export class World {
}
return 0;
}*/
setViewport(socket : Identificable, viewport: ViewportInterface): UserInterface[] {
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.');
return [];
}
return this.positionNotifier.setViewport(user, viewport);
}
}

View file

@ -2,9 +2,9 @@ import {UserInterface} from "./UserInterface";
import {PointInterface} from "_Model/Websocket/PointInterface";
import {PositionInterface} from "_Model/PositionInterface";
export type UserEntersCallback = (user: UserInterface) => void;
export type UserMovesCallback = (user: UserInterface, position: PointInterface) => void;
export type UserLeavesCallback = (user: UserInterface) => void;
export type UserEntersCallback = (user: UserInterface, listener: UserInterface) => void;
export type UserMovesCallback = (user: UserInterface, position: PointInterface, listener: UserInterface) => void;
export type UserLeavesCallback = (user: UserInterface, listener: UserInterface) => void;
export class Zone {
private players: Set<UserInterface> = new Set<UserInterface>();
@ -27,7 +27,7 @@ export class Zone {
private notifyUserLeft(user: UserInterface, newZone: Zone|null) {
for (const listener of this.listeners) {
if (listener !== user && (newZone === null || !listener.listenedZones.has(newZone))) {
this.onUserLeaves(user);
this.onUserLeaves(user, listener);
}
}
}
@ -46,40 +46,51 @@ export class Zone {
continue;
}
if (oldZone === null || !listener.listenedZones.has(oldZone)) {
this.onUserEnters(user);
this.onUserEnters(user, listener);
} else {
this.onUserMoves(user, position);
this.onUserMoves(user, position, listener);
}
}
}
public move(user: UserInterface, position: PointInterface) {
if (!this.players.has(user)) {
this.players.add(user);
const foo = this.players;
this.notifyUserEnter(user, null, position);
return;
}
for (const listener of this.listeners) {
if (listener !== user) {
this.onUserMoves(user,position);
this.onUserMoves(user,position, listener);
}
}
}
public startListening(user: UserInterface): void {
public startListening(listener: UserInterface): void {
for (const player of this.players) {
if (player !== user) {
this.onUserEnters(user);
if (player !== listener) {
this.onUserEnters(player, listener);
}
}
this.listeners.add(user);
user.listenedZones.add(this);
this.listeners.add(listener);
listener.listenedZones.add(this);
}
public stopListening(user: UserInterface): void {
public stopListening(listener: UserInterface): void {
for (const player of this.players) {
if (player !== user) {
this.onUserLeaves(user);
if (player !== listener) {
this.onUserLeaves(player, listener);
}
}
this.listeners.delete(user);
user.listenedZones.delete(this);
this.listeners.delete(listener);
listener.listenedZones.delete(this);
}
public getPlayers(): Set<UserInterface> {
return this.players;
}
}