Merge branch 'develop' of github.com:thecodingmachine/workadventure into feat/follow-woka

This commit is contained in:
David Négrier 2021-12-23 16:04:59 +01:00
commit 368a115b4c
93 changed files with 4017 additions and 2405 deletions

View file

@ -2,7 +2,13 @@ import { PointInterface } from "./Websocket/PointInterface";
import { Group } from "./Group";
import { User, UserSocket } from "./User";
import { PositionInterface } from "_Model/PositionInterface";
import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback } from "_Model/Zone";
import {
EmoteCallback,
EntersCallback,
LeavesCallback,
MovesCallback,
PlayerDetailsUpdatedCallback,
} from "_Model/Zone";
import { PositionNotifier } from "./PositionNotifier";
import { Movable } from "_Model/Movable";
import {
@ -11,6 +17,7 @@ import {
EmoteEventMessage,
ErrorMessage,
JoinRoomMessage,
SetPlayerDetailsMessage,
SubToPusherRoomMessage,
VariableMessage,
VariableWithTagMessage,
@ -28,6 +35,7 @@ import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
import { LocalUrlError } from "../Services/LocalUrlError";
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
import { VariableError } from "../Services/VariableError";
import { isRoomRedirect } from "../Services/AdminApi/RoomRedirect";
export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: User, group: Group) => void;
@ -57,10 +65,19 @@ export class GameRoom {
onEnters: EntersCallback,
onMoves: MovesCallback,
onLeaves: LeavesCallback,
onEmote: EmoteCallback
onEmote: EmoteCallback,
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
) {
// A zone is 10 sprites wide.
this.positionNotifier = new PositionNotifier(320, 320, onEnters, onMoves, onLeaves, onEmote);
this.positionNotifier = new PositionNotifier(
320,
320,
onEnters,
onMoves,
onLeaves,
onEmote,
onPlayerDetailsUpdated
);
}
public static async create(
@ -72,7 +89,8 @@ export class GameRoom {
onEnters: EntersCallback,
onMoves: MovesCallback,
onLeaves: LeavesCallback,
onEmote: EmoteCallback
onEmote: EmoteCallback,
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
): Promise<GameRoom> {
const mapDetails = await GameRoom.getMapDetails(roomUrl);
@ -86,7 +104,8 @@ export class GameRoom {
onEnters,
onMoves,
onLeaves,
onEmote
onEmote,
onPlayerDetailsUpdated
);
return gameRoom;
@ -185,6 +204,14 @@ export class GameRoom {
this.updateUserGroup(user);
}
updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) {
if (playerDetailsMessage.getRemoveoutlinecolor()) {
user.outlineColor = undefined;
} else {
user.outlineColor = playerDetailsMessage.getOutlinecolor();
}
}
private updateUserGroup(user: User): void {
user.group?.updatePosition();
user.group?.searchForNearbyUsers();
@ -277,9 +304,7 @@ export class GameRoom {
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."
);
throw new Error(`Could not find group ${group.getId()} referenced by user ${user.id} in World.`);
}
this.groups.delete(group);
//todo: is the group garbage collected?
@ -480,9 +505,9 @@ export class GameRoom {
}
const result = await adminApi.fetchMapDetails(roomUrl);
if (!isMapDetailsData(result)) {
console.error("Unexpected room details received from server", result);
throw new Error("Unexpected room details received from server");
if (isRoomRedirect(result)) {
console.error("Unexpected room redirect received while querying map details", result);
throw new Error("Unexpected room redirect received while querying map details");
}
return result;
}

View file

@ -116,7 +116,7 @@ export class Group implements Movable {
leave(user: User): void {
const success = this.users.delete(user);
if (success === false) {
throw new Error("Could not find user " + user.id + " in the group " + this.id);
throw new Error(`Could not find user ${user.id} in the group ${this.id}`);
}
user.group = undefined;

View file

@ -8,12 +8,19 @@
* The PositionNotifier is important for performance. It allows us to send the position of players only to a restricted
* number of players around the current player.
*/
import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback, Zone } from "./Zone";
import {
EmoteCallback,
EntersCallback,
LeavesCallback,
MovesCallback,
PlayerDetailsUpdatedCallback,
Zone,
} from "./Zone";
import { Movable } from "_Model/Movable";
import { PositionInterface } from "_Model/PositionInterface";
import { ZoneSocket } from "../RoomManager";
import { User } from "../Model/User";
import { EmoteEventMessage } from "../Messages/generated/messages_pb";
import { EmoteEventMessage, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb";
interface ZoneDescriptor {
i: number;
@ -42,7 +49,8 @@ export class PositionNotifier {
private onUserEnters: EntersCallback,
private onUserMoves: MovesCallback,
private onUserLeaves: LeavesCallback,
private onEmote: EmoteCallback
private onEmote: EmoteCallback,
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
) {}
private getZoneDescriptorFromCoordinates(x: number, y: number): ZoneDescriptor {
@ -98,7 +106,15 @@ export class PositionNotifier {
let zone = this.zones[j][i];
if (zone === undefined) {
zone = new Zone(this.onUserEnters, this.onUserMoves, this.onUserLeaves, this.onEmote, i, j);
zone = new Zone(
this.onUserEnters,
this.onUserMoves,
this.onUserLeaves,
this.onEmote,
this.onPlayerDetailsUpdated,
i,
j
);
this.zones[j][i] = zone;
}
return zone;
@ -132,4 +148,11 @@ export class PositionNotifier {
}
}
}
public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) {
const position = user.getPosition();
const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y);
const zone = this.getZone(zoneDesc.i, zoneDesc.j);
zone.updatePlayerDetails(user, playerDetails);
}
}

View file

@ -11,6 +11,7 @@ import {
FollowConfirmationMessage,
PusherToBackMessage,
ServerToClientMessage,
SetPlayerDetailsMessage,
SubMessage,
} from "../Messages/generated/messages_pb";
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
@ -35,7 +36,8 @@ export class User implements Movable {
public readonly visitCardUrl: string | null,
public readonly name: string,
public readonly characterLayers: CharacterLayer[],
public readonly companion?: CompanionMessage
public readonly companion?: CompanionMessage,
private _outlineColor?: number | undefined
) {
this.listenedZones = new Set<Zone>();
@ -112,4 +114,17 @@ export class User implements Movable {
}, 100);
}
}
public set outlineColor(value: number | undefined) {
this._outlineColor = value;
const playerDetails = new SetPlayerDetailsMessage();
if (value === undefined) {
playerDetails.setRemoveoutlinecolor(true);
} else {
playerDetails.setOutlinecolor(value);
}
this.positionNotifier.updatePlayerDetails(this, playerDetails);
}
}

View file

@ -3,12 +3,20 @@ import { PositionInterface } from "_Model/PositionInterface";
import { Movable } from "./Movable";
import { Group } from "./Group";
import { ZoneSocket } from "../RoomManager";
import { EmoteEventMessage } from "../Messages/generated/messages_pb";
import {
EmoteEventMessage,
SetPlayerDetailsMessage,
PlayerDetailsUpdatedMessage,
} from "../Messages/generated/messages_pb";
export type EntersCallback = (thing: Movable, fromZone: Zone | null, listener: ZoneSocket) => void;
export type MovesCallback = (thing: Movable, position: PositionInterface, listener: ZoneSocket) => void;
export type LeavesCallback = (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => void;
export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void;
export type PlayerDetailsUpdatedCallback = (
playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage,
listener: ZoneSocket
) => void;
export class Zone {
private things: Set<Movable> = new Set<Movable>();
@ -19,6 +27,7 @@ export class Zone {
private onMoves: MovesCallback,
private onLeaves: LeavesCallback,
private onEmote: EmoteCallback,
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback,
public readonly x: number,
public readonly y: number
) {}
@ -30,21 +39,13 @@ export class Zone {
const result = this.things.delete(thing);
if (!result) {
if (thing instanceof User) {
throw new Error("Could not find user in zone " + thing.id);
throw new Error(`Could not find user in zone ${thing.id}`);
}
if (thing instanceof Group) {
throw new Error(
"Could not find group " +
thing.getId() +
" in zone (" +
this.x +
"," +
this.y +
"). Position of group: (" +
thing.getPosition().x +
"," +
thing.getPosition().y +
")"
`Could not find group ${thing.getId()} in zone (${this.x},${this.y}). Position of group: (${
thing.getPosition().x
},${thing.getPosition().y})`
);
}
}
@ -106,4 +107,14 @@ export class Zone {
this.onEmote(emoteEventMessage, listener);
}
}
public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) {
const playerDetailsUpdatedMessage = new PlayerDetailsUpdatedMessage();
playerDetailsUpdatedMessage.setUserid(user.id);
playerDetailsUpdatedMessage.setDetails(playerDetails);
for (const listener of this.listeners) {
this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener);
}
}
}