Merge pull request #1662 from thecodingmachine/feat/outline_api
Adding an API to control players outline
This commit is contained in:
commit
565ccb10c8
@ -2,7 +2,13 @@ import { PointInterface } from "./Websocket/PointInterface";
|
|||||||
import { Group } from "./Group";
|
import { Group } from "./Group";
|
||||||
import { User, UserSocket } from "./User";
|
import { User, UserSocket } from "./User";
|
||||||
import { PositionInterface } from "_Model/PositionInterface";
|
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 { PositionNotifier } from "./PositionNotifier";
|
||||||
import { Movable } from "_Model/Movable";
|
import { Movable } from "_Model/Movable";
|
||||||
import {
|
import {
|
||||||
@ -11,6 +17,7 @@ import {
|
|||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
VariableWithTagMessage,
|
VariableWithTagMessage,
|
||||||
@ -56,10 +63,19 @@ export class GameRoom {
|
|||||||
onEnters: EntersCallback,
|
onEnters: EntersCallback,
|
||||||
onMoves: MovesCallback,
|
onMoves: MovesCallback,
|
||||||
onLeaves: LeavesCallback,
|
onLeaves: LeavesCallback,
|
||||||
onEmote: EmoteCallback
|
onEmote: EmoteCallback,
|
||||||
|
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||||
) {
|
) {
|
||||||
// A zone is 10 sprites wide.
|
// 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(
|
public static async create(
|
||||||
@ -71,7 +87,8 @@ export class GameRoom {
|
|||||||
onEnters: EntersCallback,
|
onEnters: EntersCallback,
|
||||||
onMoves: MovesCallback,
|
onMoves: MovesCallback,
|
||||||
onLeaves: LeavesCallback,
|
onLeaves: LeavesCallback,
|
||||||
onEmote: EmoteCallback
|
onEmote: EmoteCallback,
|
||||||
|
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||||
): Promise<GameRoom> {
|
): Promise<GameRoom> {
|
||||||
const mapDetails = await GameRoom.getMapDetails(roomUrl);
|
const mapDetails = await GameRoom.getMapDetails(roomUrl);
|
||||||
|
|
||||||
@ -85,7 +102,8 @@ export class GameRoom {
|
|||||||
onEnters,
|
onEnters,
|
||||||
onMoves,
|
onMoves,
|
||||||
onLeaves,
|
onLeaves,
|
||||||
onEmote
|
onEmote,
|
||||||
|
onPlayerDetailsUpdated
|
||||||
);
|
);
|
||||||
|
|
||||||
return gameRoom;
|
return gameRoom;
|
||||||
@ -180,6 +198,14 @@ export class GameRoom {
|
|||||||
this.updateUserGroup(user);
|
this.updateUserGroup(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) {
|
||||||
|
if (playerDetailsMessage.getRemoveoutlinecolor()) {
|
||||||
|
user.outlineColor = undefined;
|
||||||
|
} else {
|
||||||
|
user.outlineColor = playerDetailsMessage.getOutlinecolor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateUserGroup(user: User): void {
|
private updateUserGroup(user: User): void {
|
||||||
user.group?.updatePosition();
|
user.group?.updatePosition();
|
||||||
user.group?.searchForNearbyUsers();
|
user.group?.searchForNearbyUsers();
|
||||||
|
@ -8,12 +8,19 @@
|
|||||||
* The PositionNotifier is important for performance. It allows us to send the position of players only to a restricted
|
* 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.
|
* 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 { 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, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb";
|
||||||
|
|
||||||
interface ZoneDescriptor {
|
interface ZoneDescriptor {
|
||||||
i: number;
|
i: number;
|
||||||
@ -42,7 +49,8 @@ export class PositionNotifier {
|
|||||||
private onUserEnters: EntersCallback,
|
private onUserEnters: EntersCallback,
|
||||||
private onUserMoves: MovesCallback,
|
private onUserMoves: MovesCallback,
|
||||||
private onUserLeaves: LeavesCallback,
|
private onUserLeaves: LeavesCallback,
|
||||||
private onEmote: EmoteCallback
|
private onEmote: EmoteCallback,
|
||||||
|
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private getZoneDescriptorFromCoordinates(x: number, y: number): ZoneDescriptor {
|
private getZoneDescriptorFromCoordinates(x: number, y: number): ZoneDescriptor {
|
||||||
@ -98,7 +106,15 @@ export class PositionNotifier {
|
|||||||
|
|
||||||
let zone = this.zones[j][i];
|
let zone = this.zones[j][i];
|
||||||
if (zone === undefined) {
|
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;
|
this.zones[j][i] = zone;
|
||||||
}
|
}
|
||||||
return 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
CompanionMessage,
|
CompanionMessage,
|
||||||
PusherToBackMessage,
|
PusherToBackMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
SubMessage,
|
SubMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
|
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
|
||||||
@ -31,7 +32,8 @@ export class User implements Movable {
|
|||||||
public readonly visitCardUrl: string | null,
|
public readonly visitCardUrl: string | null,
|
||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
public readonly characterLayers: CharacterLayer[],
|
public readonly characterLayers: CharacterLayer[],
|
||||||
public readonly companion?: CompanionMessage
|
public readonly companion?: CompanionMessage,
|
||||||
|
private _outlineColor?: number | undefined
|
||||||
) {
|
) {
|
||||||
this.listenedZones = new Set<Zone>();
|
this.listenedZones = new Set<Zone>();
|
||||||
|
|
||||||
@ -69,4 +71,17 @@ export class User implements Movable {
|
|||||||
}, 100);
|
}, 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,20 @@ import { PositionInterface } from "_Model/PositionInterface";
|
|||||||
import { Movable } from "./Movable";
|
import { Movable } from "./Movable";
|
||||||
import { Group } from "./Group";
|
import { Group } from "./Group";
|
||||||
import { ZoneSocket } from "../RoomManager";
|
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 EntersCallback = (thing: Movable, fromZone: Zone | null, listener: ZoneSocket) => void;
|
||||||
export type MovesCallback = (thing: Movable, position: PositionInterface, 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 LeavesCallback = (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => void;
|
||||||
export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void;
|
export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void;
|
||||||
|
export type PlayerDetailsUpdatedCallback = (
|
||||||
|
playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage,
|
||||||
|
listener: ZoneSocket
|
||||||
|
) => void;
|
||||||
|
|
||||||
export class Zone {
|
export class Zone {
|
||||||
private things: Set<Movable> = new Set<Movable>();
|
private things: Set<Movable> = new Set<Movable>();
|
||||||
@ -19,6 +27,7 @@ export class Zone {
|
|||||||
private onMoves: MovesCallback,
|
private onMoves: MovesCallback,
|
||||||
private onLeaves: LeavesCallback,
|
private onLeaves: LeavesCallback,
|
||||||
private onEmote: EmoteCallback,
|
private onEmote: EmoteCallback,
|
||||||
|
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback,
|
||||||
public readonly x: number,
|
public readonly x: number,
|
||||||
public readonly y: number
|
public readonly y: number
|
||||||
) {}
|
) {}
|
||||||
@ -106,4 +115,14 @@ export class Zone {
|
|||||||
this.onEmote(emoteEventMessage, listener);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
AdminPusherToBackMessage,
|
AdminPusherToBackMessage,
|
||||||
AdminRoomMessage,
|
AdminRoomMessage,
|
||||||
BanMessage,
|
BanMessage,
|
||||||
|
BanUserMessage,
|
||||||
BatchToPusherMessage,
|
BatchToPusherMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
@ -16,7 +17,9 @@ import {
|
|||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
RefreshRoomPromptMessage,
|
RefreshRoomPromptMessage,
|
||||||
RoomMessage,
|
RoomMessage,
|
||||||
|
SendUserMessage,
|
||||||
ServerToAdminClientMessage,
|
ServerToAdminClientMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
SilentMessage,
|
SilentMessage,
|
||||||
UserMovesMessage,
|
UserMovesMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
@ -118,14 +121,17 @@ const roomManager: IRoomManagerServer = {
|
|||||||
);
|
);
|
||||||
} else if (message.hasSendusermessage()) {
|
} else if (message.hasSendusermessage()) {
|
||||||
const sendUserMessage = message.getSendusermessage();
|
const sendUserMessage = message.getSendusermessage();
|
||||||
if (sendUserMessage !== undefined) {
|
socketManager.handleSendUserMessage(user, sendUserMessage as SendUserMessage);
|
||||||
socketManager.handlerSendUserMessage(user, sendUserMessage);
|
|
||||||
}
|
|
||||||
} else if (message.hasBanusermessage()) {
|
} else if (message.hasBanusermessage()) {
|
||||||
const banUserMessage = message.getBanusermessage();
|
const banUserMessage = message.getBanusermessage();
|
||||||
if (banUserMessage !== undefined) {
|
socketManager.handlerBanUserMessage(room, user, banUserMessage as BanUserMessage);
|
||||||
socketManager.handlerBanUserMessage(room, user, banUserMessage);
|
} else if (message.hasSetplayerdetailsmessage()) {
|
||||||
}
|
const setPlayerDetailsMessage = message.getSetplayerdetailsmessage();
|
||||||
|
socketManager.handleSetPlayerDetails(
|
||||||
|
room,
|
||||||
|
user,
|
||||||
|
setPlayerDetailsMessage as SetPlayerDetailsMessage
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unhandled message type");
|
throw new Error("Unhandled message type");
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@ import {
|
|||||||
VariableMessage,
|
VariableMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
|
PlayerDetailsUpdatedMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { User, UserSocket } from "../Model/User";
|
import { User, UserSocket } from "../Model/User";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
@ -151,20 +153,9 @@ export class SocketManager {
|
|||||||
//room.setViewport(client, client.viewport);
|
//room.setViewport(client, client.viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Useless now, will be useful again if we allow editing details in game
|
handleSetPlayerDetails(room: GameRoom, user: User, playerDetailsMessage: SetPlayerDetailsMessage) {
|
||||||
/*handleSetPlayerDetails(client: UserSocket, playerDetailsMessage: SetPlayerDetailsMessage) {
|
room.updatePlayerDetails(user, playerDetailsMessage);
|
||||||
const playerDetails = {
|
}
|
||||||
name: playerDetailsMessage.getName(),
|
|
||||||
characterLayers: playerDetailsMessage.getCharacterlayersList()
|
|
||||||
};
|
|
||||||
//console.log(SocketIoEvent.SET_PLAYER_DETAILS, playerDetails);
|
|
||||||
if (!isSetPlayerDetailsMessage(playerDetails)) {
|
|
||||||
emitError(client, 'Invalid SET_PLAYER_DETAILS message received: ');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.name = playerDetails.name;
|
|
||||||
client.characterLayers = SocketManager.mergeCharacterLayersAndCustomTextures(playerDetails.characterLayers, client.textures);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
handleSilentMessage(room: GameRoom, user: User, silentMessage: SilentMessage) {
|
handleSilentMessage(room: GameRoom, user: User, silentMessage: SilentMessage) {
|
||||||
room.setSilent(user, silentMessage.getSilent());
|
room.setSilent(user, silentMessage.getSilent());
|
||||||
@ -282,7 +273,9 @@ export class SocketManager {
|
|||||||
(thing: Movable, newZone: Zone | null, listener: ZoneSocket) =>
|
(thing: Movable, newZone: Zone | null, listener: ZoneSocket) =>
|
||||||
this.onClientLeave(thing, newZone, listener),
|
this.onClientLeave(thing, newZone, listener),
|
||||||
(emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) =>
|
(emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) =>
|
||||||
this.onEmote(emoteEventMessage, listener)
|
this.onEmote(emoteEventMessage, listener),
|
||||||
|
(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ZoneSocket) =>
|
||||||
|
this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener)
|
||||||
)
|
)
|
||||||
.then((gameRoom) => {
|
.then((gameRoom) => {
|
||||||
gaugeManager.incNbRoomGauge();
|
gaugeManager.incNbRoomGauge();
|
||||||
@ -329,6 +322,12 @@ export class SocketManager {
|
|||||||
userJoinedZoneMessage.setVisitcardurl(thing.visitCardUrl);
|
userJoinedZoneMessage.setVisitcardurl(thing.visitCardUrl);
|
||||||
}
|
}
|
||||||
userJoinedZoneMessage.setCompanion(thing.companion);
|
userJoinedZoneMessage.setCompanion(thing.companion);
|
||||||
|
if (thing.outlineColor === undefined) {
|
||||||
|
userJoinedZoneMessage.setHasoutline(false);
|
||||||
|
} else {
|
||||||
|
userJoinedZoneMessage.setHasoutline(true);
|
||||||
|
userJoinedZoneMessage.setOutlinecolor(thing.outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
const subMessage = new SubToPusherMessage();
|
const subMessage = new SubToPusherMessage();
|
||||||
subMessage.setUserjoinedzonemessage(userJoinedZoneMessage);
|
subMessage.setUserjoinedzonemessage(userJoinedZoneMessage);
|
||||||
@ -378,6 +377,13 @@ export class SocketManager {
|
|||||||
emitZoneMessage(subMessage, client);
|
emitZoneMessage(subMessage, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, client: ZoneSocket) {
|
||||||
|
const subMessage = new SubToPusherMessage();
|
||||||
|
subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage);
|
||||||
|
|
||||||
|
emitZoneMessage(subMessage, client);
|
||||||
|
}
|
||||||
|
|
||||||
private emitCreateUpdateGroupEvent(client: ZoneSocket, fromZone: Zone | null, group: Group): void {
|
private emitCreateUpdateGroupEvent(client: ZoneSocket, fromZone: Zone | null, group: Group): void {
|
||||||
const position = group.getPosition();
|
const position = group.getPosition();
|
||||||
const pointMessage = new PointMessage();
|
const pointMessage = new PointMessage();
|
||||||
@ -572,7 +578,7 @@ export class SocketManager {
|
|||||||
user.socket.write(serverToClientMessage);
|
user.socket.write(serverToClientMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public handlerSendUserMessage(user: User, sendUserMessageToSend: SendUserMessage) {
|
public handleSendUserMessage(user: User, sendUserMessageToSend: SendUserMessage) {
|
||||||
const sendUserMessage = new SendUserMessage();
|
const sendUserMessage = new SendUserMessage();
|
||||||
sendUserMessage.setMessage(sendUserMessageToSend.getMessage());
|
sendUserMessage.setMessage(sendUserMessageToSend.getMessage());
|
||||||
sendUserMessage.setType(sendUserMessageToSend.getType());
|
sendUserMessage.setType(sendUserMessageToSend.getType());
|
||||||
|
@ -51,7 +51,8 @@ describe("GameRoom", () => {
|
|||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
emote
|
emote,
|
||||||
|
() => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
@ -86,7 +87,8 @@ describe("GameRoom", () => {
|
|||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
emote
|
emote,
|
||||||
|
() => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
@ -125,7 +127,8 @@ describe("GameRoom", () => {
|
|||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
() => {},
|
() => {},
|
||||||
emote
|
emote,
|
||||||
|
() => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
const user1 = world.join(createMockUserSocket(), createJoinRoomMessage("1", 100, 100));
|
||||||
|
@ -19,7 +19,8 @@ describe("PositionNotifier", () => {
|
|||||||
moveTriggered = true;
|
moveTriggered = true;
|
||||||
}, (thing: Movable) => {
|
}, (thing: Movable) => {
|
||||||
leaveTriggered = true;
|
leaveTriggered = true;
|
||||||
}, () => {});
|
}, () => {},
|
||||||
|
() => {});
|
||||||
|
|
||||||
const user1 = new User(1, 'test', '10.0.0.2', {
|
const user1 = new User(1, 'test', '10.0.0.2', {
|
||||||
x: 500,
|
x: 500,
|
||||||
@ -94,7 +95,8 @@ describe("PositionNotifier", () => {
|
|||||||
moveTriggered = true;
|
moveTriggered = true;
|
||||||
}, (thing: Movable) => {
|
}, (thing: Movable) => {
|
||||||
leaveTriggered = true;
|
leaveTriggered = true;
|
||||||
}, () => {});
|
}, () => {},
|
||||||
|
() => {});
|
||||||
|
|
||||||
const user1 = new User(1, 'test', '10.0.0.2', {
|
const user1 = new User(1, 'test', '10.0.0.2', {
|
||||||
x: 500,
|
x: 500,
|
||||||
|
@ -106,3 +106,25 @@ Example :
|
|||||||
```javascript
|
```javascript
|
||||||
WA.player.onPlayerMove(console.log);
|
WA.player.onPlayerMove(console.log);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Set the outline color of the player
|
||||||
|
```
|
||||||
|
WA.player.setOutlineColor(red: number, green: number, blue: number): Promise<void>;
|
||||||
|
WA.player.removeOutlineColor(): Promise<void>;
|
||||||
|
```
|
||||||
|
|
||||||
|
You can display a thin line around your player's name (the "outline").
|
||||||
|
|
||||||
|
Use `setOutlineColor` to set the outline and `removeOutlineColor` to remove it.
|
||||||
|
|
||||||
|
Colors are expressed in RGB. Each parameter is an integer between 0 and 255.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Let's add a red outline to our player
|
||||||
|
WA.player.setOutlineColor(255, 0, 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
When you set the outline on your player, other players will see the outline too (the outline color is shared across
|
||||||
|
browsers automatically).
|
||||||
|
|
||||||
|
![](images/outlines.png)
|
||||||
|
13
front/src/Api/Events/ColorEvent.ts
Normal file
13
front/src/Api/Events/ColorEvent.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isColorEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
red: tg.isNumber,
|
||||||
|
green: tg.isNumber,
|
||||||
|
blue: tg.isNumber,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
/**
|
||||||
|
* A message sent from the iFrame to the game to dynamically set the outline of the player.
|
||||||
|
*/
|
||||||
|
export type ColorEvent = tg.GuardedType<typeof isColorEvent>;
|
@ -29,6 +29,7 @@ import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/Trigg
|
|||||||
import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
||||||
import type { ChangeLayerEvent } from "./ChangeLayerEvent";
|
import type { ChangeLayerEvent } from "./ChangeLayerEvent";
|
||||||
import type { ChangeZoneEvent } from "./ChangeZoneEvent";
|
import type { ChangeZoneEvent } from "./ChangeZoneEvent";
|
||||||
|
import { isColorEvent } from "./ColorEvent";
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T;
|
data: T;
|
||||||
@ -152,6 +153,14 @@ export const iframeQueryMapTypeGuards = {
|
|||||||
query: isCreateEmbeddedWebsiteEvent,
|
query: isCreateEmbeddedWebsiteEvent,
|
||||||
answer: tg.isUndefined,
|
answer: tg.isUndefined,
|
||||||
},
|
},
|
||||||
|
setPlayerOutline: {
|
||||||
|
query: isColorEvent,
|
||||||
|
answer: tg.isUndefined,
|
||||||
|
},
|
||||||
|
removePlayerOutline: {
|
||||||
|
query: tg.isUndefined,
|
||||||
|
answer: tg.isUndefined,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
|
type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
|
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
||||||
import type { HasPlayerMovedEvent, HasPlayerMovedEventCallback } from "../Events/HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent, HasPlayerMovedEventCallback } from "../Events/HasPlayerMovedEvent";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { apiCallback } from "./registeredCallbacks";
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
@ -82,6 +82,24 @@ export class WorkadventurePlayerCommands extends IframeApiContribution<Workadven
|
|||||||
}
|
}
|
||||||
return userRoomToken;
|
return userRoomToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setOutlineColor(red: number, green: number, blue: number): Promise<void> {
|
||||||
|
return queryWorkadventure({
|
||||||
|
type: "setPlayerOutline",
|
||||||
|
data: {
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
blue,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeOutlineColor(): Promise<void> {
|
||||||
|
return queryWorkadventure({
|
||||||
|
type: "removePlayerOutline",
|
||||||
|
data: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new WorkadventurePlayerCommands();
|
export default new WorkadventurePlayerCommands();
|
||||||
|
@ -18,6 +18,7 @@ export enum EventMessage {
|
|||||||
GROUP_DELETE = "group-delete",
|
GROUP_DELETE = "group-delete",
|
||||||
SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id.
|
SET_PLAYER_DETAILS = "set-player-details", // Send the name and character to the server (on connect), receive back the id.
|
||||||
ITEM_EVENT = "item-event",
|
ITEM_EVENT = "item-event",
|
||||||
|
USER_DETAILS_UPDATED = "user-details-updated",
|
||||||
|
|
||||||
CONNECT_ERROR = "connect_error",
|
CONNECT_ERROR = "connect_error",
|
||||||
CONNECTING_ERROR = "connecting_error",
|
CONNECTING_ERROR = "connecting_error",
|
||||||
@ -64,6 +65,7 @@ export interface MessageUserJoined {
|
|||||||
visitCardUrl: string | null;
|
visitCardUrl: string | null;
|
||||||
companion: string | null;
|
companion: string | null;
|
||||||
userUuid: string;
|
userUuid: string;
|
||||||
|
outlineColor: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PositionInterface {
|
export interface PositionInterface {
|
||||||
@ -102,6 +104,12 @@ export interface ItemEventMessageInterface {
|
|||||||
parameters: unknown;
|
parameters: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PlayerDetailsUpdatedMessageInterface {
|
||||||
|
userId: number;
|
||||||
|
outlineColor: number;
|
||||||
|
removeOutlineColor: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RoomJoinedMessageInterface {
|
export interface RoomJoinedMessageInterface {
|
||||||
//users: MessageUserPositionInterface[],
|
//users: MessageUserPositionInterface[],
|
||||||
//groups: GroupCreatedUpdatedMessageInterface[],
|
//groups: GroupCreatedUpdatedMessageInterface[],
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
BanUserMessage,
|
BanUserMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
|
PlayerDetailsUpdatedMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
|
|
||||||
import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer";
|
import type { UserSimplePeerInterface } from "../WebRtc/SimplePeer";
|
||||||
@ -45,6 +46,7 @@ import {
|
|||||||
ItemEventMessageInterface,
|
ItemEventMessageInterface,
|
||||||
MessageUserJoined,
|
MessageUserJoined,
|
||||||
OnConnectInterface,
|
OnConnectInterface,
|
||||||
|
PlayerDetailsUpdatedMessageInterface,
|
||||||
PlayGlobalMessageInterface,
|
PlayGlobalMessageInterface,
|
||||||
PositionInterface,
|
PositionInterface,
|
||||||
RoomJoinedMessageInterface,
|
RoomJoinedMessageInterface,
|
||||||
@ -172,6 +174,9 @@ export class RoomConnection implements RoomConnection {
|
|||||||
} else if (subMessage.hasEmoteeventmessage()) {
|
} else if (subMessage.hasEmoteeventmessage()) {
|
||||||
const emoteMessage = subMessage.getEmoteeventmessage() as EmoteEventMessage;
|
const emoteMessage = subMessage.getEmoteeventmessage() as EmoteEventMessage;
|
||||||
emoteEventStream.fire(emoteMessage.getActoruserid(), emoteMessage.getEmote());
|
emoteEventStream.fire(emoteMessage.getActoruserid(), emoteMessage.getEmote());
|
||||||
|
} else if (subMessage.hasPlayerdetailsupdatedmessage()) {
|
||||||
|
event = EventMessage.USER_DETAILS_UPDATED;
|
||||||
|
payload = subMessage.getPlayerdetailsupdatedmessage();
|
||||||
} else if (subMessage.hasErrormessage()) {
|
} else if (subMessage.hasErrormessage()) {
|
||||||
const errorMessage = subMessage.getErrormessage() as ErrorMessage;
|
const errorMessage = subMessage.getErrormessage() as ErrorMessage;
|
||||||
console.error("An error occurred server side: " + errorMessage.getMessage());
|
console.error("An error occurred server side: " + errorMessage.getMessage());
|
||||||
@ -276,7 +281,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) {
|
/*public emitPlayerDetailsMessage(userName: string, characterLayersSelected: BodyResourceDescriptionInterface[]) {
|
||||||
const message = new SetPlayerDetailsMessage();
|
const message = new SetPlayerDetailsMessage();
|
||||||
message.setName(userName);
|
message.setName(userName);
|
||||||
message.setCharacterlayersList(characterLayersSelected.map((characterLayer) => characterLayer.name));
|
message.setCharacterlayersList(characterLayersSelected.map((characterLayer) => characterLayer.name));
|
||||||
@ -284,6 +289,20 @@ export class RoomConnection implements RoomConnection {
|
|||||||
const clientToServerMessage = new ClientToServerMessage();
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
clientToServerMessage.setSetplayerdetailsmessage(message);
|
clientToServerMessage.setSetplayerdetailsmessage(message);
|
||||||
|
|
||||||
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public emitPlayerOutlineColor(color: number | null) {
|
||||||
|
const message = new SetPlayerDetailsMessage();
|
||||||
|
if (color === null) {
|
||||||
|
message.setRemoveoutlinecolor(true);
|
||||||
|
} else {
|
||||||
|
message.setOutlinecolor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setSetplayerdetailsmessage(message);
|
||||||
|
|
||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,6 +423,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
position: ProtobufClientUtils.toPointInterface(position),
|
position: ProtobufClientUtils.toPointInterface(position),
|
||||||
companion: companion ? companion.getName() : null,
|
companion: companion ? companion.getName() : null,
|
||||||
userUuid: message.getUseruuid(),
|
userUuid: message.getUseruuid(),
|
||||||
|
outlineColor: message.getHasoutline() ? message.getOutlinecolor() : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,6 +616,20 @@ export class RoomConnection implements RoomConnection {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPlayerDetailsUpdated(callback: (message: PlayerDetailsUpdatedMessageInterface) => void): void {
|
||||||
|
this.onMessage(EventMessage.USER_DETAILS_UPDATED, (message: PlayerDetailsUpdatedMessage) => {
|
||||||
|
const details = message.getDetails();
|
||||||
|
if (details === undefined) {
|
||||||
|
throw new Error("Malformed message. Missing details in PlayerDetailsUpdatedMessage");
|
||||||
|
}
|
||||||
|
callback({
|
||||||
|
userId: message.getUserid(),
|
||||||
|
outlineColor: details.getOutlinecolor(),
|
||||||
|
removeOutlineColor: details.getRemoveoutlinecolor(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public uploadAudio(file: FormData) {
|
public uploadAudio(file: FormData) {
|
||||||
return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file)
|
return Axios.post(`${UPLOADER_URL}/upload-audio-message`, file)
|
||||||
.then((res: { data: {} }) => {
|
.then((res: { data: {} }) => {
|
||||||
|
@ -13,7 +13,8 @@ import { isSilentStore } from "../../Stores/MediaStore";
|
|||||||
import { lazyLoadPlayerCharacterTextures, loadAllDefaultModels } from "./PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures, loadAllDefaultModels } from "./PlayerTexturesLoadingManager";
|
||||||
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
||||||
import type { PictureStore } from "../../Stores/PictureStore";
|
import type { PictureStore } from "../../Stores/PictureStore";
|
||||||
import { Writable, writable } from "svelte/store";
|
import { Unsubscriber, Writable, writable } from "svelte/store";
|
||||||
|
import { createColorStore } from "../../Stores/OutlineColorStore";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ export abstract class Character extends Container {
|
|||||||
private emoteTween: Phaser.Tweens.Tween | null = null;
|
private emoteTween: Phaser.Tweens.Tween | null = null;
|
||||||
scene: GameScene;
|
scene: GameScene;
|
||||||
private readonly _pictureStore: Writable<string | undefined>;
|
private readonly _pictureStore: Writable<string | undefined>;
|
||||||
|
private readonly outlineColorStore = createColorStore();
|
||||||
|
private readonly outlineColorStoreUnsubscribe: Unsubscriber;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: GameScene,
|
scene: GameScene,
|
||||||
@ -97,18 +100,26 @@ export abstract class Character extends Container {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.on("pointerover", () => {
|
this.on("pointerover", () => {
|
||||||
this.getOutlinePlugin()?.add(this.playerName, {
|
this.outlineColorStore.pointerOver();
|
||||||
thickness: 2,
|
|
||||||
outlineColor: 0xffff00,
|
|
||||||
});
|
|
||||||
this.scene.markDirty();
|
|
||||||
});
|
});
|
||||||
this.on("pointerout", () => {
|
this.on("pointerout", () => {
|
||||||
this.getOutlinePlugin()?.remove(this.playerName);
|
this.outlineColorStore.pointerOut();
|
||||||
this.scene.markDirty();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.outlineColorStoreUnsubscribe = this.outlineColorStore.subscribe((color) => {
|
||||||
|
if (color === undefined) {
|
||||||
|
this.getOutlinePlugin()?.remove(this.playerName);
|
||||||
|
} else {
|
||||||
|
this.getOutlinePlugin()?.remove(this.playerName);
|
||||||
|
this.getOutlinePlugin()?.add(this.playerName, {
|
||||||
|
thickness: 2,
|
||||||
|
outlineColor: color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.scene.markDirty();
|
||||||
|
});
|
||||||
|
|
||||||
scene.add.existing(this);
|
scene.add.existing(this);
|
||||||
|
|
||||||
this.scene.physics.world.enableBody(this);
|
this.scene.physics.world.enableBody(this);
|
||||||
@ -315,6 +326,7 @@ export abstract class Character extends Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.list.forEach((objectContaining) => objectContaining.destroy());
|
this.list.forEach((objectContaining) => objectContaining.destroy());
|
||||||
|
this.outlineColorStoreUnsubscribe();
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,4 +413,12 @@ export abstract class Character extends Container {
|
|||||||
public get pictureStore(): PictureStore {
|
public get pictureStore(): PictureStore {
|
||||||
return this._pictureStore;
|
return this._pictureStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setOutlineColor(color: number): void {
|
||||||
|
this.outlineColorStore.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeOutlineColor(): void {
|
||||||
|
this.outlineColorStore.removeColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ import type {
|
|||||||
MessageUserMovedInterface,
|
MessageUserMovedInterface,
|
||||||
MessageUserPositionInterface,
|
MessageUserPositionInterface,
|
||||||
OnConnectInterface,
|
OnConnectInterface,
|
||||||
|
PlayerDetailsUpdatedMessageInterface,
|
||||||
PointInterface,
|
PointInterface,
|
||||||
PositionInterface,
|
PositionInterface,
|
||||||
RoomJoinedMessageInterface,
|
RoomJoinedMessageInterface,
|
||||||
@ -88,6 +89,7 @@ import Tileset = Phaser.Tilemaps.Tileset;
|
|||||||
import SpriteSheetFile = Phaser.Loader.FileTypes.SpriteSheetFile;
|
import SpriteSheetFile = Phaser.Loader.FileTypes.SpriteSheetFile;
|
||||||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||||
import { MapStore } from "../../Stores/Utils/MapStore";
|
import { MapStore } from "../../Stores/Utils/MapStore";
|
||||||
|
import { SetPlayerDetailsMessage } from "../../Messages/generated/messages_pb";
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
reconnecting: boolean;
|
reconnecting: boolean;
|
||||||
@ -123,6 +125,11 @@ interface DeleteGroupEventInterface {
|
|||||||
groupId: number;
|
groupId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PlayerDetailsUpdatedInterface {
|
||||||
|
type: "PlayerDetailsUpdated";
|
||||||
|
details: PlayerDetailsUpdatedMessageInterface;
|
||||||
|
}
|
||||||
|
|
||||||
export class GameScene extends DirtyScene {
|
export class GameScene extends DirtyScene {
|
||||||
Terrains: Array<Phaser.Tilemaps.Tileset>;
|
Terrains: Array<Phaser.Tilemaps.Tileset>;
|
||||||
CurrentPlayer!: Player;
|
CurrentPlayer!: Player;
|
||||||
@ -135,20 +142,14 @@ export class GameScene extends DirtyScene {
|
|||||||
groups: Map<number, Sprite>;
|
groups: Map<number, Sprite>;
|
||||||
circleTexture!: CanvasTexture;
|
circleTexture!: CanvasTexture;
|
||||||
circleRedTexture!: CanvasTexture;
|
circleRedTexture!: CanvasTexture;
|
||||||
pendingEvents: Queue<
|
pendingEvents = new Queue<
|
||||||
| InitUserPositionEventInterface
|
|
||||||
| AddPlayerEventInterface
|
|
||||||
| RemovePlayerEventInterface
|
|
||||||
| UserMovedEventInterface
|
|
||||||
| GroupCreatedUpdatedEventInterface
|
|
||||||
| DeleteGroupEventInterface
|
|
||||||
> = new Queue<
|
|
||||||
| InitUserPositionEventInterface
|
| InitUserPositionEventInterface
|
||||||
| AddPlayerEventInterface
|
| AddPlayerEventInterface
|
||||||
| RemovePlayerEventInterface
|
| RemovePlayerEventInterface
|
||||||
| UserMovedEventInterface
|
| UserMovedEventInterface
|
||||||
| GroupCreatedUpdatedEventInterface
|
| GroupCreatedUpdatedEventInterface
|
||||||
| DeleteGroupEventInterface
|
| DeleteGroupEventInterface
|
||||||
|
| PlayerDetailsUpdatedInterface
|
||||||
>();
|
>();
|
||||||
private initPosition: PositionInterface | null = null;
|
private initPosition: PositionInterface | null = null;
|
||||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||||
@ -682,6 +683,7 @@ export class GameScene extends DirtyScene {
|
|||||||
visitCardUrl: message.visitCardUrl,
|
visitCardUrl: message.visitCardUrl,
|
||||||
companion: message.companion,
|
companion: message.companion,
|
||||||
userUuid: message.userUuid,
|
userUuid: message.userUuid,
|
||||||
|
outlineColor: message.outlineColor,
|
||||||
};
|
};
|
||||||
this.addPlayer(userMessage);
|
this.addPlayer(userMessage);
|
||||||
});
|
});
|
||||||
@ -735,6 +737,13 @@ export class GameScene extends DirtyScene {
|
|||||||
item.fire(message.event, message.state, message.parameters);
|
item.fire(message.event, message.state, message.parameters);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.connection.onPlayerDetailsUpdated((message) => {
|
||||||
|
this.pendingEvents.enqueue({
|
||||||
|
type: "PlayerDetailsUpdated",
|
||||||
|
details: message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered when we receive the JWT token to connect to Jitsi
|
* Triggered when we receive the JWT token to connect to Jitsi
|
||||||
*/
|
*/
|
||||||
@ -1300,6 +1309,21 @@ ${escapedMessage}
|
|||||||
iframeListener.registerAnswerer("removeActionMessage", (message) => {
|
iframeListener.registerAnswerer("removeActionMessage", (message) => {
|
||||||
layoutManagerActionStore.removeAction(message.uuid);
|
layoutManagerActionStore.removeAction(message.uuid);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("setPlayerOutline", (message) => {
|
||||||
|
const normalizeColor = (color: number) => Math.min(Math.max(0, Math.round(color)), 255);
|
||||||
|
const red = normalizeColor(message.red);
|
||||||
|
const green = normalizeColor(message.green);
|
||||||
|
const blue = normalizeColor(message.blue);
|
||||||
|
const color = (red << 16) | (green << 8) | blue;
|
||||||
|
this.CurrentPlayer.setOutlineColor(color);
|
||||||
|
this.connection?.emitPlayerOutlineColor(color);
|
||||||
|
});
|
||||||
|
|
||||||
|
iframeListener.registerAnswerer("removePlayerOutline", (message) => {
|
||||||
|
this.CurrentPlayer.removeOutlineColor();
|
||||||
|
this.connection?.emitPlayerOutlineColor(null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPropertyLayer(
|
private setPropertyLayer(
|
||||||
@ -1422,6 +1446,7 @@ ${escapedMessage}
|
|||||||
iframeListener.unregisterAnswerer("removeActionMessage");
|
iframeListener.unregisterAnswerer("removeActionMessage");
|
||||||
iframeListener.unregisterAnswerer("openCoWebsite");
|
iframeListener.unregisterAnswerer("openCoWebsite");
|
||||||
iframeListener.unregisterAnswerer("getCoWebsites");
|
iframeListener.unregisterAnswerer("getCoWebsites");
|
||||||
|
iframeListener.unregisterAnswerer("setPlayerOutline");
|
||||||
this.sharedVariablesManager?.close();
|
this.sharedVariablesManager?.close();
|
||||||
this.embeddedWebsiteManager?.close();
|
this.embeddedWebsiteManager?.close();
|
||||||
|
|
||||||
@ -1676,6 +1701,12 @@ ${escapedMessage}
|
|||||||
case "DeleteGroupEvent":
|
case "DeleteGroupEvent":
|
||||||
this.doDeleteGroup(event.groupId);
|
this.doDeleteGroup(event.groupId);
|
||||||
break;
|
break;
|
||||||
|
case "PlayerDetailsUpdated":
|
||||||
|
this.doUpdatePlayerDetails(event.details);
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
const tmp: never = event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Let's move all users
|
// Let's move all users
|
||||||
@ -1749,6 +1780,9 @@ ${escapedMessage}
|
|||||||
addPlayerData.companion,
|
addPlayerData.companion,
|
||||||
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
|
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
|
||||||
);
|
);
|
||||||
|
if (addPlayerData.outlineColor !== undefined) {
|
||||||
|
player.setOutlineColor(addPlayerData.outlineColor);
|
||||||
|
}
|
||||||
this.MapPlayers.add(player);
|
this.MapPlayers.add(player);
|
||||||
this.MapPlayersByKey.set(player.userId, player);
|
this.MapPlayersByKey.set(player.userId, player);
|
||||||
player.updatePosition(addPlayerData.position);
|
player.updatePosition(addPlayerData.position);
|
||||||
@ -1852,6 +1886,23 @@ ${escapedMessage}
|
|||||||
this.groups.delete(groupId);
|
this.groups.delete(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doUpdatePlayerDetails(message: PlayerDetailsUpdatedMessageInterface): void {
|
||||||
|
const character = this.MapPlayersByKey.get(message.userId);
|
||||||
|
if (character === undefined) {
|
||||||
|
console.log(
|
||||||
|
"Could not set new details to character with ID ",
|
||||||
|
message.userId,
|
||||||
|
". Did he/she left before te message was received?"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.removeOutlineColor) {
|
||||||
|
character.removeOutlineColor();
|
||||||
|
} else {
|
||||||
|
character.setOutlineColor(message.outlineColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends to the server an event emitted by one of the ActionableItems.
|
* Sends to the server an event emitted by one of the ActionableItems.
|
||||||
*/
|
*/
|
||||||
|
@ -8,4 +8,5 @@ export interface PlayerInterface {
|
|||||||
companion: string | null;
|
companion: string | null;
|
||||||
userUuid: string;
|
userUuid: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
|
outlineColor?: number;
|
||||||
}
|
}
|
||||||
|
@ -365,7 +365,9 @@ function applyCameraConstraints(currentStream: MediaStream | null, constraints:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const track of currentStream.getVideoTracks()) {
|
for (const track of currentStream.getVideoTracks()) {
|
||||||
toggleConstraints(track, constraints);
|
toggleConstraints(track, constraints).catch((e) =>
|
||||||
|
console.error("Error while setting new camera constraints:", e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,19 +382,21 @@ function applyMicrophoneConstraints(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const track of currentStream.getAudioTracks()) {
|
for (const track of currentStream.getAudioTracks()) {
|
||||||
toggleConstraints(track, constraints);
|
toggleConstraints(track, constraints).catch((e) =>
|
||||||
|
console.error("Error while setting new audio constraints:", e)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): void {
|
async function toggleConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints | boolean): Promise<void> {
|
||||||
if (implementCorrectTrackBehavior) {
|
if (implementCorrectTrackBehavior) {
|
||||||
track.enabled = constraints !== false;
|
track.enabled = constraints !== false;
|
||||||
} else if (constraints === false) {
|
} else if (constraints === false) {
|
||||||
track.stop();
|
track.stop();
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
|
||||||
if (typeof constraints !== "boolean" && constraints !== true) {
|
if (typeof constraints !== "boolean" && constraints !== true) {
|
||||||
track.applyConstraints(constraints);
|
return track.applyConstraints(constraints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,7 +488,12 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
type: "success",
|
type: "success",
|
||||||
stream: null,
|
stream: null,
|
||||||
});
|
});
|
||||||
initStream(constraints);
|
initStream(constraints).catch((e) => {
|
||||||
|
set({
|
||||||
|
type: "error",
|
||||||
|
error: e instanceof Error ? e : new Error("An unknown error happened"),
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//on bad navigators like chrome, we have to stop the tracks when we mute and reinstantiate the stream when we need to unmute
|
//on bad navigators like chrome, we have to stop the tracks when we mute and reinstantiate the stream when we need to unmute
|
||||||
@ -496,7 +505,12 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
});
|
});
|
||||||
} //we reemit the stream if it was muted just to be sure
|
} //we reemit the stream if it was muted just to be sure
|
||||||
else if (constraints.audio /* && !oldConstraints.audio*/ || (!oldConstraints.video && constraints.video)) {
|
else if (constraints.audio /* && !oldConstraints.audio*/ || (!oldConstraints.video && constraints.video)) {
|
||||||
initStream(constraints);
|
initStream(constraints).catch((e) => {
|
||||||
|
set({
|
||||||
|
type: "error",
|
||||||
|
error: e instanceof Error ? e : new Error("An unknown error happened"),
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
oldConstraints = {
|
oldConstraints = {
|
||||||
video: !!constraints.video,
|
video: !!constraints.video,
|
||||||
|
40
front/src/Stores/OutlineColorStore.ts
Normal file
40
front/src/Stores/OutlineColorStore.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export function createColorStore() {
|
||||||
|
const { subscribe, set } = writable<number | undefined>(undefined);
|
||||||
|
|
||||||
|
let color: number | undefined = undefined;
|
||||||
|
let focused: boolean = false;
|
||||||
|
|
||||||
|
const updateColor = () => {
|
||||||
|
if (focused) {
|
||||||
|
set(0xffff00);
|
||||||
|
} else {
|
||||||
|
set(color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
|
||||||
|
pointerOver() {
|
||||||
|
focused = true;
|
||||||
|
updateColor();
|
||||||
|
},
|
||||||
|
|
||||||
|
pointerOut() {
|
||||||
|
focused = false;
|
||||||
|
updateColor();
|
||||||
|
},
|
||||||
|
|
||||||
|
setColor(newColor: number) {
|
||||||
|
color = newColor;
|
||||||
|
updateColor();
|
||||||
|
},
|
||||||
|
|
||||||
|
removeColor() {
|
||||||
|
color = undefined;
|
||||||
|
updateColor();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
@ -98,7 +98,7 @@ export class SimplePeer {
|
|||||||
|
|
||||||
private receiveWebrtcStart(user: UserSimplePeerInterface): void {
|
private receiveWebrtcStart(user: UserSimplePeerInterface): void {
|
||||||
this.Users.push(user);
|
this.Users.push(user);
|
||||||
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group)
|
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joins a group)
|
||||||
// So we can receive a request we already had before. (which will abort at the first line of createPeerConnection)
|
// So we can receive a request we already had before. (which will abort at the first line of createPeerConnection)
|
||||||
// This would be symmetrical to the way we handle disconnection.
|
// This would be symmetrical to the way we handle disconnection.
|
||||||
|
|
||||||
|
93
maps/tests/Outline/outline.json
Normal file
93
maps/tests/Outline/outline.json
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"outline.php"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsiteAllowApi",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":342.082007343941,
|
||||||
|
"id":1,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":13,
|
||||||
|
"text":"Test:\nPlay with the colors and the limits in the form\n\nResult:\nThe outline should be displayed. A mouse over displays the yellow outline but the normal outline comes back on mouse out.\n\nTest:\nClick the remove outline\n\nResult:\nThe outline is removed\n\nTest:\nClick with many players\n\nResult:\nThe outline is correctly shared",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":274.96422378621,
|
||||||
|
"x":35.7623688177162,
|
||||||
|
"y":8.73391812865529
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":6,
|
||||||
|
"nextobjectid":3,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"..\/tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
36
maps/tests/Outline/outline.php
Normal file
36
maps/tests/Outline/outline.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script src="<?php echo $_SERVER["FRONT_URL"] ?>/iframe_api.js"></script>
|
||||||
|
<script>
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('After WA init');
|
||||||
|
const setOutlineButton = document.getElementById('setOutline');
|
||||||
|
const removeOutlineButton = document.getElementById('removeOutline');
|
||||||
|
const redField = document.getElementById('red');
|
||||||
|
const greenField = document.getElementById('green');
|
||||||
|
const blueField = document.getElementById('blue');
|
||||||
|
|
||||||
|
setOutlineButton.addEventListener('click', () => {
|
||||||
|
console.log('SETTING OUTLINE');
|
||||||
|
WA.player.setOutlineColor(parseInt(redField.value), parseInt(greenField.value), parseInt(blueField.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
removeOutlineButton.addEventListener('click', () => {
|
||||||
|
console.log('REMOVING OUTLINE');
|
||||||
|
WA.player.removeOutlineColor();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
red: <input type="text" id="red" value="0" /><br/>
|
||||||
|
green: <input type="text" id="green" value="0" /><br/>
|
||||||
|
blue: <input type="text" id="blue" value="0" /><br/>
|
||||||
|
|
||||||
|
<button id="setOutline">Set outline</button>
|
||||||
|
|
||||||
|
<button id="removeOutline">Remove outline</button>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -251,6 +251,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="ChangeLayerApi/change_layer_api.json" target="_blank">Testing scripting API for enters/leaves layer</a>
|
<a href="#" class="testLink" data-testmap="ChangeLayerApi/change_layer_api.json" target="_blank">Testing scripting API for enters/leaves layer</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-outline-api"> Success <input type="radio" name="test-outline-api"> Failure <input type="radio" name="test-outline-api" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="Outline/outline.json" target="_blank">Testing scripting API for outline on players</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h2>CoWebsite</h2>
|
<h2>CoWebsite</h2>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
@ -47,8 +47,12 @@ message PingMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SetPlayerDetailsMessage {
|
message SetPlayerDetailsMessage {
|
||||||
string name = 1;
|
//string name = 1;
|
||||||
repeated string characterLayers = 2;
|
//repeated string characterLayers = 2;
|
||||||
|
|
||||||
|
// TODO: switch to google.protobuf.Int32Value when we migrate to ts-proto
|
||||||
|
uint32 outlineColor = 3;
|
||||||
|
bool removeOutlineColor = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserMovesMessage {
|
message UserMovesMessage {
|
||||||
@ -150,6 +154,7 @@ message SubMessage {
|
|||||||
EmoteEventMessage emoteEventMessage = 7;
|
EmoteEventMessage emoteEventMessage = 7;
|
||||||
VariableMessage variableMessage = 8;
|
VariableMessage variableMessage = 8;
|
||||||
ErrorMessage errorMessage = 9;
|
ErrorMessage errorMessage = 9;
|
||||||
|
PlayerDetailsUpdatedMessage playerDetailsUpdatedMessage = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +181,8 @@ message UserJoinedMessage {
|
|||||||
CompanionMessage companion = 5;
|
CompanionMessage companion = 5;
|
||||||
string visitCardUrl = 6;
|
string visitCardUrl = 6;
|
||||||
string userUuid = 7;
|
string userUuid = 7;
|
||||||
|
uint32 outlineColor = 8;
|
||||||
|
bool hasOutline = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserLeftMessage {
|
message UserLeftMessage {
|
||||||
@ -313,6 +320,8 @@ message UserJoinedZoneMessage {
|
|||||||
CompanionMessage companion = 6;
|
CompanionMessage companion = 6;
|
||||||
string visitCardUrl = 7;
|
string visitCardUrl = 7;
|
||||||
string userUuid = 8;
|
string userUuid = 8;
|
||||||
|
uint32 outlineColor = 9;
|
||||||
|
bool hasOutline = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UserLeftZoneMessage {
|
message UserLeftZoneMessage {
|
||||||
@ -332,6 +341,10 @@ message GroupLeftZoneMessage {
|
|||||||
Zone toZone = 2;
|
Zone toZone = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PlayerDetailsUpdatedMessage {
|
||||||
|
int32 userId = 1;
|
||||||
|
SetPlayerDetailsMessage details = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message Zone {
|
message Zone {
|
||||||
int32 x = 1;
|
int32 x = 1;
|
||||||
@ -384,6 +397,7 @@ message SubToPusherMessage {
|
|||||||
BanUserMessage banUserMessage = 8;
|
BanUserMessage banUserMessage = 8;
|
||||||
EmoteEventMessage emoteEventMessage = 9;
|
EmoteEventMessage emoteEventMessage = 9;
|
||||||
ErrorMessage errorMessage = 10;
|
ErrorMessage errorMessage = 10;
|
||||||
|
PlayerDetailsUpdatedMessage playerDetailsUpdatedMessage = 11;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import {
|
|||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
CompanionMessage,
|
CompanionMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
|
PlayerDetailsUpdatedMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ClientReadableStream } from "grpc";
|
import { ClientReadableStream } from "grpc";
|
||||||
import { PositionDispatcher } from "_Model/PositionDispatcher";
|
import { PositionDispatcher } from "_Model/PositionDispatcher";
|
||||||
@ -32,6 +34,7 @@ export interface ZoneEventListener {
|
|||||||
onGroupLeaves(groupId: number, listener: ExSocketInterface): void;
|
onGroupLeaves(groupId: number, listener: ExSocketInterface): void;
|
||||||
onEmote(emoteMessage: EmoteEventMessage, listener: ExSocketInterface): void;
|
onEmote(emoteMessage: EmoteEventMessage, listener: ExSocketInterface): void;
|
||||||
onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void;
|
onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void;
|
||||||
|
onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ExSocketInterface): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*export type EntersCallback = (thing: Movable, listener: User) => void;
|
/*export type EntersCallback = (thing: Movable, listener: User) => void;
|
||||||
@ -46,7 +49,8 @@ export class UserDescriptor {
|
|||||||
private characterLayers: CharacterLayerMessage[],
|
private characterLayers: CharacterLayerMessage[],
|
||||||
private position: PositionMessage,
|
private position: PositionMessage,
|
||||||
private visitCardUrl: string | null,
|
private visitCardUrl: string | null,
|
||||||
private companion?: CompanionMessage
|
private companion?: CompanionMessage,
|
||||||
|
private outlineColor?: number
|
||||||
) {
|
) {
|
||||||
if (!Number.isInteger(this.userId)) {
|
if (!Number.isInteger(this.userId)) {
|
||||||
throw new Error("UserDescriptor.userId is not an integer: " + this.userId);
|
throw new Error("UserDescriptor.userId is not an integer: " + this.userId);
|
||||||
@ -65,7 +69,8 @@ export class UserDescriptor {
|
|||||||
message.getCharacterlayersList(),
|
message.getCharacterlayersList(),
|
||||||
position,
|
position,
|
||||||
message.getVisitcardurl(),
|
message.getVisitcardurl(),
|
||||||
message.getCompanion()
|
message.getCompanion(),
|
||||||
|
message.getHasoutline() ? message.getOutlinecolor() : undefined
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +82,14 @@ export class UserDescriptor {
|
|||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateDetails(playerDetails: SetPlayerDetailsMessage) {
|
||||||
|
if (playerDetails.getRemoveoutlinecolor()) {
|
||||||
|
this.outlineColor = undefined;
|
||||||
|
} else {
|
||||||
|
this.outlineColor = playerDetails.getOutlinecolor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public toUserJoinedMessage(): UserJoinedMessage {
|
public toUserJoinedMessage(): UserJoinedMessage {
|
||||||
const userJoinedMessage = new UserJoinedMessage();
|
const userJoinedMessage = new UserJoinedMessage();
|
||||||
|
|
||||||
@ -89,6 +102,12 @@ export class UserDescriptor {
|
|||||||
}
|
}
|
||||||
userJoinedMessage.setCompanion(this.companion);
|
userJoinedMessage.setCompanion(this.companion);
|
||||||
userJoinedMessage.setUseruuid(this.userUuid);
|
userJoinedMessage.setUseruuid(this.userUuid);
|
||||||
|
if (this.outlineColor !== undefined) {
|
||||||
|
userJoinedMessage.setOutlinecolor(this.outlineColor);
|
||||||
|
userJoinedMessage.setHasoutline(true);
|
||||||
|
} else {
|
||||||
|
userJoinedMessage.setHasoutline(false);
|
||||||
|
}
|
||||||
|
|
||||||
return userJoinedMessage;
|
return userJoinedMessage;
|
||||||
}
|
}
|
||||||
@ -209,7 +228,7 @@ export class Zone {
|
|||||||
const userDescriptor = this.users.get(userId);
|
const userDescriptor = this.users.get(userId);
|
||||||
|
|
||||||
if (userDescriptor === undefined) {
|
if (userDescriptor === undefined) {
|
||||||
console.error('Unexpected move message received for user "' + userId + '"');
|
console.error('Unexpected move message received for unknown user "' + userId + '"');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +238,27 @@ export class Zone {
|
|||||||
} else if (message.hasEmoteeventmessage()) {
|
} else if (message.hasEmoteeventmessage()) {
|
||||||
const emoteEventMessage = message.getEmoteeventmessage() as EmoteEventMessage;
|
const emoteEventMessage = message.getEmoteeventmessage() as EmoteEventMessage;
|
||||||
this.notifyEmote(emoteEventMessage);
|
this.notifyEmote(emoteEventMessage);
|
||||||
|
} else if (message.hasPlayerdetailsupdatedmessage()) {
|
||||||
|
const playerDetailsUpdatedMessage =
|
||||||
|
message.getPlayerdetailsupdatedmessage() as PlayerDetailsUpdatedMessage;
|
||||||
|
|
||||||
|
const userId = playerDetailsUpdatedMessage.getUserid();
|
||||||
|
const userDescriptor = this.users.get(userId);
|
||||||
|
|
||||||
|
if (userDescriptor === undefined) {
|
||||||
|
console.error('Unexpected details message received for unknown user "' + userId + '"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const details = playerDetailsUpdatedMessage.getDetails();
|
||||||
|
if (details === undefined) {
|
||||||
|
console.error('Unexpected details message without details received for user "' + userId + '"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
userDescriptor.updateDetails(details);
|
||||||
|
|
||||||
|
this.notifyPlayerDetailsUpdated(playerDetailsUpdatedMessage);
|
||||||
} else if (message.hasErrormessage()) {
|
} else if (message.hasErrormessage()) {
|
||||||
const errorMessage = message.getErrormessage() as ErrorMessage;
|
const errorMessage = message.getErrormessage() as ErrorMessage;
|
||||||
this.notifyError(errorMessage);
|
this.notifyError(errorMessage);
|
||||||
@ -308,6 +348,15 @@ export class Zone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private notifyPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage) {
|
||||||
|
for (const listener of this.listeners) {
|
||||||
|
if (listener.userId === playerDetailsUpdatedMessage.getUserid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.socketListener.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private notifyError(errorMessage: ErrorMessage) {
|
private notifyError(errorMessage: ErrorMessage) {
|
||||||
for (const listener of this.listeners) {
|
for (const listener of this.listeners) {
|
||||||
this.socketListener.onError(errorMessage, listener);
|
this.socketListener.onError(errorMessage, listener);
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
VariableMessage,
|
VariableMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
WorldFullMessage,
|
WorldFullMessage,
|
||||||
|
PlayerDetailsUpdatedMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, JITSI_ISS, JITSI_URL, SECRET_JITSI_KEY } from "../Enum/EnvironmentVariable";
|
||||||
@ -55,6 +56,7 @@ const debug = Debug("socket");
|
|||||||
interface AdminSocketRoomsList {
|
interface AdminSocketRoomsList {
|
||||||
[index: string]: number;
|
[index: string]: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AdminSocketUsersList {
|
interface AdminSocketUsersList {
|
||||||
[index: string]: boolean;
|
[index: string]: boolean;
|
||||||
}
|
}
|
||||||
@ -276,6 +278,16 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
emitInBatch(listener, subMessage);
|
emitInBatch(listener, subMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPlayerDetailsUpdated(
|
||||||
|
playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage,
|
||||||
|
listener: ExSocketInterface
|
||||||
|
): void {
|
||||||
|
const subMessage = new SubMessage();
|
||||||
|
subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage);
|
||||||
|
|
||||||
|
emitInBatch(listener, subMessage);
|
||||||
|
}
|
||||||
|
|
||||||
onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void {
|
onError(errorMessage: ErrorMessage, listener: ExSocketInterface): void {
|
||||||
const subMessage = new SubMessage();
|
const subMessage = new SubMessage();
|
||||||
subMessage.setErrormessage(errorMessage);
|
subMessage.setErrormessage(errorMessage);
|
||||||
|
Loading…
Reference in New Issue
Block a user