Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop

This commit is contained in:
_Bastler
2022-04-13 15:35:28 +02:00
182 changed files with 1413 additions and 2592 deletions
+163 -84
View File
@@ -1,45 +1,44 @@
import * as tg from "generic-type-guard";
import { z } from "zod";
import type { ButtonClickedEvent } from "./ButtonClickedEvent";
import type { ChatEvent } from "./ChatEvent";
import type { ClosePopupEvent } from "./ClosePopupEvent";
import { isChatEvent } from "./ChatEvent";
import { isClosePopupEvent } from "./ClosePopupEvent";
import type { EnterLeaveEvent } from "./EnterLeaveEvent";
import type { GoToPageEvent } from "./GoToPageEvent";
import type { LoadPageEvent } from "./LoadPageEvent";
import { isGoToPageEvent } from "./GoToPageEvent";
import { isLoadPageEvent } from "./LoadPageEvent";
import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent";
import type { OpenPopupEvent } from "./OpenPopupEvent";
import type { OpenTabEvent } from "./OpenTabEvent";
import { isOpenPopupEvent } from "./OpenPopupEvent";
import { isOpenTabEvent } from "./OpenTabEvent";
import type { UserInputChatEvent } from "./UserInputChatEvent";
import type { LayerEvent } from "./LayerEvent";
import type { SetPropertyEvent } from "./setPropertyEvent";
import type { LoadSoundEvent } from "./LoadSoundEvent";
import type { PlaySoundEvent } from "./PlaySoundEvent";
import { isLayerEvent } from "./LayerEvent";
import { isSetPropertyEvent } from "./setPropertyEvent";
import { isLoadSoundEvent } from "./LoadSoundEvent";
import { isPlaySoundEvent } from "./PlaySoundEvent";
import { isStopSoundEvent } from "./StopSoundEvent";
import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent";
import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent";
import type { SetTilesEvent } from "./SetTilesEvent";
import { isSetTilesEvent } from "./SetTilesEvent";
import type { SetVariableEvent } from "./SetVariableEvent";
import { isGameStateEvent } from "./GameStateEvent";
import { isMapDataEvent } from "./MapDataEvent";
import { isSetVariableEvent } from "./SetVariableEvent";
import type { EmbeddedWebsite } from "../iframe/Room/EmbeddedWebsite";
import { isCreateEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent";
import type { LoadTilesetEvent } from "./LoadTilesetEvent";
import { isCreateEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent";
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
import type { MessageReferenceEvent } 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 { isPlayerPosition } from "./PlayerPosition";
import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent";
import type { ChangeZoneEvent } from "./ChangeZoneEvent";
import type { CameraSetEvent } from "./CameraSetEvent";
import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
import { isCameraSetEvent } from "./CameraSetEvent";
import { isCameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
import { isColorEvent } from "./ColorEvent";
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent";
import type { AddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
import { isAddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent";
import type { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
import { isRemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
import { isGetPropertyEvent } from "./GetPropertyEvent";
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
*/
export type IframeEventMap = {
addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent;
removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent;
loadPage: LoadPageEvent;
chat: ChatEvent;
cameraFollowPlayer: CameraFollowPlayerEvent;
cameraSet: CameraSetEvent;
openPopup: OpenPopupEvent;
closePopup: ClosePopupEvent;
openTab: OpenTabEvent;
goToPage: GoToPageEvent;
disablePlayerControls: null;
restorePlayerControls: null;
displayBubble: null;
removeBubble: null;
onPlayerMove: undefined;
onOpenActionMenu: undefined;
onCameraUpdate: undefined;
showLayer: LayerEvent;
hideLayer: LayerEvent;
setProperty: SetPropertyEvent;
loadSound: LoadSoundEvent;
playSound: PlaySoundEvent;
stopSound: null;
getState: undefined;
loadTileset: LoadTilesetEvent;
registerMenu: MenuRegisterEvent;
unregisterMenu: UnregisterMenuEvent;
setTiles: SetTilesEvent;
modifyEmbeddedWebsite: Partial<EmbeddedWebsite>; // Note: name should be compulsory in fact
};
export interface IframeEvent<T extends keyof IframeEventMap> {
type: T;
data: IframeEventMap[T];
}
export const isIframeEventWrapper = z.union([
z.object({
type: z.literal("addActionsMenuKeyToRemotePlayer"),
data: isAddActionsMenuKeyToRemotePlayerEvent,
}),
z.object({
type: z.literal("removeActionsMenuKeyFromRemotePlayer"),
data: isRemoveActionsMenuKeyFromRemotePlayerEvent,
}),
z.object({
type: z.literal("loadPage"),
data: isLoadPageEvent,
}),
z.object({
type: z.literal("chat"),
data: isChatEvent,
}),
z.object({
type: z.literal("cameraFollowPlayer"),
data: isCameraFollowPlayerEvent,
}),
z.object({
type: z.literal("cameraSet"),
data: isCameraSetEvent,
}),
z.object({
type: z.literal("openPopup"),
data: isOpenPopupEvent,
}),
z.object({
type: z.literal("closePopup"),
data: isClosePopupEvent,
}),
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 const isIframeEventWrapper = (event: any): event is IframeEvent<keyof IframeEventMap> =>
typeof event.type === "string";
export type IframeEvent = z.infer<typeof isIframeEventWrapper>;
export interface IframeResponseEventMap {
userInputChat: UserInputChatEvent;
@@ -116,13 +184,18 @@ export const isIframeResponseEventWrapper = (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.
* Types are defined using Type guards that will actually bused to enforce and check types.
*/
export const iframeQueryMapTypeGuards = {
getState: {
query: tg.isUndefined,
query: z.undefined(),
answer: isGameStateEvent,
},
getProperty: {
@@ -130,63 +203,63 @@ export const iframeQueryMapTypeGuards = {
answer: isGetPropertyEvent,
},
getMapData: {
query: tg.isUndefined,
query: z.undefined(),
answer: isMapDataEvent,
},
setVariable: {
query: isSetVariableEvent,
answer: tg.isUndefined,
answer: z.undefined(),
},
loadTileset: {
query: isLoadTilesetEvent,
answer: tg.isNumber,
answer: z.number(),
},
openCoWebsite: {
query: isOpenCoWebsiteEvent,
answer: isCoWebsite,
},
getCoWebsites: {
query: tg.isUndefined,
answer: tg.isArray(isCoWebsite),
query: z.undefined(),
answer: z.array(isCoWebsite),
},
closeCoWebsite: {
query: tg.isString,
answer: tg.isUndefined,
query: z.string(),
answer: z.undefined(),
},
closeCoWebsites: {
query: tg.isUndefined,
answer: tg.isUndefined,
query: z.undefined(),
answer: z.undefined(),
},
triggerActionMessage: {
query: isTriggerActionMessageEvent,
answer: tg.isUndefined,
answer: z.undefined(),
},
removeActionMessage: {
query: isMessageReferenceEvent,
answer: tg.isUndefined,
answer: z.undefined(),
},
getEmbeddedWebsite: {
query: tg.isString,
query: z.string(),
answer: isCreateEmbeddedWebsiteEvent,
},
deleteEmbeddedWebsite: {
query: tg.isString,
answer: tg.isUndefined,
query: z.string(),
answer: z.undefined(),
},
createEmbeddedWebsite: {
query: isCreateEmbeddedWebsiteEvent,
answer: tg.isUndefined,
answer: z.undefined(),
},
setPlayerOutline: {
query: isColorEvent,
answer: tg.isUndefined,
answer: z.undefined(),
},
removePlayerOutline: {
query: tg.isUndefined,
answer: tg.isUndefined,
query: z.undefined(),
answer: z.undefined(),
},
getPlayerPosition: {
query: tg.isUndefined,
query: z.undefined(),
answer: isPlayerPosition,
},
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 UnknownToVoid<T> = undefined extends T ? void : T;
export type IframeQueryMap = {
[key in keyof IframeQueryMapTypeGuardsType]: {
query: GuardedType<IframeQueryMapTypeGuardsType[key]["query"]>;
answer: UnknownToVoid<GuardedType<IframeQueryMapTypeGuardsType[key]["answer"]>>;
query: z.infer<typeof iframeQueryMapTypeGuards[key]["query"]>;
answer: UnknownToVoid<z.infer<typeof iframeQueryMapTypeGuards[key]["answer"]>>;
};
};
@@ -230,11 +302,18 @@ export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQuer
return false;
}
const result = iframeQueryMapTypeGuards[type].query(event.data);
if (!result) {
try {
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.');
return false;
}
return result;
return true;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any