Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop
This commit is contained in:
commit
12bc22236f
@ -26,6 +26,9 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error"
|
||||||
|
],
|
||||||
"no-throw-literal": "error"
|
"no-throw-literal": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,7 +45,6 @@
|
|||||||
"busboy": "^0.3.1",
|
"busboy": "^0.3.1",
|
||||||
"circular-json": "^0.5.9",
|
"circular-json": "^0.5.9",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"generic-type-guard": "^3.2.0",
|
|
||||||
"google-protobuf": "^3.13.0",
|
"google-protobuf": "^3.13.0",
|
||||||
"grpc": "^1.24.4",
|
"grpc": "^1.24.4",
|
||||||
"ipaddr.js": "^2.0.1",
|
"ipaddr.js": "^2.0.1",
|
||||||
@ -56,7 +55,7 @@
|
|||||||
"redis": "^3.1.2",
|
"redis": "^3.1.2",
|
||||||
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
||||||
"uuidv4": "^6.0.7",
|
"uuidv4": "^6.0.7",
|
||||||
"zod": "^3.12.0"
|
"zod": "^3.14.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/busboy": "^0.2.3",
|
"@types/busboy": "^0.2.3",
|
||||||
|
@ -48,7 +48,7 @@ export class DebugController {
|
|||||||
return obj;
|
return obj;
|
||||||
} else if (value instanceof Set) {
|
} else if (value instanceof Set) {
|
||||||
const obj: Array<unknown> = [];
|
const obj: Array<unknown> = [];
|
||||||
for (const [setKey, setValue] of value.entries()) {
|
for (const setValue of value.values()) {
|
||||||
obj.push(setValue);
|
obj.push(setValue);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { App } from "../Server/sifrr.server";
|
import { App } from "../Server/sifrr.server";
|
||||||
import { HttpRequest, HttpResponse } from "uWebSockets.js";
|
import { HttpResponse } from "uWebSockets.js";
|
||||||
import { register, collectDefaultMetrics } from "prom-client";
|
import { register, collectDefaultMetrics } from "prom-client";
|
||||||
|
|
||||||
export class PrometheusController {
|
export class PrometheusController {
|
||||||
@ -11,7 +11,7 @@ export class PrometheusController {
|
|||||||
this.App.get("/metrics", this.metrics.bind(this));
|
this.App.get("/metrics", this.metrics.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private metrics(res: HttpResponse, req: HttpRequest): void {
|
private metrics(res: HttpResponse): void {
|
||||||
res.writeHeader("Content-Type", register.contentType);
|
res.writeHeader("Content-Type", register.contentType);
|
||||||
res.end(register.metrics());
|
res.end(register.metrics());
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { PointInterface } from "./Websocket/PointInterface";
|
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 {
|
import {
|
||||||
EmoteCallback,
|
EmoteCallback,
|
||||||
EntersCallback,
|
EntersCallback,
|
||||||
@ -9,23 +9,20 @@ import {
|
|||||||
LockGroupCallback,
|
LockGroupCallback,
|
||||||
MovesCallback,
|
MovesCallback,
|
||||||
PlayerDetailsUpdatedCallback,
|
PlayerDetailsUpdatedCallback,
|
||||||
} from "_Model/Zone";
|
} from "../Model/Zone";
|
||||||
import { PositionNotifier } from "./PositionNotifier";
|
import { PositionNotifier } from "./PositionNotifier";
|
||||||
import { Movable } from "_Model/Movable";
|
import { Movable } from "../Model/Movable";
|
||||||
import {
|
import {
|
||||||
BatchToPusherMessage,
|
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
ErrorMessage,
|
|
||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage,
|
||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
VariableMessage,
|
|
||||||
VariableWithTagMessage,
|
VariableWithTagMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
import { RoomSocket, ZoneSocket } from "src/RoomManager";
|
import { RoomSocket, ZoneSocket } from "../RoomManager";
|
||||||
import { Admin } from "../Model/Admin";
|
import { Admin } from "../Model/Admin";
|
||||||
import { adminApi } from "../Services/AdminApi";
|
import { adminApi } from "../Services/AdminApi";
|
||||||
import { isMapDetailsData, MapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
import { isMapDetailsData, MapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
||||||
@ -36,7 +33,6 @@ import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
|||||||
import { LocalUrlError } from "../Services/LocalUrlError";
|
import { LocalUrlError } from "../Services/LocalUrlError";
|
||||||
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
|
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
|
||||||
import { VariableError } from "../Services/VariableError";
|
import { VariableError } from "../Services/VariableError";
|
||||||
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
|
|
||||||
|
|
||||||
export type ConnectCallback = (user: User, group: Group) => void;
|
export type ConnectCallback = (user: User, group: Group) => void;
|
||||||
export type DisconnectCallback = (user: User, group: Group) => void;
|
export type DisconnectCallback = (user: User, group: Group) => void;
|
||||||
@ -150,6 +146,7 @@ export class GameRoom {
|
|||||||
position,
|
position,
|
||||||
false,
|
false,
|
||||||
this.positionNotifier,
|
this.positionNotifier,
|
||||||
|
joinRoomMessage.getAway(),
|
||||||
socket,
|
socket,
|
||||||
joinRoomMessage.getTagList(),
|
joinRoomMessage.getTagList(),
|
||||||
joinRoomMessage.getVisitcardurl(),
|
joinRoomMessage.getVisitcardurl(),
|
||||||
@ -398,7 +395,7 @@ export class GameRoom {
|
|||||||
private searchClosestAvailableUserOrGroup(user: User): User | Group | null {
|
private searchClosestAvailableUserOrGroup(user: User): User | Group | null {
|
||||||
let minimumDistanceFound: number = Math.max(this.minDistance, this.groupRadius);
|
let minimumDistanceFound: number = Math.max(this.minDistance, this.groupRadius);
|
||||||
let matchingItem: User | Group | null = null;
|
let matchingItem: User | Group | null = null;
|
||||||
this.users.forEach((currentUser, userId) => {
|
this.users.forEach((currentUser) => {
|
||||||
// Let's only check users that are not part of a group
|
// Let's only check users that are not part of a group
|
||||||
if (typeof currentUser.group !== "undefined") {
|
if (typeof currentUser.group !== "undefined") {
|
||||||
return;
|
return;
|
||||||
@ -584,12 +581,15 @@ export class GameRoom {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await adminApi.fetchMapDetails(roomUrl);
|
const result = isMapDetailsData.safeParse(await adminApi.fetchMapDetails(roomUrl));
|
||||||
if (isRoomRedirect(result)) {
|
|
||||||
console.error("Unexpected room redirect received while querying map details", result);
|
if (result.success) {
|
||||||
throw new Error("Unexpected room redirect received while querying map details");
|
return result.data;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
console.error(result.error.issues);
|
||||||
|
console.error("Unexpected room redirect received while querying map details", result);
|
||||||
|
throw new Error("Unexpected room redirect received while querying map details");
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapPromise: Promise<ITiledMap> | undefined;
|
private mapPromise: Promise<ITiledMap> | undefined;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { ConnectCallback, DisconnectCallback, GameRoom } 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 { MAX_PER_GROUP } from "../Enum/EnvironmentVariable";
|
import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable";
|
||||||
import type { Zone } from "../Model/Zone";
|
import type { Zone } from "../Model/Zone";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { PositionInterface } from "_Model/PositionInterface";
|
import { PositionInterface } from "../Model/PositionInterface";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A physical object that can be placed into a Zone
|
* A physical object that can be placed into a Zone
|
||||||
|
@ -17,8 +17,8 @@ import {
|
|||||||
PlayerDetailsUpdatedCallback,
|
PlayerDetailsUpdatedCallback,
|
||||||
Zone,
|
Zone,
|
||||||
} from "./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, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb";
|
import { EmoteEventMessage, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb";
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Group } from "./Group";
|
import { Group } from "./Group";
|
||||||
import { PointInterface } from "./Websocket/PointInterface";
|
import { PointInterface } from "./Websocket/PointInterface";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "../Model/Zone";
|
||||||
import { Movable } from "_Model/Movable";
|
import { Movable } from "../Model/Movable";
|
||||||
import { PositionNotifier } from "_Model/PositionNotifier";
|
import { PositionNotifier } from "../Model/PositionNotifier";
|
||||||
import { ServerDuplexStream } from "grpc";
|
import { ServerDuplexStream } from "grpc";
|
||||||
import {
|
import {
|
||||||
BatchMessage,
|
BatchMessage,
|
||||||
@ -14,7 +14,7 @@ import {
|
|||||||
SetPlayerDetailsMessage,
|
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";
|
||||||
import { BoolValue, UInt32Value } from "google-protobuf/google/protobuf/wrappers_pb";
|
import { BoolValue, UInt32Value } from "google-protobuf/google/protobuf/wrappers_pb";
|
||||||
|
|
||||||
export type UserSocket = ServerDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
export type UserSocket = ServerDuplexStream<PusherToBackMessage, ServerToClientMessage>;
|
||||||
@ -32,6 +32,7 @@ export class User implements Movable {
|
|||||||
private position: PointInterface,
|
private position: PointInterface,
|
||||||
public silent: boolean,
|
public silent: boolean,
|
||||||
private positionNotifier: PositionNotifier,
|
private positionNotifier: PositionNotifier,
|
||||||
|
private away: boolean,
|
||||||
public readonly socket: UserSocket,
|
public readonly socket: UserSocket,
|
||||||
public readonly tags: string[],
|
public readonly tags: string[],
|
||||||
public readonly visitCardUrl: string | null,
|
public readonly visitCardUrl: string | null,
|
||||||
@ -89,6 +90,10 @@ export class User implements Movable {
|
|||||||
return this.outlineColor;
|
return this.outlineColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isAway(): boolean {
|
||||||
|
return this.away;
|
||||||
|
}
|
||||||
|
|
||||||
get following(): User | undefined {
|
get following(): User | undefined {
|
||||||
return this._following;
|
return this._following;
|
||||||
}
|
}
|
||||||
@ -129,6 +134,11 @@ export class User implements Movable {
|
|||||||
}
|
}
|
||||||
this.voiceIndicatorShown = details.getShowvoiceindicator()?.getValue();
|
this.voiceIndicatorShown = details.getShowvoiceindicator()?.getValue();
|
||||||
|
|
||||||
|
const away = details.getAway();
|
||||||
|
if (away) {
|
||||||
|
this.away = away.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
const playerDetails = new SetPlayerDetailsMessage();
|
const playerDetails = new SetPlayerDetailsMessage();
|
||||||
|
|
||||||
if (this.outlineColor !== undefined) {
|
if (this.outlineColor !== undefined) {
|
||||||
@ -137,6 +147,9 @@ export class User implements Movable {
|
|||||||
if (this.voiceIndicatorShown !== undefined) {
|
if (this.voiceIndicatorShown !== undefined) {
|
||||||
playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown));
|
playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown));
|
||||||
}
|
}
|
||||||
|
if (details.getAway() !== undefined) {
|
||||||
|
playerDetails.setAway(new BoolValue().setValue(this.away));
|
||||||
|
}
|
||||||
|
|
||||||
this.positionNotifier.updatePlayerDetails(this, playerDetails);
|
this.positionNotifier.updatePlayerDetails(this, playerDetails);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isItemEventMessageInterface = new tg.IsInterface()
|
export const isItemEventMessageInterface = z.object({
|
||||||
.withProperties({
|
itemId: z.number(),
|
||||||
itemId: tg.isNumber,
|
event: z.string(),
|
||||||
event: tg.isString,
|
state: z.unknown(),
|
||||||
state: tg.isUnknown,
|
parameters: z.unknown(),
|
||||||
parameters: tg.isUnknown,
|
});
|
||||||
})
|
|
||||||
.get();
|
export type ItemEventMessageInterface = z.infer<typeof isItemEventMessageInterface>;
|
||||||
export type ItemEventMessageInterface = tg.GuardedType<typeof isItemEventMessageInterface>;
|
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
/*export interface PointInterface {
|
export const isPointInterface = z.object({
|
||||||
readonly x: number;
|
x: z.number(),
|
||||||
readonly y: number;
|
y: z.number(),
|
||||||
readonly direction: string;
|
direction: z.string(),
|
||||||
readonly moving: boolean;
|
moving: z.boolean(),
|
||||||
}*/
|
});
|
||||||
|
|
||||||
export const isPointInterface = new tg.IsInterface()
|
export type PointInterface = z.infer<typeof isPointInterface>;
|
||||||
.withProperties({
|
|
||||||
x: tg.isNumber,
|
|
||||||
y: tg.isNumber,
|
|
||||||
direction: tg.isString,
|
|
||||||
moving: tg.isBoolean,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
export type PointInterface = tg.GuardedType<typeof isPointInterface>;
|
|
||||||
|
@ -5,10 +5,10 @@ import {
|
|||||||
PointMessage,
|
PointMessage,
|
||||||
PositionMessage,
|
PositionMessage,
|
||||||
} from "../../Messages/generated/messages_pb";
|
} from "../../Messages/generated/messages_pb";
|
||||||
import { CharacterLayer } from "_Model/Websocket/CharacterLayer";
|
import { CharacterLayer } from "../../Model/Websocket/CharacterLayer";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import { ItemEventMessageInterface } from "_Model/Websocket/ItemEventMessage";
|
import { ItemEventMessageInterface } from "../../Model/Websocket/ItemEventMessage";
|
||||||
import { PositionInterface } from "_Model/PositionInterface";
|
import { PositionInterface } from "../../Model/PositionInterface";
|
||||||
|
|
||||||
export class ProtobufUtils {
|
export class ProtobufUtils {
|
||||||
public static toPositionMessage(point: PointInterface): PositionMessage {
|
public static toPositionMessage(point: PointInterface): PositionMessage {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { User } from "./User";
|
import { User } from "./User";
|
||||||
import { PositionInterface } from "_Model/PositionInterface";
|
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";
|
||||||
@ -71,6 +71,7 @@ export class Zone {
|
|||||||
/**
|
/**
|
||||||
* Notify listeners of this zone that this user entered
|
* Notify listeners of this zone that this user entered
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
private notifyEnter(thing: Movable, oldZone: Zone | null, position: PositionInterface) {
|
private notifyEnter(thing: Movable, oldZone: Zone | null, position: PositionInterface) {
|
||||||
for (const listener of this.listeners) {
|
for (const listener of this.listeners) {
|
||||||
this.onEnters(thing, oldZone, listener);
|
this.onEnters(thing, oldZone, listener);
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
EmptyMessage,
|
EmptyMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
PlayGlobalMessage,
|
|
||||||
PusherToBackMessage,
|
PusherToBackMessage,
|
||||||
QueryJitsiJwtMessage,
|
QueryJitsiJwtMessage,
|
||||||
RefreshRoomPromptMessage,
|
RefreshRoomPromptMessage,
|
||||||
|
@ -18,12 +18,21 @@ class AdminApi {
|
|||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isMapDetailsData(res.data) && !isRoomRedirect(res.data)) {
|
const mapDetailData = isMapDetailsData.safeParse(res.data);
|
||||||
console.error("Unexpected answer from the /api/map admin endpoint.", res.data);
|
const roomRedirect = isRoomRedirect.safeParse(res.data);
|
||||||
throw new Error("Unexpected answer from the /api/map admin endpoint.");
|
|
||||||
|
if (mapDetailData.success) {
|
||||||
|
return mapDetailData.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
if (roomRedirect.success) {
|
||||||
|
return roomRedirect.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(mapDetailData.error.issues);
|
||||||
|
console.error(roomRedirect.error.issues);
|
||||||
|
console.error("Unexpected answer from the /api/map admin endpoint.", res.data);
|
||||||
|
throw new Error("Unexpected answer from the /api/map admin endpoint.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
BatchMessage,
|
|
||||||
BatchToPusherMessage,
|
BatchToPusherMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
@ -7,7 +6,7 @@ import {
|
|||||||
SubToPusherMessage,
|
SubToPusherMessage,
|
||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { UserSocket } from "_Model/User";
|
import { UserSocket } from "../Model/User";
|
||||||
import { RoomSocket, ZoneSocket } from "../RoomManager";
|
import { RoomSocket, ZoneSocket } from "../RoomManager";
|
||||||
|
|
||||||
function getMessageFromError(error: unknown): string {
|
function getMessageFromError(error: unknown): string {
|
||||||
|
@ -4,10 +4,12 @@ import { VariablesRepositoryInterface } from "./VariablesRepositoryInterface";
|
|||||||
* Mock class in charge of NOT saving/loading variables from the data store
|
* Mock class in charge of NOT saving/loading variables from the data store
|
||||||
*/
|
*/
|
||||||
export class VoidVariablesRepository implements VariablesRepositoryInterface {
|
export class VoidVariablesRepository implements VariablesRepositoryInterface {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
loadVariables(roomUrl: string): Promise<{ [key: string]: string }> {
|
loadVariables(roomUrl: string): Promise<{ [key: string]: string }> {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
saveVariable(roomUrl: string, key: string, value: string): Promise<number> {
|
saveVariable(roomUrl: string, key: string, value: string): Promise<number> {
|
||||||
return Promise.resolve(0);
|
return Promise.resolve(0);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import { GameRoom } from "../Model/GameRoom";
|
|||||||
import {
|
import {
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
ItemStateMessage,
|
ItemStateMessage,
|
||||||
PlayGlobalMessage,
|
|
||||||
PointMessage,
|
PointMessage,
|
||||||
RoomJoinedMessage,
|
RoomJoinedMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
@ -35,12 +34,10 @@ import {
|
|||||||
FollowAbortMessage,
|
FollowAbortMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
SubToPusherRoomMessage,
|
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage,
|
||||||
PlayerDetailsUpdatedMessage,
|
PlayerDetailsUpdatedMessage,
|
||||||
GroupUsersUpdateMessage,
|
GroupUsersUpdateMessage,
|
||||||
LockGroupPromptMessage,
|
LockGroupPromptMessage,
|
||||||
RoomMessage,
|
|
||||||
} 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";
|
||||||
@ -60,9 +57,9 @@ import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
|||||||
import { clientEventsEmitter } from "./ClientEventsEmitter";
|
import { clientEventsEmitter } from "./ClientEventsEmitter";
|
||||||
import { gaugeManager } from "./GaugeManager";
|
import { gaugeManager } from "./GaugeManager";
|
||||||
import { RoomSocket, ZoneSocket } from "../RoomManager";
|
import { RoomSocket, ZoneSocket } from "../RoomManager";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "../Model/Zone";
|
||||||
import Debug from "debug";
|
import Debug from "debug";
|
||||||
import { Admin } from "_Model/Admin";
|
import { Admin } from "../Model/Admin";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
|
||||||
const debug = Debug("sockermanager");
|
const debug = Debug("sockermanager");
|
||||||
@ -331,6 +328,7 @@ export class SocketManager {
|
|||||||
userJoinedZoneMessage.setUserid(thing.id);
|
userJoinedZoneMessage.setUserid(thing.id);
|
||||||
userJoinedZoneMessage.setUseruuid(thing.uuid);
|
userJoinedZoneMessage.setUseruuid(thing.uuid);
|
||||||
userJoinedZoneMessage.setName(thing.name);
|
userJoinedZoneMessage.setName(thing.name);
|
||||||
|
userJoinedZoneMessage.setAway(thing.isAway());
|
||||||
userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
|
userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
|
||||||
userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));
|
userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));
|
||||||
userJoinedZoneMessage.setFromzone(this.toProtoZone(fromZone));
|
userJoinedZoneMessage.setFromzone(this.toProtoZone(fromZone));
|
||||||
@ -658,6 +656,7 @@ export class SocketManager {
|
|||||||
userJoinedMessage.setUserid(thing.id);
|
userJoinedMessage.setUserid(thing.id);
|
||||||
userJoinedMessage.setUseruuid(thing.uuid);
|
userJoinedMessage.setUseruuid(thing.uuid);
|
||||||
userJoinedMessage.setName(thing.name);
|
userJoinedMessage.setName(thing.name);
|
||||||
|
userJoinedMessage.setAway(thing.isAway());
|
||||||
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
|
userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers));
|
||||||
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));
|
userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition()));
|
||||||
if (thing.visitCardUrl) {
|
if (thing.visitCardUrl) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* Handles variables shared between the scripting API and the server.
|
* Handles variables shared between the scripting API and the server.
|
||||||
*/
|
*/
|
||||||
import { ITiledMap, ITiledMapLayer, ITiledMapObject } from "@workadventure/tiled-map-type-guard/dist";
|
import { ITiledMap, ITiledMapLayer, ITiledMapObject } from "@workadventure/tiled-map-type-guard/dist";
|
||||||
import { User } from "_Model/User";
|
import { User } from "../Model/User";
|
||||||
import { variablesRepository } from "./Repository/VariablesRepository";
|
import { variablesRepository } from "./Repository/VariablesRepository";
|
||||||
import { redisClient } from "./RedisClient";
|
import { redisClient } from "./RedisClient";
|
||||||
import { VariableError } from "./VariableError";
|
import { VariableError } from "./VariableError";
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import "jasmine";
|
import "jasmine";
|
||||||
import { ConnectCallback, DisconnectCallback, GameRoom } from "../src/Model/GameRoom";
|
import { ConnectCallback, DisconnectCallback, GameRoom } from "../src/Model/GameRoom";
|
||||||
import { Point } from "../src/Model/Websocket/MessageUserPosition";
|
import { Point } from "../src/Model/Websocket/MessageUserPosition";
|
||||||
import { Group } from "../src/Model/Group";
|
import { Group } from "../src/Model/Group";
|
||||||
import { User, UserSocket } from "_Model/User";
|
import { User, UserSocket } from "../src/Model/User";
|
||||||
import { JoinRoomMessage, PositionMessage } from "../src/Messages/generated/messages_pb";
|
import { JoinRoomMessage, PositionMessage } from "../src/Messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import { EmoteCallback } from "_Model/Zone";
|
import { EmoteCallback } from "../src/Model/Zone";
|
||||||
|
|
||||||
function createMockUser(userId: number): User {
|
function createMockUser(userId: number): User {
|
||||||
return {
|
return {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { arrayIntersect } from "../src/Services/ArrayHelper";
|
|
||||||
import { mapFetcher } from "../src/Services/MapFetcher";
|
import { mapFetcher } from "../src/Services/MapFetcher";
|
||||||
|
|
||||||
describe("MapFetcher", () => {
|
describe("MapFetcher", () => {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import "jasmine";
|
import "jasmine";
|
||||||
import { PositionNotifier } from "../src/Model/PositionNotifier";
|
import { PositionNotifier } from "../src/Model/PositionNotifier";
|
||||||
import { User, UserSocket } from "../src/Model/User";
|
import { User, UserSocket } from "../src/Model/User";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "../src/Model/Zone";
|
||||||
import { Movable } from "_Model/Movable";
|
import { Movable } from "../src/Model/Movable";
|
||||||
import { PositionInterface } from "_Model/PositionInterface";
|
import { PositionInterface } from "../src/Model/PositionInterface";
|
||||||
import { ZoneSocket } from "../src/RoomManager";
|
import { ZoneSocket } from "../src/RoomManager";
|
||||||
|
|
||||||
describe("PositionNotifier", () => {
|
describe("PositionNotifier", () => {
|
||||||
@ -41,6 +42,7 @@ describe("PositionNotifier", () => {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
positionNotifier,
|
positionNotifier,
|
||||||
|
false,
|
||||||
{} as UserSocket,
|
{} as UserSocket,
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
@ -60,6 +62,7 @@ describe("PositionNotifier", () => {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
positionNotifier,
|
positionNotifier,
|
||||||
|
false,
|
||||||
{} as UserSocket,
|
{} as UserSocket,
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
@ -149,6 +152,7 @@ describe("PositionNotifier", () => {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
positionNotifier,
|
positionNotifier,
|
||||||
|
false,
|
||||||
{} as UserSocket,
|
{} as UserSocket,
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
@ -168,6 +172,7 @@ describe("PositionNotifier", () => {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
positionNotifier,
|
positionNotifier,
|
||||||
|
false,
|
||||||
{} as UserSocket,
|
{} as UserSocket,
|
||||||
[],
|
[],
|
||||||
null,
|
null,
|
||||||
|
@ -3,18 +3,18 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
"target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
@ -23,50 +23,50 @@
|
|||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||||
"noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ // Disabled because of sifrr server that is monkey patching HttpResponse
|
"noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ // Disabled because of sifrr server that is monkey patching HttpResponse
|
||||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
/* Additional Checks */
|
/* Additional Checks */
|
||||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": ".", /* Base directory to resolve non-absolute module names. */
|
||||||
"paths": {
|
// "paths": {
|
||||||
"_Controller/*": ["src/Controller/*"],
|
// "_Controller/*": [
|
||||||
"_Model/*": ["src/Model/*"],
|
// "src/Controller/*"
|
||||||
"_Enum/*": ["src/Enum/*"]
|
// ],
|
||||||
}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "_Model/*": [
|
||||||
|
// "src/Model/*"
|
||||||
|
// ],
|
||||||
|
// "_Enum/*": [
|
||||||
|
// "src/Enum/*"
|
||||||
|
// ]
|
||||||
|
// }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
// "types": [], /* Type declaration files to be included in compilation. */
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
|
||||||
/* Source Map Options */
|
/* Source Map Options */
|
||||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
|
|
||||||
/* Experimental Options */
|
/* Experimental Options */
|
||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
|
||||||
/* Advanced Options */
|
/* Advanced Options */
|
||||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -981,7 +981,7 @@ gauge@^3.0.0:
|
|||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
wide-align "^1.1.2"
|
wide-align "^1.1.2"
|
||||||
|
|
||||||
generic-type-guard@^3.2.0, generic-type-guard@^3.4.1:
|
generic-type-guard@^3.4.1:
|
||||||
version "3.5.0"
|
version "3.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/generic-type-guard/-/generic-type-guard-3.5.0.tgz#39de9f8fceee65d79e7540959f0e7b23210c07b6"
|
resolved "https://registry.yarnpkg.com/generic-type-guard/-/generic-type-guard-3.5.0.tgz#39de9f8fceee65d79e7540959f0e7b23210c07b6"
|
||||||
integrity sha512-OpgXv/sbRobhFboaSyN/Tsh97Sxt5pcfLLxCiYZgYIIWFFp+kn2EzAXiaQZKEVRlq1rOE/zh8cYhJXEwplbJiQ==
|
integrity sha512-OpgXv/sbRobhFboaSyN/Tsh97Sxt5pcfLLxCiYZgYIIWFFp+kn2EzAXiaQZKEVRlq1rOE/zh8cYhJXEwplbJiQ==
|
||||||
@ -1459,9 +1459,9 @@ minimatch@^3.0.4:
|
|||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
minimist@^1.2.5:
|
minimist@^1.2.5:
|
||||||
version "1.2.5"
|
version "1.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||||
|
|
||||||
minipass@^3.0.0:
|
minipass@^3.0.0:
|
||||||
version "3.1.6"
|
version "3.1.6"
|
||||||
@ -2259,7 +2259,7 @@ yn@3.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
|
|
||||||
zod@^3.12.0:
|
zod@^3.14.3:
|
||||||
version "3.14.2"
|
version "3.14.3"
|
||||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.2.tgz#0b4ed79085c471adce0e7f2c0a4fbb5ddc516ba2"
|
resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.3.tgz#60e86341c05883c281fe96a0e79acea48a09f123"
|
||||||
integrity sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw==
|
integrity sha512-OzwRCSXB1+/8F6w6HkYHdbuWysYWnAF4fkRgKDcSFc54CE+Sv0rHXKfeNUReGCrHukm1LNpi6AYeXotznhYJbQ==
|
||||||
|
6
benchmark/package-lock.json
generated
6
benchmark/package-lock.json
generated
@ -369,9 +369,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
|
@ -268,8 +268,8 @@ minimatch@^3.0.4:
|
|||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
minimist@^1.1.3, minimist@^1.2.5:
|
minimist@^1.1.3, minimist@^1.2.5:
|
||||||
version "1.2.5"
|
version "1.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||||
|
|
||||||
mkdirp@^1.0.4:
|
mkdirp@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
|
@ -12,7 +12,7 @@ services:
|
|||||||
- --entryPoints.websecure.address=:${HTTPS_PORT}
|
- --entryPoints.websecure.address=:${HTTPS_PORT}
|
||||||
# HTTP challenge
|
# HTTP challenge
|
||||||
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
- --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
|
||||||
- --certificatesresolvers.myresolver.acme.storage=/acme.json
|
- --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
|
||||||
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
- --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
|
||||||
# Let's Encrypt's staging server
|
# Let's Encrypt's staging server
|
||||||
# uncomment during testing to avoid rate limiting
|
# uncomment during testing to avoid rate limiting
|
||||||
@ -22,7 +22,7 @@ services:
|
|||||||
- "${HTTPS_PORT}:443"
|
- "${HTTPS_PORT}:443"
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ${DATA_DIR}/letsencrypt/acme.json:/acme.json
|
- ${DATA_DIR}/letsencrypt/:/letsencrypt/
|
||||||
restart: ${RESTART_POLICY}
|
restart: ${RESTART_POLICY}
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,6 +64,11 @@
|
|||||||
"ADMIN_API_URL": adminUrl,
|
"ADMIN_API_URL": adminUrl,
|
||||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||||
"ADMIN_SOCKETS_TOKEN": env.ADMIN_SOCKETS_TOKEN,
|
"ADMIN_SOCKETS_TOKEN": env.ADMIN_SOCKETS_TOKEN,
|
||||||
|
"OPID_CLIENT_ID": "auth-code-client",
|
||||||
|
"OPID_CLIENT_SECRET": "mySecretHydraWA2022",
|
||||||
|
"OPID_CLIENT_ISSUER": "https://publichydra-"+url,
|
||||||
|
"OPID_CLIENT_REDIRECT_URL": "https://"+url+"/oauth/hydra",
|
||||||
|
"OPID_LOGIN_SCREEN_PROVIDER": "https://pusher-"+url+"/login-screen",
|
||||||
} else {})
|
} else {})
|
||||||
},
|
},
|
||||||
"front": {
|
"front": {
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"baseUrl": ".",
|
//"baseUrl": ".",
|
||||||
"paths": {},
|
//"paths": {},
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"baseUrl": ".",
|
//"baseUrl": ".",
|
||||||
/**
|
/**
|
||||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||||
* Disable checkJs if you'd like to use dynamic types in JS.
|
* Disable checkJs if you'd like to use dynamic types in JS.
|
||||||
@ -15,10 +15,23 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"~/*": ["./src/*"],
|
"~/*": [
|
||||||
"@wa-preload-local-app": ["../electron/src/preload-local-app/types.ts"],
|
"./src/*"
|
||||||
|
],
|
||||||
|
"@wa-preload-local-app": [
|
||||||
|
"../electron/src/preload-local-app/types.ts"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
|
"include": [
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"src/**/*.d.ts",
|
||||||
}
|
"src/**/*.ts",
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.svelte"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.node.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -114,7 +114,6 @@ services:
|
|||||||
#APACHE_EXTENSION_HEADERS: 1
|
#APACHE_EXTENSION_HEADERS: 1
|
||||||
STARTUP_COMMAND_0: sudo a2enmod headers
|
STARTUP_COMMAND_0: sudo a2enmod headers
|
||||||
STARTUP_COMMAND_1: yarn install
|
STARTUP_COMMAND_1: yarn install
|
||||||
STARTUP_COMMAND_2: yarn run dev &
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./maps:/var/www/html
|
- ./maps:/var/www/html
|
||||||
labels:
|
labels:
|
||||||
|
@ -9,7 +9,7 @@ The [scripting API](https://workadventu.re/map-building/scripting.md) allows map
|
|||||||
|
|
||||||
The philosophy behind WorkAdventure is to build a platform that is as open as possible. Part of this strategy is to
|
The philosophy behind WorkAdventure is to build a platform that is as open as possible. Part of this strategy is to
|
||||||
offer map developers the ability to turn a WorkAdventures map into something unexpected, using the API. For instance,
|
offer map developers the ability to turn a WorkAdventures map into something unexpected, using the API. For instance,
|
||||||
you could use it to develop games (we have seen a PacMan and a mine-sweeper on WorkAdventure!)
|
you could use it to develop games (we have seen a PacMan and a mine-sweeper on WorkAdventure!)
|
||||||
|
|
||||||
We started working on the WorkAdventure scripting API with this in mind, but at some point, maybe you will find that
|
We started working on the WorkAdventure scripting API with this in mind, but at some point, maybe you will find that
|
||||||
a feature is missing in the API. This article is here to explain to you how to add this feature.
|
a feature is missing in the API. This article is here to explain to you how to add this feature.
|
||||||
@ -35,7 +35,7 @@ directly access Phaser objects (Phaser is the game engine used in WorkAdventure)
|
|||||||
can contribute a map, we cannot allow anyone to run any code in the scope of the WorkAdventure server (that would be
|
can contribute a map, we cannot allow anyone to run any code in the scope of the WorkAdventure server (that would be
|
||||||
a huge XSS security flaw).
|
a huge XSS security flaw).
|
||||||
|
|
||||||
Instead, the only way the script can interact with WorkAdventure is by sending messages using the
|
Instead, the only way the script can interact with WorkAdventure is by sending messages using the
|
||||||
[postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).
|
[postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).
|
||||||
|
|
||||||
![](images/scripting_2.svg)
|
![](images/scripting_2.svg)
|
||||||
@ -103,14 +103,14 @@ All the other files dedicated to the iframe API are located in the `src/Api/ifra
|
|||||||
|
|
||||||
## Utility functions to exchange messages
|
## Utility functions to exchange messages
|
||||||
|
|
||||||
In the example above, we already saw you can easily send a message from the iframe to WorkAdventure using the
|
In the example above, we already saw you can easily send a message from the iframe to WorkAdventure using the
|
||||||
[`sendToWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L11-L13) utility function.
|
[`sendToWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L11-L13) utility function.
|
||||||
|
|
||||||
Of course, messaging can go the other way around and WorkAdventure can also send messages to the iframes.
|
Of course, messaging can go the other way around and WorkAdventure can also send messages to the iframes.
|
||||||
We use the [`IFrameListener.postMessage`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/IframeListener.ts#L455-L459) function for this.
|
We use the [`IFrameListener.postMessage`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/IframeListener.ts#L455-L459) function for this.
|
||||||
|
|
||||||
Finally, there is a last type of utility function (a quite powerful one). It is quite common to need to call a function
|
Finally, there is a last type of utility function (a quite powerful one). It is quite common to need to call a function
|
||||||
from the iframe in WorkAdventure, and to expect a response. For those use cases, the iframe API comes with a
|
from the iframe in WorkAdventure, and to expect a response. For those use cases, the iframe API comes with a
|
||||||
[`queryWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L30-L49) utility function.
|
[`queryWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L30-L49) utility function.
|
||||||
|
|
||||||
## Types
|
## Types
|
||||||
@ -122,7 +122,7 @@ Indeed, Typescript interfaces only exist at compilation time but cannot be enfor
|
|||||||
is an entry point to WorkAdventure, and as with any entry point, data must be checked (otherwise, a hacker could
|
is an entry point to WorkAdventure, and as with any entry point, data must be checked (otherwise, a hacker could
|
||||||
send specially crafted JSON packages to try to hack WA).
|
send specially crafted JSON packages to try to hack WA).
|
||||||
|
|
||||||
In WorkAdventure, we use the [generic-type-guard](https://github.com/mscharley/generic-type-guard) package. This package
|
In WorkAdventure, we use the [zod](https://github.com/colinhacks/zod) package. This package
|
||||||
allows us to create interfaces AND custom type guards in one go.
|
allows us to create interfaces AND custom type guards in one go.
|
||||||
|
|
||||||
Let's go back at our example. Let's have a look at the JSON message sent when we want to send a chat message from the API:
|
Let's go back at our example. Let's have a look at the JSON message sent when we want to send a chat message from the API:
|
||||||
@ -140,21 +140,20 @@ sendToWorkadventure({
|
|||||||
The "data" part of the message is defined in `front/src/Api/Events/ChatEvent.ts`:
|
The "data" part of the message is defined in `front/src/Api/Events/ChatEvent.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isChatEvent = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
author: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isChatEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
message: tg.isString,
|
|
||||||
author: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type ChatEvent = tg.GuardedType<typeof isChatEvent>;
|
export type ChatEvent = z.infer<typeof isChatEvent>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Using the generic-type-guard library, we start by writing a type guard function (`isChatEvent`).
|
Using the zod library, we start by writing a type guard function (`isChatEvent`).
|
||||||
From this type guard, the library can automatically generate the `ChatEvent` type that we can refer in our code.
|
From this type guard, the library can automatically generate the `ChatEvent` type that we can refer in our code.
|
||||||
|
|
||||||
The advantage of this technique is that, **at runtime**, WorkAdventure can verify that the JSON message received
|
The advantage of this technique is that, **at runtime**, WorkAdventure can verify that the JSON message received
|
||||||
@ -212,7 +211,7 @@ export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
|||||||
If you want to add a new "query" (if you are using the `queryWorkadventure` utility function), you will need to
|
If you want to add a new "query" (if you are using the `queryWorkadventure` utility function), you will need to
|
||||||
define the type of the query and the type of the response.
|
define the type of the query and the type of the response.
|
||||||
|
|
||||||
The signature of `queryWorkadventure` is:
|
The signature of `queryWorkadventure` is:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function queryWorkadventure<T extends keyof IframeQueryMap>(
|
function queryWorkadventure<T extends keyof IframeQueryMap>(
|
||||||
@ -250,12 +249,12 @@ Here is a sample:
|
|||||||
```typescript
|
```typescript
|
||||||
iframeListener.registerAnswerer("openCoWebsite", (openCoWebsiteEvent, source) => {
|
iframeListener.registerAnswerer("openCoWebsite", (openCoWebsiteEvent, source) => {
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
return /*...*/;
|
return /*...*/;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
The `registerAnswerer` callback is passed the event, and should return a response (or a promise to the response) in the expected format
|
The `registerAnswerer` callback is passed the event, and should return a response (or a promise to the response) in the expected format
|
||||||
(the one you defined in the `answer` key of `iframeQueryMapTypeGuards`).
|
(the one you defined in the `answer` key of `iframeQueryMapTypeGuards`).
|
||||||
|
|
||||||
Important:
|
Important:
|
||||||
|
@ -9,7 +9,7 @@ In order to build your own map for WorkAdventure, you need:
|
|||||||
* "tiles" (i.e. images) to create your map
|
* "tiles" (i.e. images) to create your map
|
||||||
* a web-server to serve your map
|
* a web-server to serve your map
|
||||||
|
|
||||||
WorkAdventure comes with a "map starter kit" that we recommend using to start designing your map quickly. It contains **a good default tileset** for building an office and it proposes to **use Github static pages as a web-server** which is both free and performant. It also comes with a local webserver for testing purpose and with Typescript support (if you are looking to use the [map scripting API]({{url('/map-building/scripting')}}).
|
WorkAdventure comes with a "map starter kit" that we recommend using to start designing your map quickly. It contains **a good default tileset** for building an office and it proposes to **use Github static pages as a web-server** which is both free and performant. It also comes with a local webserver for testing purpose and with Typescript support (if you are looking to use the [map scripting API](scripting.md).
|
||||||
|
|
||||||
{.alert.alert-info}
|
{.alert.alert-info}
|
||||||
If you are looking to host your maps on your own webserver, be sure to read the [Self-hosting your map](hosting.md) guide.
|
If you are looking to host your maps on your own webserver, be sure to read the [Self-hosting your map](hosting.md) guide.
|
||||||
|
@ -27,8 +27,8 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.svelte"],
|
"files": ["*.svelte"],
|
||||||
"processor": "svelte3/svelte3"
|
"processor": "svelte3/svelte3"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
@ -36,6 +36,7 @@ module.exports = {
|
|||||||
"eol-last": ["error", "always"],
|
"eol-last": ["error", "always"],
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
"no-throw-literal": "error",
|
"no-throw-literal": "error",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["error"],
|
||||||
// TODO: remove those ignored rules and write a stronger code!
|
// TODO: remove those ignored rules and write a stronger code!
|
||||||
"@typescript-eslint/no-unsafe-call": "off",
|
"@typescript-eslint/no-unsafe-call": "off",
|
||||||
"@typescript-eslint/restrict-plus-operands": "off",
|
"@typescript-eslint/restrict-plus-operands": "off",
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
"deep-copy-ts": "^0.5.0",
|
"deep-copy-ts": "^0.5.0",
|
||||||
"dompurify" : "^2.3.6",
|
"dompurify" : "^2.3.6",
|
||||||
"easystarjs": "^0.4.4",
|
"easystarjs": "^0.4.4",
|
||||||
"generic-type-guard": "^3.4.2",
|
|
||||||
"google-protobuf": "^3.13.0",
|
"google-protobuf": "^3.13.0",
|
||||||
"phaser": "3.55.1",
|
"phaser": "3.55.1",
|
||||||
"phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254",
|
"phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254",
|
||||||
@ -63,7 +62,7 @@
|
|||||||
"ts-proto": "^1.96.0",
|
"ts-proto": "^1.96.0",
|
||||||
"typesafe-i18n": "^2.59.0",
|
"typesafe-i18n": "^2.59.0",
|
||||||
"uuidv4": "^6.2.10",
|
"uuidv4": "^6.2.10",
|
||||||
"zod": "^3.11.6"
|
"zod": "^3.14.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "run-p templater serve watch-iframe-api svelte-check-watch typesafe-i18n-watch",
|
"start": "run-p templater serve watch-iframe-api svelte-check-watch typesafe-i18n-watch",
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isActionsMenuActionClickedEvent = new tg.IsInterface()
|
export const isActionsMenuActionClickedEvent = z.object({
|
||||||
.withProperties({
|
id: z.number(),
|
||||||
id: tg.isNumber,
|
actionName: z.string(),
|
||||||
actionName: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type ActionsMenuActionClickedEvent = tg.GuardedType<typeof isActionsMenuActionClickedEvent>;
|
export type ActionsMenuActionClickedEvent = z.infer<typeof isActionsMenuActionClickedEvent>;
|
||||||
|
|
||||||
export type ActionsMenuActionClickedEventCallback = (event: ActionsMenuActionClickedEvent) => void;
|
export type ActionsMenuActionClickedEventCallback = (event: ActionsMenuActionClickedEvent) => void;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isAddActionsMenuKeyToRemotePlayerEvent = new tg.IsInterface()
|
export const isAddActionsMenuKeyToRemotePlayerEvent = z.object({
|
||||||
.withProperties({
|
id: z.number(),
|
||||||
id: tg.isNumber,
|
actionKey: z.string(),
|
||||||
actionKey: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type AddActionsMenuKeyToRemotePlayerEvent = tg.GuardedType<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
export type AddActionsMenuKeyToRemotePlayerEvent = z.infer<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
||||||
|
|
||||||
export type AddActionsMenuKeyToRemotePlayerEventCallback = (event: AddActionsMenuKeyToRemotePlayerEvent) => void;
|
export type AddActionsMenuKeyToRemotePlayerEventCallback = (event: AddActionsMenuKeyToRemotePlayerEvent) => void;
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isButtonClickedEvent = z.object({
|
||||||
|
popupId: z.number(),
|
||||||
|
buttonId: z.number(),
|
||||||
|
input: z.boolean(),
|
||||||
|
inputValue: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isButtonClickedEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
popupId: tg.isNumber,
|
|
||||||
buttonId: tg.isNumber,
|
|
||||||
input: tg.isBoolean,
|
|
||||||
inputValue: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property.
|
* A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property.
|
||||||
*/
|
*/
|
||||||
export type ButtonClickedEvent = tg.GuardedType<typeof isButtonClickedEvent>;
|
export type ButtonClickedEvent = z.infer<typeof isButtonClickedEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isCameraFollowPlayerEvent = z.object({
|
||||||
|
smooth: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isCameraFollowPlayerEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
smooth: tg.isBoolean,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to make the camera follow player.
|
* A message sent from the iFrame to the game to make the camera follow player.
|
||||||
*/
|
*/
|
||||||
export type CameraFollowPlayerEvent = tg.GuardedType<typeof isCameraFollowPlayerEvent>;
|
export type CameraFollowPlayerEvent = z.infer<typeof isCameraFollowPlayerEvent>;
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isCameraSetEvent = z.object({
|
||||||
|
x: z.number(),
|
||||||
|
y: z.number(),
|
||||||
|
width: z.optional(z.number()),
|
||||||
|
height: z.optional(z.number()),
|
||||||
|
lock: z.boolean(),
|
||||||
|
smooth: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isCameraSetEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
x: tg.isNumber,
|
|
||||||
y: tg.isNumber,
|
|
||||||
width: tg.isOptional(tg.isNumber),
|
|
||||||
height: tg.isOptional(tg.isNumber),
|
|
||||||
lock: tg.isBoolean,
|
|
||||||
smooth: tg.isBoolean,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to change the camera position.
|
* A message sent from the iFrame to the game to change the camera position.
|
||||||
*/
|
*/
|
||||||
export type CameraSetEvent = tg.GuardedType<typeof isCameraSetEvent>;
|
export type CameraSetEvent = z.infer<typeof isCameraSetEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isChangeLayerEvent = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isChangeLayerEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
name: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a user enters or leaves a layer.
|
* A message sent from the game to the iFrame when a user enters or leaves a layer.
|
||||||
*/
|
*/
|
||||||
export type ChangeLayerEvent = tg.GuardedType<typeof isChangeLayerEvent>;
|
export type ChangeLayerEvent = z.infer<typeof isChangeLayerEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isChangeZoneEvent = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isChangeZoneEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
name: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a user enters or leaves a zone.
|
* A message sent from the game to the iFrame when a user enters or leaves a zone.
|
||||||
*/
|
*/
|
||||||
export type ChangeZoneEvent = tg.GuardedType<typeof isChangeZoneEvent>;
|
export type ChangeZoneEvent = z.infer<typeof isChangeZoneEvent>;
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isChatEvent = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
author: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isChatEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
message: tg.isString,
|
|
||||||
author: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type ChatEvent = tg.GuardedType<typeof isChatEvent>;
|
export type ChatEvent = z.infer<typeof isChatEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isCloseCoWebsite = new tg.IsInterface()
|
export const isCloseCoWebsite = z.object({
|
||||||
.withProperties({
|
id: z.optional(z.string()),
|
||||||
id: tg.isOptional(tg.isString),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type CloseCoWebsiteEvent = tg.GuardedType<typeof isCloseCoWebsite>;
|
export type CloseCoWebsiteEvent = z.infer<typeof isCloseCoWebsite>;
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { string, z } from "zod";
|
||||||
|
|
||||||
export const isClosePopupEvent = new tg.IsInterface()
|
export const isClosePopupEvent = z.object({
|
||||||
.withProperties({
|
popupId: z.number(),
|
||||||
popupId: tg.isNumber,
|
inputValue: z.string(),
|
||||||
inputValue: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type ClosePopupEvent = tg.GuardedType<typeof isClosePopupEvent>;
|
export type ClosePopupEvent = z.infer<typeof isClosePopupEvent>;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isColorEvent = z.object({
|
||||||
|
red: z.number(),
|
||||||
|
green: z.number(),
|
||||||
|
blue: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
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.
|
* A message sent from the iFrame to the game to dynamically set the outline of the player.
|
||||||
*/
|
*/
|
||||||
export type ColorEvent = tg.GuardedType<typeof isColorEvent>;
|
export type ColorEvent = z.infer<typeof isColorEvent>;
|
||||||
|
@ -1,52 +1,43 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isRectangle = new tg.IsInterface()
|
export const isRectangle = z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
width: z.number(),
|
||||||
width: tg.isNumber,
|
height: z.number(),
|
||||||
height: tg.isNumber,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isEmbeddedWebsiteEvent = new tg.IsInterface()
|
// TODO: make a variation that is all optional (except for the name)
|
||||||
.withProperties({
|
export type Rectangle = z.infer<typeof isRectangle>;
|
||||||
name: tg.isString,
|
|
||||||
})
|
|
||||||
.withOptionalProperties({
|
|
||||||
url: tg.isString,
|
|
||||||
visible: tg.isBoolean,
|
|
||||||
allowApi: tg.isBoolean,
|
|
||||||
allow: tg.isString,
|
|
||||||
x: tg.isNumber,
|
|
||||||
y: tg.isNumber,
|
|
||||||
width: tg.isNumber,
|
|
||||||
height: tg.isNumber,
|
|
||||||
origin: tg.isSingletonStringUnion("player", "map"),
|
|
||||||
scale: tg.isNumber,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isCreateEmbeddedWebsiteEvent = new tg.IsInterface()
|
export const isEmbeddedWebsiteEvent = z.object({
|
||||||
.withProperties({
|
name: z.string(),
|
||||||
name: tg.isString,
|
url: z.optional(z.string()),
|
||||||
url: tg.isString,
|
visible: z.optional(z.boolean()),
|
||||||
position: isRectangle,
|
allowApi: z.optional(z.boolean()),
|
||||||
})
|
allow: z.optional(z.string()),
|
||||||
.withOptionalProperties({
|
x: z.optional(z.number()),
|
||||||
visible: tg.isBoolean,
|
y: z.optional(z.number()),
|
||||||
allowApi: tg.isBoolean,
|
width: z.optional(z.number()),
|
||||||
allow: tg.isString,
|
height: z.optional(z.number()),
|
||||||
origin: tg.isSingletonStringUnion("player", "map"),
|
origin: z.optional(z.enum(["player", "map"])),
|
||||||
scale: tg.isNumber,
|
scale: z.optional(z.number()),
|
||||||
})
|
});
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to modify an embedded website
|
* A message sent from the iFrame to the game to modify an embedded website
|
||||||
*/
|
*/
|
||||||
export type ModifyEmbeddedWebsiteEvent = tg.GuardedType<typeof isEmbeddedWebsiteEvent>;
|
export type ModifyEmbeddedWebsiteEvent = z.infer<typeof isEmbeddedWebsiteEvent>;
|
||||||
|
|
||||||
export type CreateEmbeddedWebsiteEvent = tg.GuardedType<typeof isCreateEmbeddedWebsiteEvent>;
|
export const isCreateEmbeddedWebsiteEvent = z.object({
|
||||||
// TODO: make a variation that is all optional (except for the name)
|
name: z.string(),
|
||||||
export type Rectangle = tg.GuardedType<typeof isRectangle>;
|
url: z.string(),
|
||||||
|
position: isRectangle,
|
||||||
|
visible: z.optional(z.boolean()),
|
||||||
|
allowApi: z.optional(z.boolean()),
|
||||||
|
allow: z.optional(z.string()),
|
||||||
|
origin: z.optional(z.enum(["player", "map"])),
|
||||||
|
scale: z.optional(z.number()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateEmbeddedWebsiteEvent = z.infer<typeof isCreateEmbeddedWebsiteEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isEnterLeaveEvent = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isEnterLeaveEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
name: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property.
|
* A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property.
|
||||||
*/
|
*/
|
||||||
export type EnterLeaveEvent = tg.GuardedType<typeof isEnterLeaveEvent>;
|
export type EnterLeaveEvent = z.infer<typeof isEnterLeaveEvent>;
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isGameStateEvent = z.object({
|
||||||
|
roomId: z.string(),
|
||||||
|
mapUrl: z.string(),
|
||||||
|
nickname: z.string(),
|
||||||
|
language: z.optional(z.string()),
|
||||||
|
uuid: z.optional(z.string()),
|
||||||
|
startLayerName: z.optional(z.string()),
|
||||||
|
tags: z.array(z.string()),
|
||||||
|
variables: z.unknown(), // Todo : Typing
|
||||||
|
playerVariables: z.unknown(), // Todo : Typing
|
||||||
|
userRoomToken: z.optional(z.string()),
|
||||||
|
});
|
||||||
|
|
||||||
export const isGameStateEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
roomId: tg.isString,
|
|
||||||
mapUrl: tg.isString,
|
|
||||||
nickname: tg.isString,
|
|
||||||
language: tg.isUnion(tg.isString, tg.isUndefined),
|
|
||||||
uuid: tg.isUnion(tg.isString, tg.isUndefined),
|
|
||||||
startLayerName: tg.isUnion(tg.isString, tg.isNull),
|
|
||||||
tags: tg.isArray(tg.isString),
|
|
||||||
variables: tg.isObject,
|
|
||||||
playerVariables: tg.isObject,
|
|
||||||
userRoomToken: tg.isUnion(tg.isString, tg.isUndefined),
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when the gameState is received by the script
|
* A message sent from the game to the iFrame when the gameState is received by the script
|
||||||
*/
|
*/
|
||||||
export type GameStateEvent = tg.GuardedType<typeof isGameStateEvent>;
|
export type GameStateEvent = z.infer<typeof isGameStateEvent>;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isGetPropertyEvent = z.object({
|
||||||
|
layerName: z.string(),
|
||||||
|
propertyName: z.string(),
|
||||||
|
propertyValue: z.union([ z.string(), z.number(), z.boolean(), z.undefined() ]),
|
||||||
|
});
|
||||||
|
|
||||||
export const isGetPropertyEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
layerName: tg.isString,
|
|
||||||
propertyName: tg.isString,
|
|
||||||
propertyValue: tg.isUnion(tg.isString, tg.isUnion(tg.isNumber, tg.isUnion(tg.isBoolean, tg.isUndefined))),
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to change the value of the property of the layer
|
* A message sent from the iFrame to the game to change the value of the property of the layer
|
||||||
*/
|
*/
|
||||||
export type GetPropertyEvent = tg.GuardedType<typeof isGetPropertyEvent>;
|
export type GetPropertyEvent = z.infer<typeof isGetPropertyEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isGoToPageEvent = new tg.IsInterface()
|
export const isGoToPageEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type GoToPageEvent = tg.GuardedType<typeof isGoToPageEvent>;
|
export type GoToPageEvent = z.infer<typeof isGoToPageEvent>;
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isHasPlayerMovedEvent = new tg.IsInterface()
|
export const isHasPlayerMovedEvent = z.object({
|
||||||
.withProperties({
|
direction: z.enum(["right", "left", "up", "down"]),
|
||||||
direction: tg.isElementOf("right", "left", "up", "down"),
|
moving: z.boolean(),
|
||||||
moving: tg.isBoolean,
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
oldX: z.optional(z.number()),
|
||||||
oldX: tg.isOptional(tg.isNumber),
|
oldY: z.optional(z.number()),
|
||||||
oldY: tg.isOptional(tg.isNumber),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame to notify a movement from the current player.
|
* A message sent from the game to the iFrame to notify a movement from the current player.
|
||||||
*/
|
*/
|
||||||
export type HasPlayerMovedEvent = tg.GuardedType<typeof isHasPlayerMovedEvent>;
|
export type HasPlayerMovedEvent = z.infer<typeof isHasPlayerMovedEvent>;
|
||||||
|
|
||||||
export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void;
|
export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void;
|
||||||
|
@ -1,45 +1,44 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
import type { ButtonClickedEvent } from "./ButtonClickedEvent";
|
import type { ButtonClickedEvent } from "./ButtonClickedEvent";
|
||||||
import type { ChatEvent } from "./ChatEvent";
|
import { isChatEvent } from "./ChatEvent";
|
||||||
import type { ClosePopupEvent } from "./ClosePopupEvent";
|
import { isClosePopupEvent } from "./ClosePopupEvent";
|
||||||
import type { EnterLeaveEvent } from "./EnterLeaveEvent";
|
import type { EnterLeaveEvent } from "./EnterLeaveEvent";
|
||||||
import type { GoToPageEvent } from "./GoToPageEvent";
|
import { isGoToPageEvent } from "./GoToPageEvent";
|
||||||
import type { LoadPageEvent } from "./LoadPageEvent";
|
import { isLoadPageEvent } from "./LoadPageEvent";
|
||||||
import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent";
|
import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent";
|
||||||
import type { OpenPopupEvent } from "./OpenPopupEvent";
|
import { isOpenPopupEvent } from "./OpenPopupEvent";
|
||||||
import type { OpenTabEvent } from "./OpenTabEvent";
|
import { isOpenTabEvent } from "./OpenTabEvent";
|
||||||
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
import type { UserInputChatEvent } from "./UserInputChatEvent";
|
||||||
import type { LayerEvent } from "./LayerEvent";
|
import { isLayerEvent } from "./LayerEvent";
|
||||||
import type { SetPropertyEvent } from "./setPropertyEvent";
|
import { isSetPropertyEvent } from "./setPropertyEvent";
|
||||||
import type { LoadSoundEvent } from "./LoadSoundEvent";
|
import { isLoadSoundEvent } from "./LoadSoundEvent";
|
||||||
import type { PlaySoundEvent } from "./PlaySoundEvent";
|
import { isPlaySoundEvent } from "./PlaySoundEvent";
|
||||||
|
import { isStopSoundEvent } from "./StopSoundEvent";
|
||||||
import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent";
|
import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent";
|
||||||
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
|
||||||
import type { SetTilesEvent } from "./SetTilesEvent";
|
import { isSetTilesEvent } from "./SetTilesEvent";
|
||||||
import type { SetVariableEvent } from "./SetVariableEvent";
|
import type { SetVariableEvent } from "./SetVariableEvent";
|
||||||
import { isGameStateEvent } from "./GameStateEvent";
|
import { isGameStateEvent } from "./GameStateEvent";
|
||||||
import { isMapDataEvent } from "./MapDataEvent";
|
import { isMapDataEvent } from "./MapDataEvent";
|
||||||
import { isSetVariableEvent } from "./SetVariableEvent";
|
import { isSetVariableEvent } from "./SetVariableEvent";
|
||||||
import type { EmbeddedWebsite } from "../iframe/Room/EmbeddedWebsite";
|
import { isCreateEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent";
|
||||||
import { isCreateEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent";
|
|
||||||
import type { LoadTilesetEvent } from "./LoadTilesetEvent";
|
|
||||||
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
||||||
import type { MessageReferenceEvent } from "./ui/TriggerActionMessageEvent";
|
import type { MessageReferenceEvent } from "./ui/TriggerActionMessageEvent";
|
||||||
import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent";
|
import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent";
|
||||||
import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./ui/MenuRegisterEvent";
|
||||||
import type { ChangeLayerEvent } from "./ChangeLayerEvent";
|
import type { ChangeLayerEvent } from "./ChangeLayerEvent";
|
||||||
import { isPlayerPosition } from "./PlayerPosition";
|
import { isPlayerPosition } from "./PlayerPosition";
|
||||||
import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent";
|
import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent";
|
||||||
import type { ChangeZoneEvent } from "./ChangeZoneEvent";
|
import type { ChangeZoneEvent } from "./ChangeZoneEvent";
|
||||||
import type { CameraSetEvent } from "./CameraSetEvent";
|
import { isCameraSetEvent } from "./CameraSetEvent";
|
||||||
import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
|
import { isCameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
|
||||||
import { isColorEvent } from "./ColorEvent";
|
import { isColorEvent } from "./ColorEvent";
|
||||||
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
|
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
|
||||||
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
|
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
|
||||||
import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent";
|
import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent";
|
||||||
import type { AddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
|
import { isAddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
|
||||||
import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent";
|
import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent";
|
||||||
import type { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
|
import { isRemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||||
import { isGetPropertyEvent } from "./GetPropertyEvent";
|
import { isGetPropertyEvent } from "./GetPropertyEvent";
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
@ -49,45 +48,114 @@ export interface TypedMessageEvent<T> extends MessageEvent {
|
|||||||
/**
|
/**
|
||||||
* List event types sent from an iFrame to WorkAdventure
|
* List event types sent from an iFrame to WorkAdventure
|
||||||
*/
|
*/
|
||||||
export type IframeEventMap = {
|
export const isIframeEventWrapper = z.union([
|
||||||
addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent;
|
z.object({
|
||||||
removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent;
|
type: z.literal("addActionsMenuKeyToRemotePlayer"),
|
||||||
loadPage: LoadPageEvent;
|
data: isAddActionsMenuKeyToRemotePlayerEvent,
|
||||||
chat: ChatEvent;
|
}),
|
||||||
cameraFollowPlayer: CameraFollowPlayerEvent;
|
z.object({
|
||||||
cameraSet: CameraSetEvent;
|
type: z.literal("removeActionsMenuKeyFromRemotePlayer"),
|
||||||
openPopup: OpenPopupEvent;
|
data: isRemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||||
closePopup: ClosePopupEvent;
|
}),
|
||||||
openTab: OpenTabEvent;
|
z.object({
|
||||||
goToPage: GoToPageEvent;
|
type: z.literal("loadPage"),
|
||||||
disablePlayerControls: null;
|
data: isLoadPageEvent,
|
||||||
restorePlayerControls: null;
|
}),
|
||||||
displayBubble: null;
|
z.object({
|
||||||
removeBubble: null;
|
type: z.literal("chat"),
|
||||||
onPlayerMove: undefined;
|
data: isChatEvent,
|
||||||
onOpenActionMenu: undefined;
|
}),
|
||||||
onCameraUpdate: undefined;
|
z.object({
|
||||||
showLayer: LayerEvent;
|
type: z.literal("cameraFollowPlayer"),
|
||||||
hideLayer: LayerEvent;
|
data: isCameraFollowPlayerEvent,
|
||||||
setProperty: SetPropertyEvent;
|
}),
|
||||||
loadSound: LoadSoundEvent;
|
z.object({
|
||||||
playSound: PlaySoundEvent;
|
type: z.literal("cameraSet"),
|
||||||
stopSound: null;
|
data: isCameraSetEvent,
|
||||||
getState: undefined;
|
}),
|
||||||
loadTileset: LoadTilesetEvent;
|
z.object({
|
||||||
registerMenu: MenuRegisterEvent;
|
type: z.literal("openPopup"),
|
||||||
unregisterMenu: UnregisterMenuEvent;
|
data: isOpenPopupEvent,
|
||||||
setTiles: SetTilesEvent;
|
}),
|
||||||
modifyEmbeddedWebsite: Partial<EmbeddedWebsite>; // Note: name should be compulsory in fact
|
z.object({
|
||||||
};
|
type: z.literal("closePopup"),
|
||||||
export interface IframeEvent<T extends keyof IframeEventMap> {
|
data: isClosePopupEvent,
|
||||||
type: T;
|
}),
|
||||||
data: IframeEventMap[T];
|
z.object({
|
||||||
}
|
type: z.literal("openTab"),
|
||||||
|
data: isOpenTabEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("goToPage"),
|
||||||
|
data: isGoToPageEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("disablePlayerControls"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("restorePlayerControls"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("displayBubble"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("removeBubble"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("onPlayerMove"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("onCameraUpdate"),
|
||||||
|
data: z.undefined(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("showLayer"),
|
||||||
|
data: isLayerEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("hideLayer"),
|
||||||
|
data: isLayerEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("setProperty"),
|
||||||
|
data: isSetPropertyEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("loadSound"),
|
||||||
|
data: isLoadSoundEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("playSound"),
|
||||||
|
data: isPlaySoundEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("stopSound"),
|
||||||
|
data: isStopSoundEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("registerMenu"),
|
||||||
|
data: isMenuRegisterEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("unregisterMenu"),
|
||||||
|
data: isUnregisterMenuEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("setTiles"),
|
||||||
|
data: isSetTilesEvent,
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
type: z.literal("modifyEmbeddedWebsite"),
|
||||||
|
data: isEmbeddedWebsiteEvent,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export type IframeEvent = z.infer<typeof isIframeEventWrapper>;
|
||||||
export const isIframeEventWrapper = (event: any): event is IframeEvent<keyof IframeEventMap> =>
|
|
||||||
typeof event.type === "string";
|
|
||||||
|
|
||||||
export interface IframeResponseEventMap {
|
export interface IframeResponseEventMap {
|
||||||
userInputChat: UserInputChatEvent;
|
userInputChat: UserInputChatEvent;
|
||||||
@ -116,13 +184,18 @@ export const isIframeResponseEventWrapper = (event: {
|
|||||||
type?: string;
|
type?: string;
|
||||||
}): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string";
|
}): event is IframeResponseEvent<keyof IframeResponseEventMap> => typeof event.type === "string";
|
||||||
|
|
||||||
|
export const isLookingLikeIframeEventWrapper = z.object({
|
||||||
|
type: z.string(),
|
||||||
|
data: z.unknown().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame.
|
* List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame.
|
||||||
* Types are defined using Type guards that will actually bused to enforce and check types.
|
* Types are defined using Type guards that will actually bused to enforce and check types.
|
||||||
*/
|
*/
|
||||||
export const iframeQueryMapTypeGuards = {
|
export const iframeQueryMapTypeGuards = {
|
||||||
getState: {
|
getState: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: isGameStateEvent,
|
answer: isGameStateEvent,
|
||||||
},
|
},
|
||||||
getProperty: {
|
getProperty: {
|
||||||
@ -130,63 +203,63 @@ export const iframeQueryMapTypeGuards = {
|
|||||||
answer: isGetPropertyEvent,
|
answer: isGetPropertyEvent,
|
||||||
},
|
},
|
||||||
getMapData: {
|
getMapData: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: isMapDataEvent,
|
answer: isMapDataEvent,
|
||||||
},
|
},
|
||||||
setVariable: {
|
setVariable: {
|
||||||
query: isSetVariableEvent,
|
query: isSetVariableEvent,
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
loadTileset: {
|
loadTileset: {
|
||||||
query: isLoadTilesetEvent,
|
query: isLoadTilesetEvent,
|
||||||
answer: tg.isNumber,
|
answer: z.number(),
|
||||||
},
|
},
|
||||||
openCoWebsite: {
|
openCoWebsite: {
|
||||||
query: isOpenCoWebsiteEvent,
|
query: isOpenCoWebsiteEvent,
|
||||||
answer: isCoWebsite,
|
answer: isCoWebsite,
|
||||||
},
|
},
|
||||||
getCoWebsites: {
|
getCoWebsites: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: tg.isArray(isCoWebsite),
|
answer: z.array(isCoWebsite),
|
||||||
},
|
},
|
||||||
closeCoWebsite: {
|
closeCoWebsite: {
|
||||||
query: tg.isString,
|
query: z.string(),
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
closeCoWebsites: {
|
closeCoWebsites: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
triggerActionMessage: {
|
triggerActionMessage: {
|
||||||
query: isTriggerActionMessageEvent,
|
query: isTriggerActionMessageEvent,
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
removeActionMessage: {
|
removeActionMessage: {
|
||||||
query: isMessageReferenceEvent,
|
query: isMessageReferenceEvent,
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
getEmbeddedWebsite: {
|
getEmbeddedWebsite: {
|
||||||
query: tg.isString,
|
query: z.string(),
|
||||||
answer: isCreateEmbeddedWebsiteEvent,
|
answer: isCreateEmbeddedWebsiteEvent,
|
||||||
},
|
},
|
||||||
deleteEmbeddedWebsite: {
|
deleteEmbeddedWebsite: {
|
||||||
query: tg.isString,
|
query: z.string(),
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
createEmbeddedWebsite: {
|
createEmbeddedWebsite: {
|
||||||
query: isCreateEmbeddedWebsiteEvent,
|
query: isCreateEmbeddedWebsiteEvent,
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
setPlayerOutline: {
|
setPlayerOutline: {
|
||||||
query: isColorEvent,
|
query: isColorEvent,
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
removePlayerOutline: {
|
removePlayerOutline: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: tg.isUndefined,
|
answer: z.undefined(),
|
||||||
},
|
},
|
||||||
getPlayerPosition: {
|
getPlayerPosition: {
|
||||||
query: tg.isUndefined,
|
query: z.undefined(),
|
||||||
answer: isPlayerPosition,
|
answer: isPlayerPosition,
|
||||||
},
|
},
|
||||||
movePlayerTo: {
|
movePlayerTo: {
|
||||||
@ -195,14 +268,13 @@ export const iframeQueryMapTypeGuards = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
|
|
||||||
type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards;
|
type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards;
|
||||||
type UnknownToVoid<T> = undefined extends T ? void : T;
|
type UnknownToVoid<T> = undefined extends T ? void : T;
|
||||||
|
|
||||||
export type IframeQueryMap = {
|
export type IframeQueryMap = {
|
||||||
[key in keyof IframeQueryMapTypeGuardsType]: {
|
[key in keyof IframeQueryMapTypeGuardsType]: {
|
||||||
query: GuardedType<IframeQueryMapTypeGuardsType[key]["query"]>;
|
query: z.infer<typeof iframeQueryMapTypeGuards[key]["query"]>;
|
||||||
answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]["answer"]>>;
|
answer: UnknownToVoid<z.infer<typeof iframeQueryMapTypeGuards[key]["answer"]>>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,11 +302,18 @@ export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQuer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = iframeQueryMapTypeGuards[type].query(event.data);
|
try {
|
||||||
if (!result) {
|
iframeQueryMapTypeGuards[type].query.parse(event.data);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof z.ZodError) {
|
||||||
|
console.error(err.issues);
|
||||||
|
}
|
||||||
console.warn('Received a query with type "' + type + '" but the payload is invalid.');
|
console.warn('Received a query with type "' + type + '" but the payload is invalid.');
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isLayerEvent = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isLayerEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
name: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to show/hide a layer.
|
* A message sent from the iFrame to the game to show/hide a layer.
|
||||||
*/
|
*/
|
||||||
export type LayerEvent = tg.GuardedType<typeof isLayerEvent>;
|
export type LayerEvent = z.infer<typeof isLayerEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isLoadPageEvent = new tg.IsInterface()
|
export const isLoadPageEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type LoadPageEvent = tg.GuardedType<typeof isLoadPageEvent>;
|
export type LoadPageEvent = z.infer<typeof isLoadPageEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isLoadSoundEvent = new tg.IsInterface()
|
export const isLoadSoundEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type LoadSoundEvent = tg.GuardedType<typeof isLoadSoundEvent>;
|
export type LoadSoundEvent = z.infer<typeof isLoadSoundEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isLoadTilesetEvent = new tg.IsInterface()
|
export const isLoadTilesetEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type LoadTilesetEvent = tg.GuardedType<typeof isLoadTilesetEvent>;
|
export type LoadTilesetEvent = z.infer<typeof isLoadTilesetEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isMapDataEvent = new tg.IsInterface()
|
export const isMapDataEvent = z.object({
|
||||||
.withProperties({
|
data: z.unknown(), // Todo : Typing
|
||||||
data: tg.isObject,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
||||||
*/
|
*/
|
||||||
export type MapDataEvent = tg.GuardedType<typeof isMapDataEvent>;
|
export type MapDataEvent = z.infer<typeof isMapDataEvent>;
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isMovePlayerToEventConfig = new tg.IsInterface()
|
export const isMovePlayerToEventConfig = z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
speed: z.optional(z.number()),
|
||||||
speed: tg.isOptional(tg.isNumber),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type MovePlayerToEvent = tg.GuardedType<typeof isMovePlayerToEventConfig>;
|
export type MovePlayerToEvent = z.infer<typeof isMovePlayerToEventConfig>;
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isMovePlayerToEventAnswer = new tg.IsInterface()
|
export const isMovePlayerToEventAnswer = z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
cancelled: z.boolean(),
|
||||||
cancelled: tg.isBoolean,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type MovePlayerToEventAnswer = tg.GuardedType<typeof isMovePlayerToEventAnswer>;
|
export type ActionsMenuActionClickedEvent = z.infer<typeof isMovePlayerToEventAnswer>;
|
||||||
|
@ -1,25 +1,21 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isOpenCoWebsiteEvent = new tg.IsInterface()
|
export const isOpenCoWebsiteEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
allowApi: z.optional(z.boolean()),
|
||||||
allowApi: tg.isOptional(tg.isBoolean),
|
allowPolicy: z.optional(z.string()),
|
||||||
allowPolicy: tg.isOptional(tg.isString),
|
widthPercent: z.optional(z.number()),
|
||||||
widthPercent: tg.isOptional(tg.isNumber),
|
position: z.optional(z.number()),
|
||||||
position: tg.isOptional(tg.isNumber),
|
closable: z.optional(z.boolean()),
|
||||||
closable: tg.isOptional(tg.isBoolean),
|
lazy: z.optional(z.boolean()),
|
||||||
lazy: tg.isOptional(tg.isBoolean),
|
hint: z.optional(z.string()),
|
||||||
hint: tg.isOptional(tg.isString),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isCoWebsite = new tg.IsInterface()
|
export const isCoWebsite = z.object({
|
||||||
.withProperties({
|
id: z.string(),
|
||||||
id: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type OpenCoWebsiteEvent = tg.GuardedType<typeof isOpenCoWebsiteEvent>;
|
export type OpenCoWebsiteEvent = z.infer<typeof isOpenCoWebsiteEvent>;
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
const isButtonDescriptor = new tg.IsInterface()
|
export const isButtonDescriptor = z.object({
|
||||||
.withProperties({
|
label: z.string(),
|
||||||
label: tg.isString,
|
className: z.optional(z.string()),
|
||||||
className: tg.isOptional(tg.isString),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isOpenPopupEvent = new tg.IsInterface()
|
export const isOpenPopupEvent = z.object({
|
||||||
.withProperties({
|
popupId: z.number(),
|
||||||
popupId: tg.isNumber,
|
targetObject: z.string(),
|
||||||
targetObject: tg.isString,
|
message: z.string(),
|
||||||
message: tg.isString,
|
buttons: z.array(isButtonDescriptor),
|
||||||
buttons: tg.isArray(isButtonDescriptor),
|
popupClass: z.string(),
|
||||||
popupClass: tg.isString,
|
input: z.boolean(),
|
||||||
input: tg.isBoolean,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type OpenPopupEvent = tg.GuardedType<typeof isOpenPopupEvent>;
|
export type OpenPopupEvent = z.infer<typeof isOpenPopupEvent>;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isOpenTabEvent = new tg.IsInterface()
|
export const isOpenTabEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type OpenTabEvent = tg.GuardedType<typeof isOpenTabEvent>;
|
export type OpenTabEvent = z.infer<typeof isOpenTabEvent>;
|
||||||
|
@ -1,25 +1,21 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
const isSoundConfig = new tg.IsInterface()
|
export const isSoundConfig = z.object({
|
||||||
.withProperties({
|
volume: z.optional(z.number()),
|
||||||
volume: tg.isOptional(tg.isNumber),
|
loop: z.optional(z.boolean()),
|
||||||
loop: tg.isOptional(tg.isBoolean),
|
mute: z.optional(z.boolean()),
|
||||||
mute: tg.isOptional(tg.isBoolean),
|
rate: z.optional(z.number()),
|
||||||
rate: tg.isOptional(tg.isNumber),
|
detune: z.optional(z.number()),
|
||||||
detune: tg.isOptional(tg.isNumber),
|
seek: z.optional(z.number()),
|
||||||
seek: tg.isOptional(tg.isNumber),
|
delay: z.optional(z.number()),
|
||||||
delay: tg.isOptional(tg.isNumber),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isPlaySoundEvent = new tg.IsInterface()
|
export const isPlaySoundEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
config: z.optional(isSoundConfig),
|
||||||
config: tg.isOptional(isSoundConfig),
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type PlaySoundEvent = tg.GuardedType<typeof isPlaySoundEvent>;
|
export type PlaySoundEvent = z.infer<typeof isPlaySoundEvent>;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isPlayerPosition = new tg.IsInterface()
|
export const isPlayerPosition = z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type PlayerPosition = tg.GuardedType<typeof isPlayerPosition>;
|
export type PlayerPosition = z.infer<typeof isPlayerPosition>;
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
// TODO: Change for player Clicked, add all neccessary data
|
// TODO: Change for player Clicked, add all neccessary data
|
||||||
export const isRemotePlayerClickedEvent = new tg.IsInterface()
|
export const isRemotePlayerClickedEvent = z.object({
|
||||||
.withProperties({
|
id: z.number(),
|
||||||
id: tg.isNumber,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when RemotePlayer is clicked.
|
* A message sent from the game to the iFrame when RemotePlayer is clicked.
|
||||||
*/
|
*/
|
||||||
export type RemotePlayerClickedEvent = tg.GuardedType<typeof isRemotePlayerClickedEvent>;
|
export type RemotePlayerClickedEvent = z.infer<typeof isRemotePlayerClickedEvent>;
|
||||||
|
|
||||||
export type RemotePlayerClickedEventCallback = (event: RemotePlayerClickedEvent) => void;
|
export type RemotePlayerClickedEventCallback = (event: RemotePlayerClickedEvent) => void;
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = new tg.IsInterface()
|
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = z.object({
|
||||||
.withProperties({
|
id: z.number(),
|
||||||
id: tg.isNumber,
|
actionKey: z.string(),
|
||||||
actionKey: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type RemoveActionsMenuKeyFromRemotePlayerEvent = tg.GuardedType<
|
export type RemoveActionsMenuKeyFromRemotePlayerEvent = z.infer<typeof isRemoveActionsMenuKeyFromRemotePlayerEvent>;
|
||||||
typeof isRemoveActionsMenuKeyFromRemotePlayerEvent
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = (
|
export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = (
|
||||||
event: RemoveActionsMenuKeyFromRemotePlayerEvent
|
event: RemoveActionsMenuKeyFromRemotePlayerEvent
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isSetTilesEvent = tg.isArray(
|
export const isSetTilesEvent = z.array(
|
||||||
new tg.IsInterface()
|
z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
tile: z.union([z.number(), z.string(), z.null()]),
|
||||||
tile: tg.isUnion(tg.isUnion(tg.isNumber, tg.isString), tg.isNull),
|
layer: z.string(),
|
||||||
layer: tg.isString,
|
})
|
||||||
})
|
|
||||||
.get()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to set one or many tiles.
|
* A message sent from the iFrame to the game to set one or many tiles.
|
||||||
*/
|
*/
|
||||||
export type SetTilesEvent = tg.GuardedType<typeof isSetTilesEvent>;
|
export type SetTilesEvent = z.infer<typeof isSetTilesEvent>;
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isSetVariableEvent = z.object({
|
||||||
|
key: z.string(),
|
||||||
|
value: z.unknown(),
|
||||||
|
target: z.enum(["global", "player"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isSetVariableIframeEvent = z.object({
|
||||||
|
type: z.enum(["setVariable"]),
|
||||||
|
data: isSetVariableEvent,
|
||||||
|
});
|
||||||
|
|
||||||
export const isSetVariableEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
key: tg.isString,
|
|
||||||
value: tg.isUnknown,
|
|
||||||
target: tg.isSingletonStringUnion("global", "player"),
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to change the value of the property of the layer
|
* A message sent from the iFrame to the game to change the value of the property of the layer
|
||||||
*/
|
*/
|
||||||
export type SetVariableEvent = tg.GuardedType<typeof isSetVariableEvent>;
|
export type SetVariableEvent = z.infer<typeof isSetVariableEvent>;
|
||||||
|
|
||||||
export const isSetVariableIframeEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
type: tg.isSingletonString("setVariable"),
|
|
||||||
data: isSetVariableEvent,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isStopSoundEvent = new tg.IsInterface()
|
export const isStopSoundEvent = z.object({
|
||||||
.withProperties({
|
url: z.string(),
|
||||||
url: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to add a message in the chat.
|
* A message sent from the iFrame to the game to add a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type StopSoundEvent = tg.GuardedType<typeof isStopSoundEvent>;
|
export type StopSoundEvent = z.infer<typeof isStopSoundEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isUserInputChatEvent = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isUserInputChatEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
message: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a user types a message in the chat.
|
* A message sent from the game to the iFrame when a user types a message in the chat.
|
||||||
*/
|
*/
|
||||||
export type UserInputChatEvent = tg.GuardedType<typeof isUserInputChatEvent>;
|
export type UserInputChatEvent = z.infer<typeof isUserInputChatEvent>;
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const isWasCameraUpdatedEvent = new tg.IsInterface()
|
export const isWasCameraUpdatedEvent = z.object({
|
||||||
.withProperties({
|
x: z.number(),
|
||||||
x: tg.isNumber,
|
y: z.number(),
|
||||||
y: tg.isNumber,
|
width: z.number(),
|
||||||
width: tg.isNumber,
|
height: z.number(),
|
||||||
height: tg.isNumber,
|
zoom: z.number(),
|
||||||
zoom: tg.isNumber,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame to notify a movement from the camera.
|
* A message sent from the game to the iFrame to notify a movement from the camera.
|
||||||
*/
|
*/
|
||||||
|
export type WasCameraUpdatedEvent = z.infer<typeof isWasCameraUpdatedEvent>;
|
||||||
export type WasCameraUpdatedEvent = tg.GuardedType<typeof isWasCameraUpdatedEvent>;
|
|
||||||
|
|
||||||
export type WasCameraUpdatedEventCallback = (event: WasCameraUpdatedEvent) => void;
|
export type WasCameraUpdatedEventCallback = (event: WasCameraUpdatedEvent) => void;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isSetPropertyEvent = z.object({
|
||||||
|
layerName: z.string(),
|
||||||
|
propertyName: z.string(),
|
||||||
|
propertyValue: z.optional(z.union([z.string(), z.number(), z.boolean()])),
|
||||||
|
});
|
||||||
|
|
||||||
export const isSetPropertyEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
layerName: tg.isString,
|
|
||||||
propertyName: tg.isString,
|
|
||||||
propertyValue: tg.isUnion(tg.isString, tg.isUnion(tg.isNumber, tg.isUnion(tg.isBoolean, tg.isUndefined))),
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the iFrame to the game to change the value of the property of the layer
|
* A message sent from the iFrame to the game to change the value of the property of the layer
|
||||||
*/
|
*/
|
||||||
export type SetPropertyEvent = tg.GuardedType<typeof isSetPropertyEvent>;
|
export type SetPropertyEvent = z.infer<typeof isSetPropertyEvent>;
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const isMenuItemClickedEvent = z.object({
|
||||||
|
menuItem: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const isMenuItemClickedEvent = new tg.IsInterface()
|
|
||||||
.withProperties({
|
|
||||||
menuItem: tg.isString,
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
/**
|
/**
|
||||||
* A message sent from the game to the iFrame when a menu item is clicked.
|
* A message sent from the game to the iFrame when a menu item is clicked.
|
||||||
*/
|
*/
|
||||||
export type MenuItemClickedEvent = tg.GuardedType<typeof isMenuItemClickedEvent>;
|
export type MenuItemClickedEvent = z.infer<typeof isMenuItemClickedEvent>;
|
||||||
|
@ -1,31 +1,25 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from a script to the game to remove a custom menu from the menu
|
* A message sent from a script to the game to remove a custom menu from the menu
|
||||||
*/
|
*/
|
||||||
export const isUnregisterMenuEvent = new tg.IsInterface()
|
export const isUnregisterMenuEvent = z.object({
|
||||||
.withProperties({
|
name: z.string(),
|
||||||
name: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type UnregisterMenuEvent = tg.GuardedType<typeof isUnregisterMenuEvent>;
|
export type UnregisterMenuEvent = z.infer<typeof isUnregisterMenuEvent>;
|
||||||
|
|
||||||
export const isMenuRegisterOptions = new tg.IsInterface()
|
export const isMenuRegisterOptions = z.object({
|
||||||
.withProperties({
|
allowApi: z.boolean(),
|
||||||
allowApi: tg.isBoolean,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message sent from a script to the game to add a custom menu from the menu
|
* A message sent from a script to the game to add a custom menu from the menu
|
||||||
*/
|
*/
|
||||||
export const isMenuRegisterEvent = new tg.IsInterface()
|
export const isMenuRegisterEvent = z.object({
|
||||||
.withProperties({
|
name: z.string(),
|
||||||
name: tg.isString,
|
iframe: z.optional(z.string()),
|
||||||
iframe: tg.isUnion(tg.isString, tg.isUndefined),
|
options: isMenuRegisterOptions,
|
||||||
options: isMenuRegisterOptions,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type MenuRegisterEvent = tg.GuardedType<typeof isMenuRegisterEvent>;
|
export type MenuRegisterEvent = z.infer<typeof isMenuRegisterEvent>;
|
||||||
|
@ -1,26 +1,22 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const triggerActionMessage = "triggerActionMessage";
|
export const triggerActionMessage = "triggerActionMessage";
|
||||||
export const removeActionMessage = "removeActionMessage";
|
export const removeActionMessage = "removeActionMessage";
|
||||||
|
|
||||||
export const isActionMessageType = tg.isSingletonStringUnion("message", "warning");
|
export const isActionMessageType = z.enum(["message", "warning"]);
|
||||||
|
|
||||||
export type ActionMessageType = tg.GuardedType<typeof isActionMessageType>;
|
export type ActionMessageType = z.infer<typeof isActionMessageType>;
|
||||||
|
|
||||||
export const isTriggerActionMessageEvent = new tg.IsInterface()
|
export const isTriggerActionMessageEvent = z.object({
|
||||||
.withProperties({
|
message: z.string(),
|
||||||
message: tg.isString,
|
uuid: z.string(),
|
||||||
uuid: tg.isString,
|
type: isActionMessageType,
|
||||||
type: isActionMessageType,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type TriggerActionMessageEvent = tg.GuardedType<typeof isTriggerActionMessageEvent>;
|
export type TriggerActionMessageEvent = z.infer<typeof isTriggerActionMessageEvent>;
|
||||||
|
|
||||||
export const isMessageReferenceEvent = new tg.IsInterface()
|
export const isMessageReferenceEvent = z.object({
|
||||||
.withProperties({
|
uuid: z.string(),
|
||||||
uuid: tg.isString,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export type MessageReferenceEvent = tg.GuardedType<typeof isMessageReferenceEvent>;
|
export type MessageReferenceEvent = z.infer<typeof isMessageReferenceEvent>;
|
||||||
|
@ -5,20 +5,16 @@ import {
|
|||||||
triggerActionMessage,
|
triggerActionMessage,
|
||||||
} from "./TriggerActionMessageEvent";
|
} from "./TriggerActionMessageEvent";
|
||||||
|
|
||||||
import * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
|
|
||||||
const isTriggerMessageEventObject = new tg.IsInterface()
|
const isTriggerMessageEventObject = z.object({
|
||||||
.withProperties({
|
type: z.enum([triggerActionMessage]),
|
||||||
type: tg.isSingletonString(triggerActionMessage),
|
data: isTriggerActionMessageEvent,
|
||||||
data: isTriggerActionMessageEvent,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
const isTriggerMessageRemoveEventObject = new tg.IsInterface()
|
const isTriggerMessageRemoveEventObject = z.object({
|
||||||
.withProperties({
|
type: z.enum([removeActionMessage]),
|
||||||
type: tg.isSingletonString(removeActionMessage),
|
data: isMessageReferenceEvent,
|
||||||
data: isMessageReferenceEvent,
|
});
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
export const isTriggerMessageHandlerEvent = tg.isUnion(isTriggerMessageEventObject, isTriggerMessageRemoveEventObject);
|
export const isTriggerMessageHandlerEvent = z.union([isTriggerMessageEventObject, isTriggerMessageRemoveEventObject]);
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { isChatEvent } from "./Events/ChatEvent";
|
|
||||||
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
||||||
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
|
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
|
||||||
import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent";
|
import { OpenPopupEvent } from "./Events/OpenPopupEvent";
|
||||||
import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent";
|
import { OpenTabEvent } from "./Events/OpenTabEvent";
|
||||||
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
|
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
|
||||||
import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
|
import { ClosePopupEvent } from "./Events/ClosePopupEvent";
|
||||||
import { scriptUtils } from "./ScriptUtils";
|
import { scriptUtils } from "./ScriptUtils";
|
||||||
import { isGoToPageEvent } from "./Events/GoToPageEvent";
|
|
||||||
import {
|
import {
|
||||||
IframeErrorAnswerEvent,
|
IframeErrorAnswerEvent,
|
||||||
IframeQueryMap,
|
IframeQueryMap,
|
||||||
@ -15,35 +13,28 @@ import {
|
|||||||
IframeResponseEventMap,
|
IframeResponseEventMap,
|
||||||
isIframeEventWrapper,
|
isIframeEventWrapper,
|
||||||
isIframeQueryWrapper,
|
isIframeQueryWrapper,
|
||||||
|
isLookingLikeIframeEventWrapper,
|
||||||
} from "./Events/IframeEvent";
|
} from "./Events/IframeEvent";
|
||||||
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
||||||
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
|
import { PlaySoundEvent } from "./Events/PlaySoundEvent";
|
||||||
import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
|
import { StopSoundEvent } from "./Events/StopSoundEvent";
|
||||||
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
|
import { LoadSoundEvent } from "./Events/LoadSoundEvent";
|
||||||
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
import { SetPropertyEvent } from "./Events/setPropertyEvent";
|
||||||
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
import { LayerEvent } from "./Events/LayerEvent";
|
||||||
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
||||||
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
import { SetTilesEvent } from "./Events/SetTilesEvent";
|
||||||
import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./Events/ui/MenuRegisterEvent";
|
|
||||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
|
||||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||||
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
import { ModifyEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||||
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
|
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
|
||||||
import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent";
|
import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent";
|
||||||
import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
|
import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
|
||||||
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
||||||
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
|
import { CameraSetEvent } from "./Events/CameraSetEvent";
|
||||||
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
import { CameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
||||||
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
|
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
|
||||||
import {
|
import { AddActionsMenuKeyToRemotePlayerEvent } from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
||||||
AddActionsMenuKeyToRemotePlayerEvent,
|
|
||||||
isAddActionsMenuKeyToRemotePlayerEvent,
|
|
||||||
} from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
|
||||||
import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent";
|
import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent";
|
||||||
import {
|
import { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||||
isRemoveActionsMenuKeyFromRemotePlayerEvent,
|
|
||||||
RemoveActionsMenuKeyFromRemotePlayerEvent,
|
|
||||||
} from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||||
query: IframeQueryMap[T]["query"],
|
query: IframeQueryMap[T]["query"],
|
||||||
@ -153,8 +144,10 @@ class IframeListener {
|
|||||||
|
|
||||||
const payload = message.data;
|
const payload = message.data;
|
||||||
|
|
||||||
|
const lookingLikeEvent = isLookingLikeIframeEventWrapper.safeParse(payload);
|
||||||
|
|
||||||
if (foundSrc === undefined || iframe === undefined) {
|
if (foundSrc === undefined || iframe === undefined) {
|
||||||
if (isIframeEventWrapper(payload)) {
|
if (lookingLikeEvent.success) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. " +
|
"It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. " +
|
||||||
"If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the " +
|
"If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the " +
|
||||||
@ -224,63 +217,70 @@ class IframeListener {
|
|||||||
} catch (reason) {
|
} catch (reason) {
|
||||||
errorHandler(reason);
|
errorHandler(reason);
|
||||||
}
|
}
|
||||||
} else if (isIframeEventWrapper(payload)) {
|
} else if (lookingLikeEvent.success) {
|
||||||
if (payload.type === "showLayer" && isLayerEvent(payload.data)) {
|
const iframeEventGuarded = isIframeEventWrapper.safeParse(lookingLikeEvent.data);
|
||||||
this._showLayerStream.next(payload.data);
|
|
||||||
} else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) {
|
if (!iframeEventGuarded.success) {
|
||||||
this._hideLayerStream.next(payload.data);
|
console.error(
|
||||||
} else if (payload.type === "setProperty" && isSetPropertyEvent(payload.data)) {
|
`Invalid event "${lookingLikeEvent.data.type}" received from Iframe: `,
|
||||||
this._setPropertyStream.next(payload.data);
|
lookingLikeEvent.data,
|
||||||
} else if (payload.type === "cameraSet" && isCameraSetEvent(payload.data)) {
|
iframeEventGuarded.error.issues
|
||||||
this._cameraSetStream.next(payload.data);
|
);
|
||||||
} else if (payload.type === "cameraFollowPlayer" && isCameraFollowPlayerEvent(payload.data)) {
|
return;
|
||||||
this._cameraFollowPlayerStream.next(payload.data);
|
}
|
||||||
} else if (payload.type === "chat" && isChatEvent(payload.data)) {
|
|
||||||
scriptUtils.sendAnonymousChat(payload.data);
|
const iframeEvent = iframeEventGuarded.data;
|
||||||
} else if (payload.type === "openPopup" && isOpenPopupEvent(payload.data)) {
|
|
||||||
this._openPopupStream.next(payload.data);
|
if (iframeEvent.type === "showLayer") {
|
||||||
} else if (payload.type === "closePopup" && isClosePopupEvent(payload.data)) {
|
this._showLayerStream.next(iframeEvent.data);
|
||||||
this._closePopupStream.next(payload.data);
|
} else if (iframeEvent.type === "hideLayer") {
|
||||||
} else if (payload.type === "openTab" && isOpenTabEvent(payload.data)) {
|
this._hideLayerStream.next(iframeEvent.data);
|
||||||
scriptUtils.openTab(payload.data.url);
|
} else if (iframeEvent.type === "setProperty") {
|
||||||
} else if (payload.type === "goToPage" && isGoToPageEvent(payload.data)) {
|
this._setPropertyStream.next(iframeEvent.data);
|
||||||
scriptUtils.goToPage(payload.data.url);
|
} else if (iframeEvent.type === "cameraSet") {
|
||||||
} else if (payload.type === "loadPage" && isLoadPageEvent(payload.data)) {
|
this._cameraSetStream.next(iframeEvent.data);
|
||||||
this._loadPageStream.next(payload.data.url);
|
} else if (iframeEvent.type === "cameraFollowPlayer") {
|
||||||
} else if (payload.type === "playSound" && isPlaySoundEvent(payload.data)) {
|
this._cameraFollowPlayerStream.next(iframeEvent.data);
|
||||||
this._playSoundStream.next(payload.data);
|
} else if (iframeEvent.type === "chat") {
|
||||||
} else if (payload.type === "stopSound" && isStopSoundEvent(payload.data)) {
|
scriptUtils.sendAnonymousChat(iframeEvent.data);
|
||||||
this._stopSoundStream.next(payload.data);
|
} else if (iframeEvent.type === "openPopup") {
|
||||||
} else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) {
|
this._openPopupStream.next(iframeEvent.data);
|
||||||
this._loadSoundStream.next(payload.data);
|
} else if (iframeEvent.type === "closePopup") {
|
||||||
} else if (payload.type === "disablePlayerControls") {
|
this._closePopupStream.next(iframeEvent.data);
|
||||||
|
} else if (iframeEvent.type === "openTab") {
|
||||||
|
scriptUtils.openTab(iframeEvent.data.url);
|
||||||
|
} else if (iframeEvent.type === "goToPage") {
|
||||||
|
scriptUtils.goToPage(iframeEvent.data.url);
|
||||||
|
} else if (iframeEvent.type === "loadPage") {
|
||||||
|
this._loadPageStream.next(iframeEvent.data.url);
|
||||||
|
} else if (iframeEvent.type === "playSound") {
|
||||||
|
this._playSoundStream.next(iframeEvent.data);
|
||||||
|
} else if (iframeEvent.type === "stopSound") {
|
||||||
|
this._stopSoundStream.next(iframeEvent.data);
|
||||||
|
} else if (iframeEvent.type === "loadSound") {
|
||||||
|
this._loadSoundStream.next(iframeEvent.data);
|
||||||
|
} else if (iframeEvent.type === "disablePlayerControls") {
|
||||||
this._disablePlayerControlStream.next();
|
this._disablePlayerControlStream.next();
|
||||||
} else if (payload.type === "restorePlayerControls") {
|
} else if (iframeEvent.type === "restorePlayerControls") {
|
||||||
this._enablePlayerControlStream.next();
|
this._enablePlayerControlStream.next();
|
||||||
} else if (payload.type === "displayBubble") {
|
} else if (iframeEvent.type === "displayBubble") {
|
||||||
this._displayBubbleStream.next();
|
this._displayBubbleStream.next();
|
||||||
} else if (payload.type === "removeBubble") {
|
} else if (iframeEvent.type === "removeBubble") {
|
||||||
this._removeBubbleStream.next();
|
this._removeBubbleStream.next();
|
||||||
} else if (payload.type == "onPlayerMove") {
|
} else if (iframeEvent.type == "onPlayerMove") {
|
||||||
this.sendPlayerMove = true;
|
this.sendPlayerMove = true;
|
||||||
} else if (
|
} else if (iframeEvent.type == "addActionsMenuKeyToRemotePlayer") {
|
||||||
payload.type == "addActionsMenuKeyToRemotePlayer" &&
|
this._addActionsMenuKeyToRemotePlayerStream.next(iframeEvent.data);
|
||||||
isAddActionsMenuKeyToRemotePlayerEvent(payload.data)
|
} else if (iframeEvent.type == "removeActionsMenuKeyFromRemotePlayer") {
|
||||||
) {
|
this._removeActionsMenuKeyFromRemotePlayerEvent.next(iframeEvent.data);
|
||||||
this._addActionsMenuKeyToRemotePlayerStream.next(payload.data);
|
} else if (iframeEvent.type == "onCameraUpdate") {
|
||||||
} else if (
|
|
||||||
payload.type == "removeActionsMenuKeyFromRemotePlayer" &&
|
|
||||||
isRemoveActionsMenuKeyFromRemotePlayerEvent(payload.data)
|
|
||||||
) {
|
|
||||||
this._removeActionsMenuKeyFromRemotePlayerEvent.next(payload.data);
|
|
||||||
} else if (payload.type == "onCameraUpdate") {
|
|
||||||
this._trackCameraUpdateStream.next();
|
this._trackCameraUpdateStream.next();
|
||||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
} else if (iframeEvent.type == "setTiles") {
|
||||||
this._setTilesStream.next(payload.data);
|
this._setTilesStream.next(iframeEvent.data);
|
||||||
} else if (payload.type == "modifyEmbeddedWebsite" && isEmbeddedWebsiteEvent(payload.data)) {
|
} else if (iframeEvent.type == "modifyEmbeddedWebsite") {
|
||||||
this._modifyEmbeddedWebsiteStream.next(payload.data);
|
this._modifyEmbeddedWebsiteStream.next(iframeEvent.data);
|
||||||
} else if (payload.type == "registerMenu" && isMenuRegisterEvent(payload.data)) {
|
} else if (iframeEvent.type == "registerMenu") {
|
||||||
const dataName = payload.data.name;
|
const dataName = iframeEvent.data.name;
|
||||||
this.iframeCloseCallbacks.get(iframe)?.push(() => {
|
this.iframeCloseCallbacks.get(iframe)?.push(() => {
|
||||||
handleMenuUnregisterEvent(dataName);
|
handleMenuUnregisterEvent(dataName);
|
||||||
});
|
});
|
||||||
@ -288,13 +288,17 @@ class IframeListener {
|
|||||||
foundSrc = this.getBaseUrl(foundSrc, message.source);
|
foundSrc = this.getBaseUrl(foundSrc, message.source);
|
||||||
|
|
||||||
handleMenuRegistrationEvent(
|
handleMenuRegistrationEvent(
|
||||||
payload.data.name,
|
iframeEvent.data.name,
|
||||||
payload.data.iframe,
|
iframeEvent.data.iframe,
|
||||||
foundSrc,
|
foundSrc,
|
||||||
payload.data.options
|
iframeEvent.data.options
|
||||||
);
|
);
|
||||||
} else if (payload.type == "unregisterMenu" && isUnregisterMenuEvent(payload.data)) {
|
} else if (iframeEvent.type == "unregisterMenu") {
|
||||||
handleMenuUnregisterEvent(payload.data.name);
|
handleMenuUnregisterEvent(iframeEvent.data.name);
|
||||||
|
} else {
|
||||||
|
// Keep the line below. It will throw an error if we forget to handle one of the possible values.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const _exhaustiveCheck: never = iframeEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -319,7 +323,7 @@ class IframeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
registerScript(scriptUrl: string, enableModuleMode: boolean = true): Promise<void> {
|
registerScript(scriptUrl: string, enableModuleMode: boolean = true): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve) => {
|
||||||
console.info("Loading map related script at ", scriptUrl);
|
console.info("Loading map related script at ", scriptUrl);
|
||||||
|
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
import type * as tg from "generic-type-guard";
|
import { z } from "zod";
|
||||||
import type {
|
import type { IframeEvent, IframeQuery, IframeQueryMap, IframeResponseEventMap } from "../Events/IframeEvent";
|
||||||
IframeEvent,
|
|
||||||
IframeEventMap,
|
|
||||||
IframeQuery,
|
|
||||||
IframeQueryMap,
|
|
||||||
IframeResponseEventMap,
|
|
||||||
} from "../Events/IframeEvent";
|
|
||||||
import type { IframeQueryWrapper } from "../Events/IframeEvent";
|
import type { IframeQueryWrapper } from "../Events/IframeEvent";
|
||||||
|
|
||||||
export function sendToWorkadventure(content: IframeEvent<keyof IframeEventMap>) {
|
export function sendToWorkadventure(content: IframeEvent) {
|
||||||
window.parent.postMessage(content, "*");
|
window.parent.postMessage(content, "*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,12 +42,10 @@ export function queryWorkadventure<T extends keyof IframeQueryMap>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type GuardedType<Guard extends tg.TypeGuard<unknown>> = Guard extends tg.TypeGuard<infer T> ? T : never;
|
|
||||||
|
|
||||||
export interface IframeCallback<
|
export interface IframeCallback<
|
||||||
Key extends keyof IframeResponseEventMap,
|
Key extends keyof IframeResponseEventMap,
|
||||||
T = IframeResponseEventMap[Key],
|
T = IframeResponseEventMap[Key],
|
||||||
Guard = tg.TypeGuard<T>
|
Guard = z.ZodType<T>
|
||||||
> {
|
> {
|
||||||
typeChecker: Guard;
|
typeChecker: Guard;
|
||||||
callback: (payloadData: T) => void;
|
callback: (payloadData: T) => void;
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import { sendToWorkadventure } from "../IframeApiContribution";
|
import { sendToWorkadventure } from "../IframeApiContribution";
|
||||||
import type {
|
import type { CreateEmbeddedWebsiteEvent, Rectangle } from "../../Events/EmbeddedWebsiteEvent";
|
||||||
CreateEmbeddedWebsiteEvent,
|
|
||||||
ModifyEmbeddedWebsiteEvent,
|
|
||||||
Rectangle,
|
|
||||||
} from "../../Events/EmbeddedWebsiteEvent";
|
|
||||||
|
|
||||||
export class EmbeddedWebsite {
|
export class EmbeddedWebsite {
|
||||||
public readonly name: string;
|
public readonly name: string;
|
||||||
|
@ -41,7 +41,7 @@ export class WorkAdventureCameraCommands extends IframeApiContribution<WorkAdven
|
|||||||
onCameraUpdate(): Subject<WasCameraUpdatedEvent> {
|
onCameraUpdate(): Subject<WasCameraUpdatedEvent> {
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
type: "onCameraUpdate",
|
type: "onCameraUpdate",
|
||||||
data: null,
|
data: undefined,
|
||||||
});
|
});
|
||||||
return moveStream;
|
return moveStream;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ export class WorkadventureControlsCommands extends IframeApiContribution<Workadv
|
|||||||
callbacks = [];
|
callbacks = [];
|
||||||
|
|
||||||
disablePlayerControls(): void {
|
disablePlayerControls(): void {
|
||||||
sendToWorkadventure({ type: "disablePlayerControls", data: null });
|
sendToWorkadventure({ type: "disablePlayerControls", data: undefined });
|
||||||
}
|
}
|
||||||
|
|
||||||
restorePlayerControls(): void {
|
restorePlayerControls(): void {
|
||||||
sendToWorkadventure({ type: "restorePlayerControls", data: null });
|
sendToWorkadventure({ type: "restorePlayerControls", data: undefined });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ export class WorkadventurePlayerCommands extends IframeApiContribution<Workadven
|
|||||||
moveStream.subscribe(callback);
|
moveStream.subscribe(callback);
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
type: "onPlayerMove",
|
type: "onPlayerMove",
|
||||||
data: null,
|
data: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import type { LoadSoundEvent } from "../Events/LoadSoundEvent";
|
import { IframeApiContribution } from "./IframeApiContribution";
|
||||||
import type { PlaySoundEvent } from "../Events/PlaySoundEvent";
|
|
||||||
import type { StopSoundEvent } from "../Events/StopSoundEvent";
|
|
||||||
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
|
|
||||||
import { Sound } from "./Sound/Sound";
|
import { Sound } from "./Sound/Sound";
|
||||||
|
|
||||||
export class WorkadventureSoundCommands extends IframeApiContribution<WorkadventureSoundCommands> {
|
export class WorkadventureSoundCommands extends IframeApiContribution<WorkadventureSoundCommands> {
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { Observable, Subject } from "rxjs";
|
import { Observable, Subject } from "rxjs";
|
||||||
|
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
import { IframeApiContribution, queryWorkadventure } from "./IframeApiContribution";
|
||||||
|
|
||||||
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
|
||||||
import { apiCallback } from "./registeredCallbacks";
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
import { isSetVariableEvent, SetVariableEvent } from "../Events/SetVariableEvent";
|
import { isSetVariableEvent, SetVariableEvent } from "../Events/SetVariableEvent";
|
||||||
|
|
||||||
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
|
||||||
|
|
||||||
export class WorkadventureStateCommands extends IframeApiContribution<WorkadventureStateCommands> {
|
export class WorkadventureStateCommands extends IframeApiContribution<WorkadventureStateCommands> {
|
||||||
private setVariableResolvers = new Subject<SetVariableEvent>();
|
private setVariableResolvers = new Subject<SetVariableEvent>();
|
||||||
private variables = new Map<string, unknown>();
|
private variables = new Map<string, unknown>();
|
||||||
@ -17,7 +13,7 @@ export class WorkadventureStateCommands extends IframeApiContribution<Workadvent
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.setVariableResolvers.subscribe((event) => {
|
this.setVariableResolvers.subscribe((event) => {
|
||||||
const oldValue = this.variables.get(event.key);
|
// const oldValue = this.variables.get(event.key);
|
||||||
// If we are setting the same value, no need to do anything.
|
// If we are setting the same value, no need to do anything.
|
||||||
// No need to do this check since it is already performed in SharedVariablesManager
|
// No need to do this check since it is already performed in SharedVariablesManager
|
||||||
/*if (JSON.stringify(oldValue) === JSON.stringify(event.value)) {
|
/*if (JSON.stringify(oldValue) === JSON.stringify(event.value)) {
|
||||||
@ -92,6 +88,7 @@ export function createState(target: "global" | "player"): WorkadventureStateComm
|
|||||||
}
|
}
|
||||||
return target.loadVariable(p.toString());
|
return target.loadVariable(p.toString());
|
||||||
},
|
},
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
set(target: WorkadventureStateCommands, p: PropertyKey, value: unknown, receiver: unknown): boolean {
|
set(target: WorkadventureStateCommands, p: PropertyKey, value: unknown, receiver: unknown): boolean {
|
||||||
// Note: when using "set", there is no way to wait, so we ignore the return of the promise.
|
// Note: when using "set", there is no way to wait, so we ignore the return of the promise.
|
||||||
// User must use WA.state.saveVariable to have error message.
|
// User must use WA.state.saveVariable to have error message.
|
||||||
|
@ -34,14 +34,6 @@ interface MenuDescriptor {
|
|||||||
|
|
||||||
export type MenuOptions = RequireOnlyOne<MenuDescriptor, "callback" | "iframe">;
|
export type MenuOptions = RequireOnlyOne<MenuDescriptor, "callback" | "iframe">;
|
||||||
|
|
||||||
interface ZonedPopupOptions {
|
|
||||||
zone: string;
|
|
||||||
objectLayerName?: string;
|
|
||||||
popupText: string;
|
|
||||||
delay?: number;
|
|
||||||
popupOptions: Array<ButtonDescriptor>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActionMessageOptions {
|
export interface ActionMessageOptions {
|
||||||
message: string;
|
message: string;
|
||||||
type?: "message" | "warning";
|
type?: "message" | "warning";
|
||||||
@ -284,11 +276,11 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
|||||||
}
|
}
|
||||||
|
|
||||||
public displayBubble(): void {
|
public displayBubble(): void {
|
||||||
sendToWorkadventure({ type: "displayBubble", data: null });
|
sendToWorkadventure({ type: "displayBubble", data: undefined });
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeBubble(): void {
|
public removeBubble(): void {
|
||||||
sendToWorkadventure({ type: "removeBubble", data: null });
|
sendToWorkadventure({ type: "removeBubble", data: undefined });
|
||||||
}
|
}
|
||||||
|
|
||||||
public displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
public displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
import { IframeApiContribution, queryWorkadventure } from "./IframeApiContribution";
|
||||||
import { EmbeddedWebsite } from "./Room/EmbeddedWebsite";
|
import { EmbeddedWebsite } from "./Room/EmbeddedWebsite";
|
||||||
import type { CreateEmbeddedWebsiteEvent } from "../Events/EmbeddedWebsiteEvent";
|
import type { CreateEmbeddedWebsiteEvent } from "../Events/EmbeddedWebsiteEvent";
|
||||||
|
|
||||||
|
@ -271,10 +271,6 @@
|
|||||||
.cowebsite-thumbnail-hint {
|
.cowebsite-thumbnail-hint {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -42,4 +42,4 @@ axiosWithRetry.interceptors.response.use((res) => {
|
|||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
|
|
||||||
const interceptorId = rax.attach(axiosWithRetry);
|
rax.attach(axiosWithRetry);
|
||||||
|
@ -4,7 +4,7 @@ import { RoomConnection } from "./RoomConnection";
|
|||||||
import type { OnConnectInterface, PositionInterface, ViewportInterface } from "./ConnexionModels";
|
import type { OnConnectInterface, PositionInterface, ViewportInterface } from "./ConnexionModels";
|
||||||
import { GameConnexionTypes, urlManager } from "../Url/UrlManager";
|
import { GameConnexionTypes, urlManager } from "../Url/UrlManager";
|
||||||
import { localUserStore } from "./LocalUserStore";
|
import { localUserStore } from "./LocalUserStore";
|
||||||
import { CharacterTexture, LocalUser } from "./LocalUser";
|
import { LocalUser } from "./LocalUser";
|
||||||
import { Room } from "./Room";
|
import { Room } from "./Room";
|
||||||
import { _ServiceWorker } from "../Network/ServiceWorker";
|
import { _ServiceWorker } from "../Network/ServiceWorker";
|
||||||
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
||||||
@ -13,7 +13,6 @@ import { analyticsClient } from "../Administration/AnalyticsClient";
|
|||||||
import { axiosWithRetry } from "./AxiosUtils";
|
import { axiosWithRetry } from "./AxiosUtils";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
||||||
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
|
||||||
import { limitMapStore } from "../Stores/GameStore";
|
import { limitMapStore } from "../Stores/GameStore";
|
||||||
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
||||||
import { gameManager } from "../Phaser/Game/GameManager";
|
import { gameManager } from "../Phaser/Game/GameManager";
|
||||||
@ -74,9 +73,7 @@ class ConnectionManager {
|
|||||||
|
|
||||||
//Logout user in pusher and hydra
|
//Logout user in pusher and hydra
|
||||||
const token = localUserStore.getAuthToken();
|
const token = localUserStore.getAuthToken();
|
||||||
const { authToken } = await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then(
|
await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then((res) => res.data);
|
||||||
(res) => res.data
|
|
||||||
);
|
|
||||||
localUserStore.setAuthToken(null);
|
localUserStore.setAuthToken(null);
|
||||||
|
|
||||||
//Go on login page can permit to clear token and start authentication process
|
//Go on login page can permit to clear token and start authentication process
|
||||||
@ -140,13 +137,19 @@ class ConnectionManager {
|
|||||||
//@deprecated
|
//@deprecated
|
||||||
else if (this.connexionType === GameConnexionTypes.register) {
|
else if (this.connexionType === GameConnexionTypes.register) {
|
||||||
const organizationMemberToken = urlManager.getOrganizationToken();
|
const organizationMemberToken = urlManager.getOrganizationToken();
|
||||||
const data = await Axios.post(`${PUSHER_URL}/register`, { organizationMemberToken }).then(
|
const result = await Axios.post(`${PUSHER_URL}/register`, { organizationMemberToken }).then(
|
||||||
(res) => res.data
|
(res) => res.data
|
||||||
);
|
);
|
||||||
if (!isRegisterData(data)) {
|
|
||||||
console.error("Invalid data received from /register route. Data: ", data);
|
const registerDataChecking = isRegisterData.safeParse(result);
|
||||||
|
|
||||||
|
if (!registerDataChecking.success) {
|
||||||
|
console.error("Invalid data received from /register route. Data: ", result);
|
||||||
throw new Error("Invalid data received from /register route.");
|
throw new Error("Invalid data received from /register route.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const data = registerDataChecking.data;
|
||||||
|
|
||||||
this.localUser = new LocalUser(data.userUuid, data.email);
|
this.localUser = new LocalUser(data.userUuid, data.email);
|
||||||
this.authToken = data.authToken;
|
this.authToken = data.authToken;
|
||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
@ -307,9 +310,9 @@ class ConnectionManager {
|
|||||||
connection.roomJoinedMessageStream.subscribe((connect: OnConnectInterface) => {
|
connection.roomJoinedMessageStream.subscribe((connect: OnConnectInterface) => {
|
||||||
resolve(connect);
|
resolve(connect);
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch(() => {
|
||||||
// Let's retry in 4-6 seconds
|
// Let's retry in 4-6 seconds
|
||||||
return new Promise<OnConnectInterface>((resolve, reject) => {
|
return new Promise<OnConnectInterface>((resolve) => {
|
||||||
this.reconnectingTimeout = setTimeout(() => {
|
this.reconnectingTimeout = setTimeout(() => {
|
||||||
//todo: allow a way to break recursion?
|
//todo: allow a way to break recursion?
|
||||||
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
|
//todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely.
|
||||||
|
@ -5,7 +5,7 @@ import type { BodyResourceDescriptionInterface } from "../Phaser/Entity/PlayerTe
|
|||||||
export interface PointInterface {
|
export interface PointInterface {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
direction: string; // TODO: modify this to the enum from ts-proto
|
direction: "up" | "down" | "left" | "right"; // TODO: modify this to the enum from ts-proto
|
||||||
moving: boolean;
|
moving: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ export interface MessageUserPositionInterface {
|
|||||||
name: string;
|
name: string;
|
||||||
characterLayers: BodyResourceDescriptionInterface[];
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
away: boolean;
|
||||||
visitCardUrl: string | null;
|
visitCardUrl: string | null;
|
||||||
companion: string | null;
|
companion: string | null;
|
||||||
userUuid: string;
|
userUuid: string;
|
||||||
@ -29,6 +30,7 @@ export interface MessageUserJoined {
|
|||||||
name: string;
|
name: string;
|
||||||
characterLayers: BodyResourceDescriptionInterface[];
|
characterLayers: BodyResourceDescriptionInterface[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
away: boolean;
|
||||||
visitCardUrl: string | null;
|
visitCardUrl: string | null;
|
||||||
companion: string | null;
|
companion: string | null;
|
||||||
userUuid: string;
|
userUuid: string;
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import * as rax from "retry-axios";
|
|
||||||
import Axios from "axios";
|
|
||||||
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
||||||
import type { CharacterTexture } from "./LocalUser";
|
|
||||||
import { localUserStore } from "./LocalUserStore";
|
import { localUserStore } from "./LocalUserStore";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { axiosWithRetry } from "./AxiosUtils";
|
import { axiosWithRetry } from "./AxiosUtils";
|
||||||
@ -112,11 +109,14 @@ export class Room {
|
|||||||
data.authenticationMandatory = Boolean(data.authenticationMandatory);
|
data.authenticationMandatory = Boolean(data.authenticationMandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRoomRedirect(data)) {
|
const roomRedirectChecking = isRoomRedirect.safeParse(data);
|
||||||
|
const mapDetailsDataChecking = isMapDetailsData.safeParse(data);
|
||||||
|
|
||||||
|
if (roomRedirectChecking.success) {
|
||||||
return {
|
return {
|
||||||
redirectUrl: data.redirectUrl,
|
redirectUrl: data.redirectUrl,
|
||||||
};
|
};
|
||||||
} else if (isMapDetailsData(data)) {
|
} else if (mapDetailsDataChecking.success) {
|
||||||
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
||||||
this._mapUrl = data.mapUrl;
|
this._mapUrl = data.mapUrl;
|
||||||
this._group = data.group;
|
this._group = data.group;
|
||||||
@ -132,6 +132,9 @@ export class Room {
|
|||||||
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
|
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
|
||||||
return new MapDetail(data.mapUrl);
|
return new MapDetail(data.mapUrl);
|
||||||
} else {
|
} else {
|
||||||
|
console.log(data);
|
||||||
|
console.error("roomRedirectChecking", roomRedirectChecking.error.issues);
|
||||||
|
console.error("mapDetailsDataChecking", mapDetailsDataChecking.error.issues);
|
||||||
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -190,7 +190,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
|
|
||||||
let interval: ReturnType<typeof setInterval> | undefined = undefined;
|
let interval: ReturnType<typeof setInterval> | undefined = undefined;
|
||||||
|
|
||||||
this.socket.onopen = (ev) => {
|
this.socket.onopen = () => {
|
||||||
//we manually ping every 20s to not be logged out by the server, even when the game is in background.
|
//we manually ping every 20s to not be logged out by the server, even when the game is in background.
|
||||||
const pingMessage = PingMessageTsProto.encode({}).finish();
|
const pingMessage = PingMessageTsProto.encode({}).finish();
|
||||||
interval = setInterval(() => this.socket.send(pingMessage), manualPingDelay);
|
interval = setInterval(() => this.socket.send(pingMessage), manualPingDelay);
|
||||||
@ -297,6 +297,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// Security check: if we forget a "case", the line below will catch the error at compile-time.
|
// Security check: if we forget a "case", the line below will catch the error at compile-time.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const tmp: never = subMessage;
|
const tmp: never = subMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,6 +478,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// Security check: if we forget a "case", the line below will catch the error at compile-time.
|
// Security check: if we forget a "case", the line below will catch the error at compile-time.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const tmp: never = message;
|
const tmp: never = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,6 +520,20 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.socket.send(bytes);
|
this.socket.send(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitPlayerAway(away: boolean): void {
|
||||||
|
const message = SetPlayerDetailsMessageTsProto.fromPartial({
|
||||||
|
away,
|
||||||
|
});
|
||||||
|
const bytes = ClientToServerMessageTsProto.encode({
|
||||||
|
message: {
|
||||||
|
$case: "setPlayerDetailsMessage",
|
||||||
|
setPlayerDetailsMessage: message,
|
||||||
|
},
|
||||||
|
}).finish();
|
||||||
|
|
||||||
|
this.socket.send(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
public emitPlayerOutlineColor(color: number | null) {
|
public emitPlayerOutlineColor(color: number | null) {
|
||||||
let message: SetPlayerDetailsMessageTsProto;
|
let message: SetPlayerDetailsMessageTsProto;
|
||||||
if (color === null) {
|
if (color === null) {
|
||||||
@ -654,6 +670,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
characterLayers,
|
characterLayers,
|
||||||
visitCardUrl: message.visitCardUrl,
|
visitCardUrl: message.visitCardUrl,
|
||||||
position: ProtobufClientUtils.toPointInterface(position),
|
position: ProtobufClientUtils.toPointInterface(position),
|
||||||
|
away: message.away,
|
||||||
companion: companion ? companion.name : null,
|
companion: companion ? companion.name : null,
|
||||||
userUuid: message.userUuid,
|
userUuid: message.userUuid,
|
||||||
outlineColor: message.hasOutline ? message.outlineColor : undefined,
|
outlineColor: message.hasOutline ? message.outlineColor : undefined,
|
||||||
|
@ -4,7 +4,7 @@ import type { PointInterface } from "../Connexion/ConnexionModels";
|
|||||||
|
|
||||||
export class ProtobufClientUtils {
|
export class ProtobufClientUtils {
|
||||||
public static toPointInterface(position: PositionMessage): PointInterface {
|
public static toPointInterface(position: PositionMessage): PointInterface {
|
||||||
let direction: string;
|
let direction: "up" | "down" | "left" | "right";
|
||||||
switch (position.direction) {
|
switch (position.direction) {
|
||||||
case PositionMessage_Direction.UP:
|
case PositionMessage_Direction.UP:
|
||||||
direction = "up";
|
direction = "up";
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
|
||||||
import { DirtyScene } from "../Game/DirtyScene";
|
import { DirtyScene } from "../Game/DirtyScene";
|
||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
import Image = Phaser.GameObjects.Image;
|
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
|
|
||||||
const TextName: string = "Loading...";
|
const TextName: string = "Loading...";
|
||||||
@ -35,8 +33,6 @@ export class Loader {
|
|||||||
const logoResource = gameManager.currentStartedRoom.loadingLogo ?? "static/images/logo.png";
|
const logoResource = gameManager.currentStartedRoom.loadingLogo ?? "static/images/logo.png";
|
||||||
this.logoNameIndex = "logoLoading" + logoResource;
|
this.logoNameIndex = "logoLoading" + logoResource;
|
||||||
|
|
||||||
const loadingBarWidth: number = Math.floor(this.scene.game.renderer.width / 3);
|
|
||||||
|
|
||||||
//add loading if logo image until logo image is ready
|
//add loading if logo image until logo image is ready
|
||||||
this.loadingText = this.scene.add.text(
|
this.loadingText = this.scene.add.text(
|
||||||
this.scene.game.renderer.width / 2,
|
this.scene.game.renderer.width / 2,
|
||||||
|
65
front/src/Phaser/Components/PlayerStatusDot.ts
Normal file
65
front/src/Phaser/Components/PlayerStatusDot.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { Easing } from "../../types";
|
||||||
|
|
||||||
|
export class PlayerStatusDot extends Phaser.GameObjects.Container {
|
||||||
|
private graphics: Phaser.GameObjects.Graphics;
|
||||||
|
|
||||||
|
private away: boolean;
|
||||||
|
|
||||||
|
private readonly COLORS = {
|
||||||
|
// online: 0x00ff00,
|
||||||
|
// away: 0xffff00,
|
||||||
|
online: 0x8cc43f,
|
||||||
|
onlineOutline: 0x427a25,
|
||||||
|
away: 0xf5931e,
|
||||||
|
awayOutline: 0x875d13,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number) {
|
||||||
|
super(scene, x, y);
|
||||||
|
|
||||||
|
this.away = false;
|
||||||
|
|
||||||
|
this.graphics = this.scene.add.graphics();
|
||||||
|
this.add(this.graphics);
|
||||||
|
this.redraw();
|
||||||
|
|
||||||
|
this.scene.add.existing(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAway(away: boolean = true, instant: boolean = false): void {
|
||||||
|
if (this.away === away) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.away = away;
|
||||||
|
if (instant) {
|
||||||
|
this.redraw();
|
||||||
|
} else {
|
||||||
|
this.playStatusChangeAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private playStatusChangeAnimation(): void {
|
||||||
|
this.scale = 1;
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: [this],
|
||||||
|
duration: 200,
|
||||||
|
yoyo: true,
|
||||||
|
ease: Easing.BackEaseIn,
|
||||||
|
scale: 0,
|
||||||
|
onYoyo: () => {
|
||||||
|
this.redraw();
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
this.scale = 1;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private redraw(): void {
|
||||||
|
this.graphics.clear();
|
||||||
|
this.graphics.fillStyle(this.away ? this.COLORS.away : this.COLORS.online);
|
||||||
|
this.graphics.lineStyle(1, this.away ? this.COLORS.awayOutline : this.COLORS.onlineOutline);
|
||||||
|
this.graphics.fillCircle(0, 0, 3);
|
||||||
|
this.graphics.strokeCircle(0, 0, 3);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
import type { ITiledMapObject } from "../Map/ITiledMap";
|
import type { ITiledMapObject } from "../Map/ITiledMap";
|
||||||
import type { GameScene } from "../Game/GameScene";
|
import type { GameScene } from "../Game/GameScene";
|
||||||
import { type } from "os";
|
|
||||||
import { GameMapProperties } from "../Game/GameMapProperties";
|
import { GameMapProperties } from "../Game/GameMapProperties";
|
||||||
|
|
||||||
export class TextUtils {
|
export class TextUtils {
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation";
|
||||||
AnimationData,
|
|
||||||
getPlayerAnimations,
|
|
||||||
PlayerAnimationDirections,
|
|
||||||
PlayerAnimationTypes,
|
|
||||||
} from "../Player/Animation";
|
|
||||||
import { SpeechBubble } from "./SpeechBubble";
|
import { SpeechBubble } from "./SpeechBubble";
|
||||||
import Text = Phaser.GameObjects.Text;
|
import Text = Phaser.GameObjects.Text;
|
||||||
import Container = Phaser.GameObjects.Container;
|
import Container = Phaser.GameObjects.Container;
|
||||||
@ -24,6 +19,7 @@ import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
|||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
import { TalkIcon } from "../Components/TalkIcon";
|
import { TalkIcon } from "../Components/TalkIcon";
|
||||||
import { Deferred } from "ts-deferred";
|
import { Deferred } from "ts-deferred";
|
||||||
|
import { PlayerStatusDot } from "../Components/PlayerStatusDot";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
const interactiveRadius = 35;
|
const interactiveRadius = 35;
|
||||||
@ -32,6 +28,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
private bubble: SpeechBubble | null = null;
|
private bubble: SpeechBubble | null = null;
|
||||||
private readonly playerNameText: Text;
|
private readonly playerNameText: Text;
|
||||||
private readonly talkIcon: TalkIcon;
|
private readonly talkIcon: TalkIcon;
|
||||||
|
protected readonly statusDot: PlayerStatusDot;
|
||||||
public playerName: string;
|
public playerName: string;
|
||||||
public sprites: Map<string, Sprite>;
|
public sprites: Map<string, Sprite>;
|
||||||
protected lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
protected lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
||||||
@ -137,7 +134,8 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.playerNameText.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
this.playerNameText.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
||||||
this.add(this.playerNameText);
|
this.statusDot = new PlayerStatusDot(scene, this.playerNameText.getLeftCenter().x - 6, playerNameY - 1);
|
||||||
|
this.add([this.playerNameText, this.statusDot]);
|
||||||
|
|
||||||
this.setClickable(isClickable);
|
this.setClickable(isClickable);
|
||||||
|
|
||||||
@ -238,6 +236,10 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
this.talkIcon.show(show, forceClose);
|
this.talkIcon.show(show, forceClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setAwayStatus(away: boolean = true, instant: boolean = false): void {
|
||||||
|
this.statusDot.setAway(away, instant);
|
||||||
|
}
|
||||||
|
|
||||||
public addCompanion(name: string, texturePromise?: CancelablePromise<string>): void {
|
public addCompanion(name: string, texturePromise?: CancelablePromise<string>): void {
|
||||||
if (typeof texturePromise !== "undefined") {
|
if (typeof texturePromise !== "undefined") {
|
||||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
import { BodyResourceDescriptionInterface, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
||||||
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
|
@ -97,6 +97,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
this.camera.pan(setTo.x, setTo.y, duration, Easing.SineEaseOut, true, (camera, progress, x, y) => {
|
this.camera.pan(setTo.x, setTo.y, duration, Easing.SineEaseOut, true, (camera, progress, x, y) => {
|
||||||
if (this.cameraMode === CameraMode.Positioned) {
|
if (this.cameraMode === CameraMode.Positioned) {
|
||||||
this.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
this.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
||||||
@ -138,6 +139,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
|
|||||||
this.emit(CameraManagerEvent.CameraUpdate, this.getCameraUpdateEventData());
|
this.emit(CameraManagerEvent.CameraUpdate, this.getCameraUpdateEventData());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
this.camera.pan(focusOn.x, focusOn.y, duration, Easing.SineEaseOut, true, (camera, progress, x, y) => {
|
this.camera.pan(focusOn.x, focusOn.y, duration, Easing.SineEaseOut, true, (camera, progress, x, y) => {
|
||||||
this.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
this.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
||||||
if (progress === 1) {
|
if (progress === 1) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user