Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
export const isActionsMenuActionClickedEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionName: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isActionsMenuActionClickedEvent = z.object({
|
||||
id: z.number(),
|
||||
actionName: z.string(),
|
||||
});
|
||||
|
||||
export type ActionsMenuActionClickedEvent = tg.GuardedType<typeof isActionsMenuActionClickedEvent>;
|
||||
export type ActionsMenuActionClickedEvent = z.infer<typeof isActionsMenuActionClickedEvent>;
|
||||
|
||||
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()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionKey: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isAddActionsMenuKeyToRemotePlayerEvent = z.object({
|
||||
id: z.number(),
|
||||
actionKey: z.string(),
|
||||
});
|
||||
|
||||
export type AddActionsMenuKeyToRemotePlayerEvent = tg.GuardedType<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
||||
export type AddActionsMenuKeyToRemotePlayerEvent = z.infer<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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()
|
||||
.withProperties({
|
||||
id: tg.isOptional(tg.isString),
|
||||
})
|
||||
.get();
|
||||
export const isCloseCoWebsite = z.object({
|
||||
id: z.optional(z.string()),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
popupId: tg.isNumber,
|
||||
inputValue: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isClosePopupEvent = z.object({
|
||||
popupId: z.number(),
|
||||
inputValue: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
width: tg.isNumber,
|
||||
height: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
export const isRectangle = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
});
|
||||
|
||||
export const isEmbeddedWebsiteEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
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();
|
||||
// TODO: make a variation that is all optional (except for the name)
|
||||
export type Rectangle = z.infer<typeof isRectangle>;
|
||||
|
||||
export const isCreateEmbeddedWebsiteEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
name: tg.isString,
|
||||
url: tg.isString,
|
||||
position: isRectangle,
|
||||
})
|
||||
.withOptionalProperties({
|
||||
visible: tg.isBoolean,
|
||||
allowApi: tg.isBoolean,
|
||||
allow: tg.isString,
|
||||
origin: tg.isSingletonStringUnion("player", "map"),
|
||||
scale: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
export const isEmbeddedWebsiteEvent = z.object({
|
||||
name: z.string(),
|
||||
url: z.optional(z.string()),
|
||||
visible: z.optional(z.boolean()),
|
||||
allowApi: z.optional(z.boolean()),
|
||||
allow: z.optional(z.string()),
|
||||
x: z.optional(z.number()),
|
||||
y: z.optional(z.number()),
|
||||
width: z.optional(z.number()),
|
||||
height: z.optional(z.number()),
|
||||
origin: z.optional(z.enum(["player", "map"])),
|
||||
scale: z.optional(z.number()),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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>;
|
||||
// TODO: make a variation that is all optional (except for the name)
|
||||
export type Rectangle = tg.GuardedType<typeof isRectangle>;
|
||||
export const isCreateEmbeddedWebsiteEvent = z.object({
|
||||
name: z.string(),
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isGoToPageEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
direction: tg.isElementOf("right", "left", "up", "down"),
|
||||
moving: tg.isBoolean,
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
oldX: tg.isOptional(tg.isNumber),
|
||||
oldY: tg.isOptional(tg.isNumber),
|
||||
})
|
||||
.get();
|
||||
export const isHasPlayerMovedEvent = z.object({
|
||||
direction: z.enum(["right", "left", "up", "down"]),
|
||||
moving: z.boolean(),
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
oldX: z.optional(z.number()),
|
||||
oldY: z.optional(z.number()),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isLoadPageEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isLoadSoundEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isLoadTilesetEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
data: tg.isObject,
|
||||
})
|
||||
.get();
|
||||
export const isMapDataEvent = z.object({
|
||||
data: z.unknown(), // Todo : Typing
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
speed: tg.isOptional(tg.isNumber),
|
||||
})
|
||||
.get();
|
||||
export const isMovePlayerToEventConfig = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
speed: z.optional(z.number()),
|
||||
});
|
||||
|
||||
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()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
cancelled: tg.isBoolean,
|
||||
})
|
||||
.get();
|
||||
export const isMovePlayerToEventAnswer = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
cancelled: z.boolean(),
|
||||
});
|
||||
|
||||
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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
allowApi: tg.isOptional(tg.isBoolean),
|
||||
allowPolicy: tg.isOptional(tg.isString),
|
||||
widthPercent: tg.isOptional(tg.isNumber),
|
||||
position: tg.isOptional(tg.isNumber),
|
||||
closable: tg.isOptional(tg.isBoolean),
|
||||
lazy: tg.isOptional(tg.isBoolean),
|
||||
hint: tg.isOptional(tg.isString),
|
||||
})
|
||||
.get();
|
||||
export const isOpenCoWebsiteEvent = z.object({
|
||||
url: z.string(),
|
||||
allowApi: z.optional(z.boolean()),
|
||||
allowPolicy: z.optional(z.string()),
|
||||
widthPercent: z.optional(z.number()),
|
||||
position: z.optional(z.number()),
|
||||
closable: z.optional(z.boolean()),
|
||||
lazy: z.optional(z.boolean()),
|
||||
hint: z.optional(z.string()),
|
||||
});
|
||||
|
||||
export const isCoWebsite = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isCoWebsite = z.object({
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
label: tg.isString,
|
||||
className: tg.isOptional(tg.isString),
|
||||
})
|
||||
.get();
|
||||
export const isButtonDescriptor = z.object({
|
||||
label: z.string(),
|
||||
className: z.optional(z.string()),
|
||||
});
|
||||
|
||||
export const isOpenPopupEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
popupId: tg.isNumber,
|
||||
targetObject: tg.isString,
|
||||
message: tg.isString,
|
||||
buttons: tg.isArray(isButtonDescriptor),
|
||||
popupClass: tg.isString,
|
||||
input: tg.isBoolean,
|
||||
})
|
||||
.get();
|
||||
export const isOpenPopupEvent = z.object({
|
||||
popupId: z.number(),
|
||||
targetObject: z.string(),
|
||||
message: z.string(),
|
||||
buttons: z.array(isButtonDescriptor),
|
||||
popupClass: z.string(),
|
||||
input: z.boolean(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isOpenTabEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
volume: tg.isOptional(tg.isNumber),
|
||||
loop: tg.isOptional(tg.isBoolean),
|
||||
mute: tg.isOptional(tg.isBoolean),
|
||||
rate: tg.isOptional(tg.isNumber),
|
||||
detune: tg.isOptional(tg.isNumber),
|
||||
seek: tg.isOptional(tg.isNumber),
|
||||
delay: tg.isOptional(tg.isNumber),
|
||||
})
|
||||
.get();
|
||||
export const isSoundConfig = z.object({
|
||||
volume: z.optional(z.number()),
|
||||
loop: z.optional(z.boolean()),
|
||||
mute: z.optional(z.boolean()),
|
||||
rate: z.optional(z.number()),
|
||||
detune: z.optional(z.number()),
|
||||
seek: z.optional(z.number()),
|
||||
delay: z.optional(z.number()),
|
||||
});
|
||||
|
||||
export const isPlaySoundEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
config: tg.isOptional(isSoundConfig),
|
||||
})
|
||||
.get();
|
||||
export const isPlaySoundEvent = z.object({
|
||||
url: z.string(),
|
||||
config: z.optional(isSoundConfig),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
export const isPlayerPosition = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
});
|
||||
|
||||
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
|
||||
export const isRemotePlayerClickedEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
export const isRemotePlayerClickedEvent = z.object({
|
||||
id: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionKey: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = z.object({
|
||||
id: z.number(),
|
||||
actionKey: z.string(),
|
||||
});
|
||||
|
||||
export type RemoveActionsMenuKeyFromRemotePlayerEvent = tg.GuardedType<
|
||||
typeof isRemoveActionsMenuKeyFromRemotePlayerEvent
|
||||
>;
|
||||
export type RemoveActionsMenuKeyFromRemotePlayerEvent = z.infer<typeof isRemoveActionsMenuKeyFromRemotePlayerEvent>;
|
||||
|
||||
export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = (
|
||||
event: RemoveActionsMenuKeyFromRemotePlayerEvent
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
export const isSetTilesEvent = tg.isArray(
|
||||
new tg.IsInterface()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
tile: tg.isUnion(tg.isUnion(tg.isNumber, tg.isString), tg.isNull),
|
||||
layer: tg.isString,
|
||||
})
|
||||
.get()
|
||||
export const isSetTilesEvent = z.array(
|
||||
z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
tile: z.union([z.number(), z.string(), z.null()]),
|
||||
layer: z.string(),
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
export type SetVariableEvent = tg.GuardedType<typeof isSetVariableEvent>;
|
||||
|
||||
export const isSetVariableIframeEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
type: tg.isSingletonString("setVariable"),
|
||||
data: isSetVariableEvent,
|
||||
})
|
||||
.get();
|
||||
export type SetVariableEvent = z.infer<typeof isSetVariableEvent>;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
export const isStopSoundEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
url: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isStopSoundEvent = z.object({
|
||||
url: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
width: tg.isNumber,
|
||||
height: tg.isNumber,
|
||||
zoom: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
export const isWasCameraUpdatedEvent = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
zoom: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* A message sent from the game to the iFrame to notify a movement from the camera.
|
||||
*/
|
||||
|
||||
export type WasCameraUpdatedEvent = tg.GuardedType<typeof isWasCameraUpdatedEvent>;
|
||||
export type WasCameraUpdatedEvent = z.infer<typeof isWasCameraUpdatedEvent>;
|
||||
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
export const isUnregisterMenuEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
name: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isUnregisterMenuEvent = z.object({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
export type UnregisterMenuEvent = tg.GuardedType<typeof isUnregisterMenuEvent>;
|
||||
export type UnregisterMenuEvent = z.infer<typeof isUnregisterMenuEvent>;
|
||||
|
||||
export const isMenuRegisterOptions = new tg.IsInterface()
|
||||
.withProperties({
|
||||
allowApi: tg.isBoolean,
|
||||
})
|
||||
.get();
|
||||
export const isMenuRegisterOptions = z.object({
|
||||
allowApi: z.boolean(),
|
||||
});
|
||||
|
||||
/**
|
||||
* A message sent from a script to the game to add a custom menu from the menu
|
||||
*/
|
||||
export const isMenuRegisterEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
name: tg.isString,
|
||||
iframe: tg.isUnion(tg.isString, tg.isUndefined),
|
||||
options: isMenuRegisterOptions,
|
||||
})
|
||||
.get();
|
||||
export const isMenuRegisterEvent = z.object({
|
||||
name: z.string(),
|
||||
iframe: z.optional(z.string()),
|
||||
options: isMenuRegisterOptions,
|
||||
});
|
||||
|
||||
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 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()
|
||||
.withProperties({
|
||||
message: tg.isString,
|
||||
uuid: tg.isString,
|
||||
type: isActionMessageType,
|
||||
})
|
||||
.get();
|
||||
export const isTriggerActionMessageEvent = z.object({
|
||||
message: z.string(),
|
||||
uuid: z.string(),
|
||||
type: isActionMessageType,
|
||||
});
|
||||
|
||||
export type TriggerActionMessageEvent = tg.GuardedType<typeof isTriggerActionMessageEvent>;
|
||||
export type TriggerActionMessageEvent = z.infer<typeof isTriggerActionMessageEvent>;
|
||||
|
||||
export const isMessageReferenceEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
uuid: tg.isString,
|
||||
})
|
||||
.get();
|
||||
export const isMessageReferenceEvent = z.object({
|
||||
uuid: z.string(),
|
||||
});
|
||||
|
||||
export type MessageReferenceEvent = tg.GuardedType<typeof isMessageReferenceEvent>;
|
||||
export type MessageReferenceEvent = z.infer<typeof isMessageReferenceEvent>;
|
||||
|
||||
@@ -5,20 +5,16 @@ import {
|
||||
triggerActionMessage,
|
||||
} from "./TriggerActionMessageEvent";
|
||||
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
const isTriggerMessageEventObject = new tg.IsInterface()
|
||||
.withProperties({
|
||||
type: tg.isSingletonString(triggerActionMessage),
|
||||
data: isTriggerActionMessageEvent,
|
||||
})
|
||||
.get();
|
||||
const isTriggerMessageEventObject = z.object({
|
||||
type: z.enum([triggerActionMessage]),
|
||||
data: isTriggerActionMessageEvent,
|
||||
});
|
||||
|
||||
const isTriggerMessageRemoveEventObject = new tg.IsInterface()
|
||||
.withProperties({
|
||||
type: tg.isSingletonString(removeActionMessage),
|
||||
data: isMessageReferenceEvent,
|
||||
})
|
||||
.get();
|
||||
const isTriggerMessageRemoveEventObject = z.object({
|
||||
type: z.enum([removeActionMessage]),
|
||||
data: isMessageReferenceEvent,
|
||||
});
|
||||
|
||||
export const isTriggerMessageHandlerEvent = tg.isUnion(isTriggerMessageEventObject, isTriggerMessageRemoveEventObject);
|
||||
export const isTriggerMessageHandlerEvent = z.union([isTriggerMessageEventObject, isTriggerMessageRemoveEventObject]);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Subject } from "rxjs";
|
||||
import { isChatEvent } from "./Events/ChatEvent";
|
||||
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
||||
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
|
||||
import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent";
|
||||
import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent";
|
||||
import { OpenPopupEvent } from "./Events/OpenPopupEvent";
|
||||
import { OpenTabEvent } from "./Events/OpenTabEvent";
|
||||
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
|
||||
import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
|
||||
import { ClosePopupEvent } from "./Events/ClosePopupEvent";
|
||||
import { scriptUtils } from "./ScriptUtils";
|
||||
import { isGoToPageEvent } from "./Events/GoToPageEvent";
|
||||
import {
|
||||
IframeErrorAnswerEvent,
|
||||
IframeQueryMap,
|
||||
@@ -15,35 +13,28 @@ import {
|
||||
IframeResponseEventMap,
|
||||
isIframeEventWrapper,
|
||||
isIframeQueryWrapper,
|
||||
isLookingLikeIframeEventWrapper,
|
||||
} from "./Events/IframeEvent";
|
||||
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
||||
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
|
||||
import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
|
||||
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
|
||||
import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent";
|
||||
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
||||
import { PlaySoundEvent } from "./Events/PlaySoundEvent";
|
||||
import { StopSoundEvent } from "./Events/StopSoundEvent";
|
||||
import { LoadSoundEvent } from "./Events/LoadSoundEvent";
|
||||
import { SetPropertyEvent } from "./Events/setPropertyEvent";
|
||||
import { LayerEvent } from "./Events/LayerEvent";
|
||||
import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent";
|
||||
import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
||||
import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./Events/ui/MenuRegisterEvent";
|
||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
||||
import { SetTilesEvent } from "./Events/SetTilesEvent";
|
||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||
import { ModifyEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||
import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore";
|
||||
import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent";
|
||||
import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
|
||||
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
||||
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
|
||||
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
||||
import { CameraSetEvent } from "./Events/CameraSetEvent";
|
||||
import { CameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
||||
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
|
||||
import {
|
||||
AddActionsMenuKeyToRemotePlayerEvent,
|
||||
isAddActionsMenuKeyToRemotePlayerEvent,
|
||||
} from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
||||
import { AddActionsMenuKeyToRemotePlayerEvent } from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
||||
import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent";
|
||||
import {
|
||||
isRemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||
RemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||
} from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||
import { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||
|
||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||
query: IframeQueryMap[T]["query"],
|
||||
@@ -153,8 +144,10 @@ class IframeListener {
|
||||
|
||||
const payload = message.data;
|
||||
|
||||
const lookingLikeEvent = isLookingLikeIframeEventWrapper.safeParse(payload);
|
||||
|
||||
if (foundSrc === undefined || iframe === undefined) {
|
||||
if (isIframeEventWrapper(payload)) {
|
||||
if (lookingLikeEvent.success) {
|
||||
console.warn(
|
||||
"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 " +
|
||||
@@ -224,63 +217,70 @@ class IframeListener {
|
||||
} catch (reason) {
|
||||
errorHandler(reason);
|
||||
}
|
||||
} else if (isIframeEventWrapper(payload)) {
|
||||
if (payload.type === "showLayer" && isLayerEvent(payload.data)) {
|
||||
this._showLayerStream.next(payload.data);
|
||||
} else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) {
|
||||
this._hideLayerStream.next(payload.data);
|
||||
} else if (payload.type === "setProperty" && isSetPropertyEvent(payload.data)) {
|
||||
this._setPropertyStream.next(payload.data);
|
||||
} else if (payload.type === "cameraSet" && isCameraSetEvent(payload.data)) {
|
||||
this._cameraSetStream.next(payload.data);
|
||||
} else if (payload.type === "cameraFollowPlayer" && isCameraFollowPlayerEvent(payload.data)) {
|
||||
this._cameraFollowPlayerStream.next(payload.data);
|
||||
} else if (payload.type === "chat" && isChatEvent(payload.data)) {
|
||||
scriptUtils.sendAnonymousChat(payload.data);
|
||||
} else if (payload.type === "openPopup" && isOpenPopupEvent(payload.data)) {
|
||||
this._openPopupStream.next(payload.data);
|
||||
} else if (payload.type === "closePopup" && isClosePopupEvent(payload.data)) {
|
||||
this._closePopupStream.next(payload.data);
|
||||
} else if (payload.type === "openTab" && isOpenTabEvent(payload.data)) {
|
||||
scriptUtils.openTab(payload.data.url);
|
||||
} else if (payload.type === "goToPage" && isGoToPageEvent(payload.data)) {
|
||||
scriptUtils.goToPage(payload.data.url);
|
||||
} else if (payload.type === "loadPage" && isLoadPageEvent(payload.data)) {
|
||||
this._loadPageStream.next(payload.data.url);
|
||||
} else if (payload.type === "playSound" && isPlaySoundEvent(payload.data)) {
|
||||
this._playSoundStream.next(payload.data);
|
||||
} else if (payload.type === "stopSound" && isStopSoundEvent(payload.data)) {
|
||||
this._stopSoundStream.next(payload.data);
|
||||
} else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) {
|
||||
this._loadSoundStream.next(payload.data);
|
||||
} else if (payload.type === "disablePlayerControls") {
|
||||
} else if (lookingLikeEvent.success) {
|
||||
const iframeEventGuarded = isIframeEventWrapper.safeParse(lookingLikeEvent.data);
|
||||
|
||||
if (!iframeEventGuarded.success) {
|
||||
console.error(
|
||||
`Invalid event "${lookingLikeEvent.data.type}" received from Iframe: `,
|
||||
lookingLikeEvent.data,
|
||||
iframeEventGuarded.error.issues
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const iframeEvent = iframeEventGuarded.data;
|
||||
|
||||
if (iframeEvent.type === "showLayer") {
|
||||
this._showLayerStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "hideLayer") {
|
||||
this._hideLayerStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "setProperty") {
|
||||
this._setPropertyStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "cameraSet") {
|
||||
this._cameraSetStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "cameraFollowPlayer") {
|
||||
this._cameraFollowPlayerStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "chat") {
|
||||
scriptUtils.sendAnonymousChat(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "openPopup") {
|
||||
this._openPopupStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type === "closePopup") {
|
||||
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();
|
||||
} else if (payload.type === "restorePlayerControls") {
|
||||
} else if (iframeEvent.type === "restorePlayerControls") {
|
||||
this._enablePlayerControlStream.next();
|
||||
} else if (payload.type === "displayBubble") {
|
||||
} else if (iframeEvent.type === "displayBubble") {
|
||||
this._displayBubbleStream.next();
|
||||
} else if (payload.type === "removeBubble") {
|
||||
} else if (iframeEvent.type === "removeBubble") {
|
||||
this._removeBubbleStream.next();
|
||||
} else if (payload.type == "onPlayerMove") {
|
||||
} else if (iframeEvent.type == "onPlayerMove") {
|
||||
this.sendPlayerMove = true;
|
||||
} else if (
|
||||
payload.type == "addActionsMenuKeyToRemotePlayer" &&
|
||||
isAddActionsMenuKeyToRemotePlayerEvent(payload.data)
|
||||
) {
|
||||
this._addActionsMenuKeyToRemotePlayerStream.next(payload.data);
|
||||
} else if (
|
||||
payload.type == "removeActionsMenuKeyFromRemotePlayer" &&
|
||||
isRemoveActionsMenuKeyFromRemotePlayerEvent(payload.data)
|
||||
) {
|
||||
this._removeActionsMenuKeyFromRemotePlayerEvent.next(payload.data);
|
||||
} else if (payload.type == "onCameraUpdate") {
|
||||
} else if (iframeEvent.type == "addActionsMenuKeyToRemotePlayer") {
|
||||
this._addActionsMenuKeyToRemotePlayerStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type == "removeActionsMenuKeyFromRemotePlayer") {
|
||||
this._removeActionsMenuKeyFromRemotePlayerEvent.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type == "onCameraUpdate") {
|
||||
this._trackCameraUpdateStream.next();
|
||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
||||
this._setTilesStream.next(payload.data);
|
||||
} else if (payload.type == "modifyEmbeddedWebsite" && isEmbeddedWebsiteEvent(payload.data)) {
|
||||
this._modifyEmbeddedWebsiteStream.next(payload.data);
|
||||
} else if (payload.type == "registerMenu" && isMenuRegisterEvent(payload.data)) {
|
||||
const dataName = payload.data.name;
|
||||
} else if (iframeEvent.type == "setTiles") {
|
||||
this._setTilesStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type == "modifyEmbeddedWebsite") {
|
||||
this._modifyEmbeddedWebsiteStream.next(iframeEvent.data);
|
||||
} else if (iframeEvent.type == "registerMenu") {
|
||||
const dataName = iframeEvent.data.name;
|
||||
this.iframeCloseCallbacks.get(iframe)?.push(() => {
|
||||
handleMenuUnregisterEvent(dataName);
|
||||
});
|
||||
@@ -288,13 +288,17 @@ class IframeListener {
|
||||
foundSrc = this.getBaseUrl(foundSrc, message.source);
|
||||
|
||||
handleMenuRegistrationEvent(
|
||||
payload.data.name,
|
||||
payload.data.iframe,
|
||||
iframeEvent.data.name,
|
||||
iframeEvent.data.iframe,
|
||||
foundSrc,
|
||||
payload.data.options
|
||||
iframeEvent.data.options
|
||||
);
|
||||
} else if (payload.type == "unregisterMenu" && isUnregisterMenuEvent(payload.data)) {
|
||||
handleMenuUnregisterEvent(payload.data.name);
|
||||
} else if (iframeEvent.type == "unregisterMenu") {
|
||||
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> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
console.info("Loading map related script at ", scriptUrl);
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import type * as tg from "generic-type-guard";
|
||||
import type {
|
||||
IframeEvent,
|
||||
IframeEventMap,
|
||||
IframeQuery,
|
||||
IframeQueryMap,
|
||||
IframeResponseEventMap,
|
||||
} from "../Events/IframeEvent";
|
||||
import { z } from "zod";
|
||||
import type { IframeEvent, IframeQuery, IframeQueryMap, IframeResponseEventMap } 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, "*");
|
||||
}
|
||||
|
||||
@@ -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<
|
||||
Key extends keyof IframeResponseEventMap,
|
||||
T = IframeResponseEventMap[Key],
|
||||
Guard = tg.TypeGuard<T>
|
||||
Guard = z.ZodType<T>
|
||||
> {
|
||||
typeChecker: Guard;
|
||||
callback: (payloadData: T) => void;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { sendToWorkadventure } from "../IframeApiContribution";
|
||||
import type {
|
||||
CreateEmbeddedWebsiteEvent,
|
||||
ModifyEmbeddedWebsiteEvent,
|
||||
Rectangle,
|
||||
} from "../../Events/EmbeddedWebsiteEvent";
|
||||
import type { CreateEmbeddedWebsiteEvent, Rectangle } from "../../Events/EmbeddedWebsiteEvent";
|
||||
|
||||
export class EmbeddedWebsite {
|
||||
public readonly name: string;
|
||||
|
||||
@@ -41,7 +41,7 @@ export class WorkAdventureCameraCommands extends IframeApiContribution<WorkAdven
|
||||
onCameraUpdate(): Subject<WasCameraUpdatedEvent> {
|
||||
sendToWorkadventure({
|
||||
type: "onCameraUpdate",
|
||||
data: null,
|
||||
data: undefined,
|
||||
});
|
||||
return moveStream;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ export class WorkadventureControlsCommands extends IframeApiContribution<Workadv
|
||||
callbacks = [];
|
||||
|
||||
disablePlayerControls(): void {
|
||||
sendToWorkadventure({ type: "disablePlayerControls", data: null });
|
||||
sendToWorkadventure({ type: "disablePlayerControls", data: undefined });
|
||||
}
|
||||
|
||||
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);
|
||||
sendToWorkadventure({
|
||||
type: "onPlayerMove",
|
||||
data: null,
|
||||
data: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import type { LoadSoundEvent } from "../Events/LoadSoundEvent";
|
||||
import type { PlaySoundEvent } from "../Events/PlaySoundEvent";
|
||||
import type { StopSoundEvent } from "../Events/StopSoundEvent";
|
||||
import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution";
|
||||
import { IframeApiContribution } from "./IframeApiContribution";
|
||||
import { Sound } from "./Sound/Sound";
|
||||
|
||||
export class WorkadventureSoundCommands extends IframeApiContribution<WorkadventureSoundCommands> {
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { Observable, Subject } from "rxjs";
|
||||
|
||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
||||
|
||||
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
||||
import { IframeApiContribution, queryWorkadventure } from "./IframeApiContribution";
|
||||
import { apiCallback } from "./registeredCallbacks";
|
||||
import { isSetVariableEvent, SetVariableEvent } from "../Events/SetVariableEvent";
|
||||
|
||||
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
||||
|
||||
export class WorkadventureStateCommands extends IframeApiContribution<WorkadventureStateCommands> {
|
||||
private setVariableResolvers = new Subject<SetVariableEvent>();
|
||||
private variables = new Map<string, unknown>();
|
||||
@@ -17,7 +13,7 @@ export class WorkadventureStateCommands extends IframeApiContribution<Workadvent
|
||||
super();
|
||||
|
||||
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.
|
||||
// No need to do this check since it is already performed in SharedVariablesManager
|
||||
/*if (JSON.stringify(oldValue) === JSON.stringify(event.value)) {
|
||||
@@ -92,6 +88,7 @@ export function createState(target: "global" | "player"): WorkadventureStateComm
|
||||
}
|
||||
return target.loadVariable(p.toString());
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
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.
|
||||
// User must use WA.state.saveVariable to have error message.
|
||||
|
||||
@@ -34,14 +34,6 @@ interface MenuDescriptor {
|
||||
|
||||
export type MenuOptions = RequireOnlyOne<MenuDescriptor, "callback" | "iframe">;
|
||||
|
||||
interface ZonedPopupOptions {
|
||||
zone: string;
|
||||
objectLayerName?: string;
|
||||
popupText: string;
|
||||
delay?: number;
|
||||
popupOptions: Array<ButtonDescriptor>;
|
||||
}
|
||||
|
||||
export interface ActionMessageOptions {
|
||||
message: string;
|
||||
type?: "message" | "warning";
|
||||
@@ -284,11 +276,11 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
||||
}
|
||||
|
||||
public displayBubble(): void {
|
||||
sendToWorkadventure({ type: "displayBubble", data: null });
|
||||
sendToWorkadventure({ type: "displayBubble", data: undefined });
|
||||
}
|
||||
|
||||
public removeBubble(): void {
|
||||
sendToWorkadventure({ type: "removeBubble", data: null });
|
||||
sendToWorkadventure({ type: "removeBubble", data: undefined });
|
||||
}
|
||||
|
||||
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 type { CreateEmbeddedWebsiteEvent } from "../Events/EmbeddedWebsiteEvent";
|
||||
|
||||
|
||||
@@ -271,10 +271,6 @@
|
||||
.cowebsite-thumbnail-hint {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -42,4 +42,4 @@ axiosWithRetry.interceptors.response.use((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 { GameConnexionTypes, urlManager } from "../Url/UrlManager";
|
||||
import { localUserStore } from "./LocalUserStore";
|
||||
import { CharacterTexture, LocalUser } from "./LocalUser";
|
||||
import { LocalUser } from "./LocalUser";
|
||||
import { Room } from "./Room";
|
||||
import { _ServiceWorker } from "../Network/ServiceWorker";
|
||||
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
||||
@@ -13,7 +13,6 @@ import { analyticsClient } from "../Administration/AnalyticsClient";
|
||||
import { axiosWithRetry } from "./AxiosUtils";
|
||||
import axios from "axios";
|
||||
import { isRegisterData } from "../Messages/JsonMessages/RegisterData";
|
||||
import { isAdminApiData } from "../Messages/JsonMessages/AdminApiData";
|
||||
import { limitMapStore } from "../Stores/GameStore";
|
||||
import { showLimitRoomModalStore } from "../Stores/ModalStore";
|
||||
import { gameManager } from "../Phaser/Game/GameManager";
|
||||
@@ -74,9 +73,7 @@ class ConnectionManager {
|
||||
|
||||
//Logout user in pusher and hydra
|
||||
const token = localUserStore.getAuthToken();
|
||||
const { authToken } = await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then(
|
||||
(res) => res.data
|
||||
);
|
||||
await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then((res) => res.data);
|
||||
localUserStore.setAuthToken(null);
|
||||
|
||||
//Go on login page can permit to clear token and start authentication process
|
||||
@@ -140,13 +137,19 @@ class ConnectionManager {
|
||||
//@deprecated
|
||||
else if (this.connexionType === GameConnexionTypes.register) {
|
||||
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
|
||||
);
|
||||
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.");
|
||||
}
|
||||
|
||||
const data = registerDataChecking.data;
|
||||
|
||||
this.localUser = new LocalUser(data.userUuid, data.email);
|
||||
this.authToken = data.authToken;
|
||||
localUserStore.saveUser(this.localUser);
|
||||
@@ -307,9 +310,9 @@ class ConnectionManager {
|
||||
connection.roomJoinedMessageStream.subscribe((connect: OnConnectInterface) => {
|
||||
resolve(connect);
|
||||
});
|
||||
}).catch((err) => {
|
||||
}).catch(() => {
|
||||
// Let's retry in 4-6 seconds
|
||||
return new Promise<OnConnectInterface>((resolve, reject) => {
|
||||
return new Promise<OnConnectInterface>((resolve) => {
|
||||
this.reconnectingTimeout = setTimeout(() => {
|
||||
//todo: allow a way to break recursion?
|
||||
//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 {
|
||||
x: 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;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface MessageUserPositionInterface {
|
||||
name: string;
|
||||
characterLayers: BodyResourceDescriptionInterface[];
|
||||
position: PointInterface;
|
||||
away: boolean;
|
||||
visitCardUrl: string | null;
|
||||
companion: string | null;
|
||||
userUuid: string;
|
||||
@@ -29,6 +30,7 @@ export interface MessageUserJoined {
|
||||
name: string;
|
||||
characterLayers: BodyResourceDescriptionInterface[];
|
||||
position: PointInterface;
|
||||
away: boolean;
|
||||
visitCardUrl: string | null;
|
||||
companion: string | null;
|
||||
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 type { CharacterTexture } from "./LocalUser";
|
||||
import { localUserStore } from "./LocalUserStore";
|
||||
import axios from "axios";
|
||||
import { axiosWithRetry } from "./AxiosUtils";
|
||||
@@ -112,11 +109,14 @@ export class Room {
|
||||
data.authenticationMandatory = Boolean(data.authenticationMandatory);
|
||||
}
|
||||
|
||||
if (isRoomRedirect(data)) {
|
||||
const roomRedirectChecking = isRoomRedirect.safeParse(data);
|
||||
const mapDetailsDataChecking = isMapDetailsData.safeParse(data);
|
||||
|
||||
if (roomRedirectChecking.success) {
|
||||
return {
|
||||
redirectUrl: data.redirectUrl,
|
||||
};
|
||||
} else if (isMapDetailsData(data)) {
|
||||
} else if (mapDetailsDataChecking.success) {
|
||||
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
||||
this._mapUrl = data.mapUrl;
|
||||
this._group = data.group;
|
||||
@@ -132,6 +132,9 @@ export class Room {
|
||||
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
|
||||
return new MapDetail(data.mapUrl);
|
||||
} 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.");
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -190,7 +190,7 @@ export class RoomConnection implements RoomConnection {
|
||||
|
||||
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.
|
||||
const pingMessage = PingMessageTsProto.encode({}).finish();
|
||||
interval = setInterval(() => this.socket.send(pingMessage), manualPingDelay);
|
||||
@@ -297,6 +297,7 @@ export class RoomConnection implements RoomConnection {
|
||||
}
|
||||
default: {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -477,6 +478,7 @@ export class RoomConnection implements RoomConnection {
|
||||
}
|
||||
default: {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -518,6 +520,20 @@ export class RoomConnection implements RoomConnection {
|
||||
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) {
|
||||
let message: SetPlayerDetailsMessageTsProto;
|
||||
if (color === null) {
|
||||
@@ -654,6 +670,7 @@ export class RoomConnection implements RoomConnection {
|
||||
characterLayers,
|
||||
visitCardUrl: message.visitCardUrl,
|
||||
position: ProtobufClientUtils.toPointInterface(position),
|
||||
away: message.away,
|
||||
companion: companion ? companion.name : null,
|
||||
userUuid: message.userUuid,
|
||||
outlineColor: message.hasOutline ? message.outlineColor : undefined,
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { PointInterface } from "../Connexion/ConnexionModels";
|
||||
|
||||
export class ProtobufClientUtils {
|
||||
public static toPointInterface(position: PositionMessage): PointInterface {
|
||||
let direction: string;
|
||||
let direction: "up" | "down" | "left" | "right";
|
||||
switch (position.direction) {
|
||||
case PositionMessage_Direction.UP:
|
||||
direction = "up";
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
||||
import { DirtyScene } from "../Game/DirtyScene";
|
||||
import { gameManager } from "../Game/GameManager";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import Image = Phaser.GameObjects.Image;
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
|
||||
const TextName: string = "Loading...";
|
||||
@@ -35,8 +33,6 @@ export class Loader {
|
||||
const logoResource = gameManager.currentStartedRoom.loadingLogo ?? "static/images/logo.png";
|
||||
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
|
||||
this.loadingText = this.scene.add.text(
|
||||
this.scene.game.renderer.width / 2,
|
||||
|
||||
@@ -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 { GameScene } from "../Game/GameScene";
|
||||
import { type } from "os";
|
||||
import { GameMapProperties } from "../Game/GameMapProperties";
|
||||
|
||||
export class TextUtils {
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
AnimationData,
|
||||
getPlayerAnimations,
|
||||
PlayerAnimationDirections,
|
||||
PlayerAnimationTypes,
|
||||
} from "../Player/Animation";
|
||||
import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation";
|
||||
import { SpeechBubble } from "./SpeechBubble";
|
||||
import Text = Phaser.GameObjects.Text;
|
||||
import Container = Phaser.GameObjects.Container;
|
||||
@@ -24,6 +19,7 @@ import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import { TalkIcon } from "../Components/TalkIcon";
|
||||
import { Deferred } from "ts-deferred";
|
||||
import { PlayerStatusDot } from "../Components/PlayerStatusDot";
|
||||
|
||||
const playerNameY = -25;
|
||||
const interactiveRadius = 35;
|
||||
@@ -32,6 +28,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
||||
private bubble: SpeechBubble | null = null;
|
||||
private readonly playerNameText: Text;
|
||||
private readonly talkIcon: TalkIcon;
|
||||
protected readonly statusDot: PlayerStatusDot;
|
||||
public playerName: string;
|
||||
public sprites: Map<string, Sprite>;
|
||||
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.add(this.playerNameText);
|
||||
this.statusDot = new PlayerStatusDot(scene, this.playerNameText.getLeftCenter().x - 6, playerNameY - 1);
|
||||
this.add([this.playerNameText, this.statusDot]);
|
||||
|
||||
this.setClickable(isClickable);
|
||||
|
||||
@@ -238,6 +236,10 @@ export abstract class Character extends Container implements OutlineableInterfac
|
||||
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 {
|
||||
if (typeof texturePromise !== "undefined") {
|
||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
||||
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
||||
import { BodyResourceDescriptionInterface, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
|
||||
@@ -97,6 +97,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
|
||||
});
|
||||
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) => {
|
||||
if (this.cameraMode === CameraMode.Positioned) {
|
||||
this.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
||||
@@ -138,6 +139,7 @@ export class CameraManager extends Phaser.Events.EventEmitter {
|
||||
this.emit(CameraManagerEvent.CameraUpdate, this.getCameraUpdateEventData());
|
||||
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.waScaleManager.zoomModifier = currentZoomModifier + progress * zoomModifierChange;
|
||||
if (progress === 1) {
|
||||
|
||||
@@ -223,7 +223,7 @@ height,*/
|
||||
}
|
||||
|
||||
close(): void {
|
||||
for (const [key, website] of this.embeddedWebsites) {
|
||||
for (const website of this.embeddedWebsites.values()) {
|
||||
if (website.allowApi) {
|
||||
iframeListener.unregisterIframe(website.iframe);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { SKIP_RENDER_OPTIMIZATIONS } from "../../Enum/EnvironmentVariable";
|
||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { ResizableScene } from "../Login/ResizableScene";
|
||||
|
||||
const Events = Phaser.Core.Events;
|
||||
|
||||
@@ -202,6 +202,8 @@ export class GameMap {
|
||||
|
||||
/**
|
||||
* Registers a callback called when the user moves inside another zone.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public onEnterZone(callback: zoneChangeCallback) {
|
||||
this.enterZoneCallbacks.push(callback);
|
||||
@@ -209,6 +211,8 @@ export class GameMap {
|
||||
|
||||
/**
|
||||
* Registers a callback called when the user moves outside another zone.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public onLeaveZone(callback: zoneChangeCallback) {
|
||||
this.leaveZoneCallbacks.push(callback);
|
||||
|
||||
@@ -112,7 +112,7 @@ export class GameMapPropertiesListener {
|
||||
}
|
||||
});
|
||||
|
||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue, oldValue) => {
|
||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_SCENE_URL, (newValue) => {
|
||||
if (newValue) {
|
||||
this.scene
|
||||
.onMapExit(
|
||||
@@ -130,7 +130,7 @@ export class GameMapPropertiesListener {
|
||||
}
|
||||
});
|
||||
|
||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue, oldValue) => {
|
||||
this.gameMap.onPropertyChange(GameMapProperties.EXIT_URL, (newValue) => {
|
||||
if (newValue) {
|
||||
this.scene
|
||||
.onMapExit(Room.getRoomPathFromExitUrl(newValue as string, window.location.toString()))
|
||||
@@ -142,7 +142,7 @@ export class GameMapPropertiesListener {
|
||||
}
|
||||
});
|
||||
|
||||
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue, oldValue) => {
|
||||
this.gameMap.onPropertyChange(GameMapProperties.SILENT, (newValue) => {
|
||||
if (newValue === undefined || newValue === false || newValue === "") {
|
||||
this.scene.connection?.setSilent(false);
|
||||
this.scene.CurrentPlayer.noSilent();
|
||||
@@ -162,7 +162,7 @@ export class GameMapPropertiesListener {
|
||||
});
|
||||
|
||||
// TODO: This legacy property should be removed at some point
|
||||
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue, oldValue) => {
|
||||
this.gameMap.onPropertyChange(GameMapProperties.PLAY_AUDIO_LOOP, (newValue) => {
|
||||
newValue === undefined
|
||||
? audioManagerFileStore.unloadAudio()
|
||||
: audioManagerFileStore.playAudio(newValue, this.scene.getMapDirUrl(), undefined, true);
|
||||
|
||||
@@ -71,7 +71,7 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor
|
||||
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||
import { playersStore } from "../../Stores/PlayersStore";
|
||||
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
||||
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||
import { jitsiParticipantsCountStore, userIsAdminStore, userIsJitsiDominantSpeakerStore } from "../../Stores/GameStore";
|
||||
import { contactPageStore } from "../../Stores/MenuStore";
|
||||
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
|
||||
import { audioManagerFileStore } from "../../Stores/AudioManagerStore";
|
||||
@@ -98,11 +98,11 @@ import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||
import type { VideoPeer } from "../../WebRtc/VideoPeer";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { Deferred } from "ts-deferred";
|
||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||
import { PlayerDetailsUpdatedMessage } from "../../Messages/ts-proto-generated/protos/messages";
|
||||
import { privacyShutdownStore } from "../../Stores/PrivacyShutdownStore";
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface | null;
|
||||
reconnecting: boolean;
|
||||
@@ -178,7 +178,9 @@ export class GameScene extends DirtyScene {
|
||||
|
||||
private localVolumeStoreUnsubscriber: Unsubscriber | undefined;
|
||||
private followUsersColorStoreUnsubscribe!: Unsubscriber;
|
||||
private currentPlayerGroupIdStoreUnsubscribe!: Unsubscriber;
|
||||
private privacyShutdownStoreUnsubscribe!: Unsubscriber;
|
||||
private userIsJitsiDominantSpeakerStoreUnsubscriber!: Unsubscriber;
|
||||
private jitsiParticipantsCountStoreUnsubscriber!: Unsubscriber;
|
||||
|
||||
private biggestAvailableAreaStoreUnsubscribe!: () => void;
|
||||
MapUrlFile: string;
|
||||
@@ -188,7 +190,7 @@ export class GameScene extends DirtyScene {
|
||||
currentTick!: number;
|
||||
lastSentTick!: number; // The last tick at which a position was sent.
|
||||
lastMoveEventSent: HasPlayerMovedEvent = {
|
||||
direction: "",
|
||||
direction: "down",
|
||||
moving: false,
|
||||
x: -1000,
|
||||
y: -1000,
|
||||
@@ -222,6 +224,8 @@ export class GameScene extends DirtyScene {
|
||||
private firstCameraUpdateSent: boolean = false;
|
||||
private showVoiceIndicatorChangeMessageSent: boolean = false;
|
||||
private currentPlayerGroupId?: number;
|
||||
private jitsiDominantSpeaker: boolean = false;
|
||||
private jitsiParticipantsCount: number = 0;
|
||||
public readonly superLoad: SuperLoaderPlugin;
|
||||
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
|
||||
@@ -664,16 +668,7 @@ export class GameScene extends DirtyScene {
|
||||
if (volume === undefined) {
|
||||
return;
|
||||
}
|
||||
const aboveTreshold = volume > talkIconVolumeTreshold;
|
||||
this.CurrentPlayer.showTalkIcon(aboveTreshold);
|
||||
|
||||
if (this.showVoiceIndicatorChangeMessageSent && !aboveTreshold) {
|
||||
this.connection?.emitPlayerShowVoiceIndicator(false);
|
||||
this.showVoiceIndicatorChangeMessageSent = false;
|
||||
} else if (!this.showVoiceIndicatorChangeMessageSent && aboveTreshold) {
|
||||
this.connection?.emitPlayerShowVoiceIndicator(true);
|
||||
this.showVoiceIndicatorChangeMessageSent = true;
|
||||
}
|
||||
this.tryChangeShowVoiceIndicatorState(volume > talkIconVolumeTreshold);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -689,6 +684,18 @@ export class GameScene extends DirtyScene {
|
||||
oldPeersNumber = peers.size;
|
||||
});
|
||||
|
||||
this.userIsJitsiDominantSpeakerStoreUnsubscriber = userIsJitsiDominantSpeakerStore.subscribe(
|
||||
(dominantSpeaker) => {
|
||||
this.jitsiDominantSpeaker = dominantSpeaker;
|
||||
this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1);
|
||||
}
|
||||
);
|
||||
|
||||
this.jitsiParticipantsCountStoreUnsubscriber = jitsiParticipantsCountStore.subscribe((participantsCount) => {
|
||||
this.jitsiParticipantsCount = participantsCount;
|
||||
this.tryChangeShowVoiceIndicatorState(this.jitsiDominantSpeaker && this.jitsiParticipantsCount > 1);
|
||||
});
|
||||
|
||||
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
||||
if (emote) {
|
||||
this.CurrentPlayer?.playEmote(emote.unicode);
|
||||
@@ -715,6 +722,10 @@ export class GameScene extends DirtyScene {
|
||||
}
|
||||
});
|
||||
|
||||
this.privacyShutdownStoreUnsubscribe = privacyShutdownStore.subscribe((away) => {
|
||||
this.connection?.emitPlayerAway(away);
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
this.connectionAnswerPromiseDeferred.promise as Promise<unknown>,
|
||||
...scriptPromises,
|
||||
@@ -773,6 +784,7 @@ export class GameScene extends DirtyScene {
|
||||
characterLayers: message.characterLayers,
|
||||
name: message.name,
|
||||
position: message.position,
|
||||
away: message.away,
|
||||
visitCardUrl: message.visitCardUrl,
|
||||
companion: message.companion,
|
||||
userUuid: message.userUuid,
|
||||
@@ -1051,6 +1063,7 @@ export class GameScene extends DirtyScene {
|
||||
}, 100);
|
||||
|
||||
id = 0;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for (const button of openPopupEvent.buttons) {
|
||||
const button = HtmlUtils.getElementByIdOrFail<HTMLButtonElement>(
|
||||
`popup-${openPopupEvent.popupId}-${id}`
|
||||
@@ -1326,7 +1339,7 @@ export class GameScene extends DirtyScene {
|
||||
await this.connectionAnswerPromiseDeferred.promise;
|
||||
return {
|
||||
mapUrl: this.MapUrlFile,
|
||||
startLayerName: this.startPositionCalculator.startLayerName,
|
||||
startLayerName: this.startPositionCalculator.startLayerName ?? undefined,
|
||||
uuid: localUserStore.getLocalUser()?.uuid,
|
||||
nickname: this.playerName,
|
||||
language: get(locale),
|
||||
@@ -1435,6 +1448,7 @@ export class GameScene extends DirtyScene {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const _exhaustiveCheck: never = event.target;
|
||||
}
|
||||
}
|
||||
@@ -1454,7 +1468,7 @@ export class GameScene extends DirtyScene {
|
||||
this.connection?.emitPlayerOutlineColor(color);
|
||||
});
|
||||
|
||||
iframeListener.registerAnswerer("removePlayerOutline", (message) => {
|
||||
iframeListener.registerAnswerer("removePlayerOutline", () => {
|
||||
this.CurrentPlayer.removeApiOutlineColor();
|
||||
this.connection?.emitPlayerOutlineColor(null);
|
||||
});
|
||||
@@ -1597,7 +1611,10 @@ export class GameScene extends DirtyScene {
|
||||
this.emoteUnsubscribe();
|
||||
this.emoteMenuUnsubscribe();
|
||||
this.followUsersColorStoreUnsubscribe();
|
||||
this.privacyShutdownStoreUnsubscribe();
|
||||
this.biggestAvailableAreaStoreUnsubscribe();
|
||||
this.userIsJitsiDominantSpeakerStoreUnsubscriber();
|
||||
this.jitsiParticipantsCountStoreUnsubscriber();
|
||||
iframeListener.unregisterAnswerer("getState");
|
||||
iframeListener.unregisterAnswerer("loadTileset");
|
||||
iframeListener.unregisterAnswerer("getMapData");
|
||||
@@ -1734,6 +1751,7 @@ export class GameScene extends DirtyScene {
|
||||
private createCollisionWithPlayer() {
|
||||
//add collision layer
|
||||
for (const phaserLayer of this.gameMap.phaserLayers) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
this.physics.add.collider(this.CurrentPlayer, phaserLayer, (object1: GameObject, object2: GameObject) => {
|
||||
//this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name)
|
||||
});
|
||||
@@ -1784,9 +1802,11 @@ export class GameScene extends DirtyScene {
|
||||
emoteMenuStore.openEmoteMenu();
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OVER, (pointer: Phaser.Input.Pointer) => {
|
||||
this.CurrentPlayer.pointerOverOutline(0x365dff);
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OUT, (pointer: Phaser.Input.Pointer) => {
|
||||
this.CurrentPlayer.pointerOutOutline();
|
||||
});
|
||||
@@ -1888,6 +1908,7 @@ export class GameScene extends DirtyScene {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const tmp: never = event;
|
||||
}
|
||||
}
|
||||
@@ -1967,6 +1988,9 @@ export class GameScene extends DirtyScene {
|
||||
if (addPlayerData.outlineColor !== undefined) {
|
||||
player.setApiOutlineColor(addPlayerData.outlineColor);
|
||||
}
|
||||
if (addPlayerData.away !== undefined) {
|
||||
player.setAwayStatus(addPlayerData.away, true);
|
||||
}
|
||||
this.MapPlayers.add(player);
|
||||
this.MapPlayersByKey.set(player.userId, player);
|
||||
player.updatePosition(addPlayerData.position);
|
||||
@@ -1996,6 +2020,17 @@ export class GameScene extends DirtyScene {
|
||||
});
|
||||
}
|
||||
|
||||
private tryChangeShowVoiceIndicatorState(show: boolean): void {
|
||||
this.CurrentPlayer.showTalkIcon(show);
|
||||
if (this.showVoiceIndicatorChangeMessageSent && !show) {
|
||||
this.connection?.emitPlayerShowVoiceIndicator(false);
|
||||
this.showVoiceIndicatorChangeMessageSent = false;
|
||||
} else if (!this.showVoiceIndicatorChangeMessageSent && show) {
|
||||
this.connection?.emitPlayerShowVoiceIndicator(true);
|
||||
this.showVoiceIndicatorChangeMessageSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
private doRemovePlayer(userId: number) {
|
||||
const player = this.MapPlayersByKey.get(userId);
|
||||
if (player === undefined) {
|
||||
@@ -2035,8 +2070,6 @@ export class GameScene extends DirtyScene {
|
||||
this.currentTick,
|
||||
{
|
||||
...message.position,
|
||||
oldX: undefined,
|
||||
oldY: undefined,
|
||||
},
|
||||
this.currentTick + POSITION_DELAY
|
||||
);
|
||||
@@ -2107,6 +2140,9 @@ export class GameScene extends DirtyScene {
|
||||
if (message.details?.showVoiceIndicator !== undefined) {
|
||||
character.showTalkIcon(message.details?.showVoiceIndicator);
|
||||
}
|
||||
if (message.details?.away !== undefined) {
|
||||
character.setAwayStatus(message.details?.away);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface PlayerInterface {
|
||||
visitCardUrl: string | null;
|
||||
companion: string | null;
|
||||
userUuid: string;
|
||||
away: boolean;
|
||||
color?: string;
|
||||
outlineColor?: number;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@ import type { ITiledMapObject } from "../../Map/ITiledMap";
|
||||
import type { ItemFactoryInterface } from "../ItemFactoryInterface";
|
||||
import type { GameScene } from "../../Game/GameScene";
|
||||
import { ActionableItem } from "../ActionableItem";
|
||||
import * as tg from "generic-type-guard";
|
||||
import { z } from "zod";
|
||||
|
||||
const isComputerState = new tg.IsInterface()
|
||||
.withProperties({
|
||||
status: tg.isString,
|
||||
})
|
||||
.get();
|
||||
type ComputerState = tg.GuardedType<typeof isComputerState>;
|
||||
export const isComputerState = z.object({
|
||||
status: z.string(),
|
||||
});
|
||||
|
||||
export type ComputerState = z.infer<typeof isComputerState>;
|
||||
|
||||
let state: ComputerState = {
|
||||
status: "off",
|
||||
@@ -55,10 +54,14 @@ export default {
|
||||
},
|
||||
factory: (scene: GameScene, object: ITiledMapObject, initState: unknown): ActionableItem => {
|
||||
if (initState !== undefined) {
|
||||
if (!isComputerState(initState)) {
|
||||
throw new Error("Invalid state received for computer object");
|
||||
try {
|
||||
state = isComputerState.parse(initState);
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
console.error(err.issues);
|
||||
}
|
||||
throw new Error(`Invalid state received for computer object`);
|
||||
}
|
||||
state = initState;
|
||||
}
|
||||
|
||||
const computer = new Sprite(scene, object.x, object.y, "computer");
|
||||
|
||||
@@ -9,7 +9,6 @@ import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||
import {
|
||||
CustomWokaBodyPart,
|
||||
@@ -95,6 +94,7 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
}
|
||||
|
||||
public create(): void {
|
||||
waScaleManager.zoomModifier = 1;
|
||||
this.createSlotBackgroundTextures();
|
||||
this.initializeCustomWokaPreviewer();
|
||||
this.initializeBodyPartsDraggableGrid();
|
||||
@@ -112,6 +112,7 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
this.onResize();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public update(time: number, dt: number): void {
|
||||
this.customWokaPreviewer.update();
|
||||
}
|
||||
@@ -141,18 +142,19 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
|
||||
gameManager.setCharacterLayers(layers);
|
||||
this.scene.stop(CustomizeSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
gameManager.tryResumingGame(EnableCameraSceneName);
|
||||
}
|
||||
|
||||
public backToPreviousScene() {
|
||||
this.scene.stop(CustomizeSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
this.scene.run(SelectCharacterSceneName);
|
||||
}
|
||||
|
||||
private createSlotBackgroundTextures(): void {
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
if (this.textures.getTextureKeys().includes(`floorTexture${i}`)) {
|
||||
continue;
|
||||
}
|
||||
TexturesHelper.createFloorRectangleTexture(this, `floorTexture${i}`, 50, 50, "floorTiles", i);
|
||||
}
|
||||
}
|
||||
@@ -467,11 +469,6 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
private bindEventHandlers(): void {
|
||||
this.bindKeyboardEventHandlers();
|
||||
|
||||
this.events.addListener("wake", () => {
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
|
||||
});
|
||||
|
||||
this.randomizeButton.on(Phaser.Input.Events.POINTER_UP, () => {
|
||||
this.randomizeOutfit();
|
||||
this.clearGrid();
|
||||
|
||||
@@ -13,5 +13,6 @@ export class EmptyScene extends Scene {
|
||||
|
||||
create() {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
update(time: number, delta: number): void {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { gameManager } from "../Game/GameManager";
|
||||
import { ResizableScene } from "./ResizableScene";
|
||||
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
|
||||
export const EnableCameraSceneName = "EnableCameraScene";
|
||||
@@ -25,6 +24,7 @@ export class EnableCameraScene extends ResizableScene {
|
||||
|
||||
public onResize(): void {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
update(time: number, delta: number): void {}
|
||||
|
||||
public login(): void {
|
||||
|
||||
@@ -7,8 +7,6 @@ import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { get } from "svelte/store";
|
||||
import { localeDetector } from "../../i18n/locales";
|
||||
import { PlayerTextures } from "../Entity/PlayerTextures";
|
||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||
|
||||
export const EntrySceneName = "EntryScene";
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export class LoginScene extends ResizableScene {
|
||||
loginSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
update(time: number, delta: number): void {}
|
||||
|
||||
public onResize(): void {}
|
||||
|
||||
@@ -28,7 +28,7 @@ export class Player extends Character {
|
||||
companionTexturePromise?: CancelablePromise<string>
|
||||
) {
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
||||
|
||||
this.statusDot.setVisible(false);
|
||||
//the current player model should be push away by other players to prevent conflict
|
||||
this.getBody().setImmovable(false);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { TextField } from "../Components/TextField";
|
||||
import Image = Phaser.GameObjects.Image;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ export class WaScaleManager {
|
||||
const { width: gameWidth, height: gameHeight } = coWebsiteManager.getGameSize();
|
||||
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
||||
|
||||
const { game: gameSize, real: realSize } = this.hdpiManager.getOptimalGameSize({
|
||||
const { real: realSize } = this.hdpiManager.getOptimalGameSize({
|
||||
width: gameWidth * devicePixelRatio,
|
||||
height: gameHeight * devicePixelRatio,
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
|
||||
gameObjects: Phaser.GameObjects.GameObject[],
|
||||
deltaX: number,
|
||||
deltaY: number,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
deltaZ: number
|
||||
): void {
|
||||
this.gameScene.zoomByFactor(1 - (deltaY / 53) * 0.1);
|
||||
@@ -55,7 +56,7 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
|
||||
.then((path) => {
|
||||
// Remove first step as it is for the tile we are currently standing on
|
||||
path.shift();
|
||||
this.gameScene.CurrentPlayer.setPathToFollow(path).catch((reason) => { });
|
||||
this.gameScene.CurrentPlayer.setPathToFollow(path).catch(() => { });
|
||||
})
|
||||
.catch((reason) => {
|
||||
console.warn(reason);
|
||||
|
||||
@@ -91,7 +91,7 @@ function createAudioManagerFileStore() {
|
||||
});
|
||||
},
|
||||
unloadAudio: () => {
|
||||
update((file: string) => {
|
||||
update(() => {
|
||||
audioManagerVolumeStore.setLoop(false);
|
||||
return "";
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ function createCoWebsiteStore() {
|
||||
return {
|
||||
subscribe,
|
||||
add: (coWebsite: CoWebsite, position?: number) => {
|
||||
coWebsite.getStateSubscriber().subscribe((value) => {
|
||||
coWebsite.getStateSubscriber().subscribe(() => {
|
||||
update((currentArray) => currentArray);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,6 @@ function createCoWebsiteStore() {
|
||||
if (position === 0) {
|
||||
return [coWebsite, ...currentArray];
|
||||
} else if (currentArray.length > position) {
|
||||
const test = [...currentArray.splice(position, 0, coWebsite)];
|
||||
return [...currentArray.splice(position, 0, coWebsite)];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { derived, writable, Writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const activeRowStore = writable(0);
|
||||
|
||||
@@ -45,7 +45,4 @@ function createHighlightedEmbedScreenStore() {
|
||||
export const highlightedEmbedScreen = createHighlightedEmbedScreenStore();
|
||||
export const embedScreenLayout = writable<LayoutMode>(LayoutMode.Presentation);
|
||||
|
||||
export const hasEmbedScreen = derived(
|
||||
[streamableCollectionStore],
|
||||
($values) => get(streamableCollectionStore).size + get(coWebsites).length > 0
|
||||
);
|
||||
export const hasEmbedScreen = derived([], () => get(streamableCollectionStore).size + get(coWebsites).length > 0);
|
||||
|
||||
@@ -10,7 +10,7 @@ interface ErrorMessage {
|
||||
* A store that contains a list of error messages to be displayed.
|
||||
*/
|
||||
function createErrorStore() {
|
||||
const { subscribe, set, update } = writable<ErrorMessage[]>([]);
|
||||
const { subscribe, update } = writable<ErrorMessage[]>([]);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
@@ -6,4 +6,8 @@ export const requestVisitCardsStore = writable<string | null>(null);
|
||||
|
||||
export const userIsAdminStore = writable(false);
|
||||
|
||||
export const userIsJitsiDominantSpeakerStore = writable(false);
|
||||
|
||||
export const jitsiParticipantsCountStore = writable(0);
|
||||
|
||||
export const limitMapStore = writable(false);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { derived, writable } from "svelte/store";
|
||||
import type { ActivatablesManager } from "../Phaser/Game/ActivatablesManager";
|
||||
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
|
||||
|
||||
export interface LayoutManagerAction {
|
||||
|
||||
@@ -11,13 +11,12 @@ import { peerStore } from "./PeerStore";
|
||||
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
||||
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
|
||||
import { SoundMeter } from "../Phaser/Components/SoundMeter";
|
||||
import { visibilityStore } from "./VisibilityStore";
|
||||
|
||||
/**
|
||||
* A store that contains the camera state requested by the user (on or off).
|
||||
*/
|
||||
function createRequestedCameraState() {
|
||||
const { subscribe, set, update } = writable(true);
|
||||
const { subscribe, set } = writable(true);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
@@ -30,7 +29,7 @@ function createRequestedCameraState() {
|
||||
* A store that contains the microphone state requested by the user (on or off).
|
||||
*/
|
||||
function createRequestedMicrophoneState() {
|
||||
const { subscribe, set, update } = writable(true);
|
||||
const { subscribe, set } = writable(true);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
@@ -43,7 +42,7 @@ function createRequestedMicrophoneState() {
|
||||
* A store that contains whether the EnableCameraScene is shown or not.
|
||||
*/
|
||||
function createEnableCameraSceneVisibilityStore() {
|
||||
const { subscribe, set, update } = writable(false);
|
||||
const { subscribe, set } = writable(false);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
@@ -147,7 +146,7 @@ export const cameraEnergySavingStore = derived(
|
||||
* A store that contains video constraints.
|
||||
*/
|
||||
function createVideoConstraintStore() {
|
||||
const { subscribe, set, update } = writable({
|
||||
const { subscribe, update } = writable({
|
||||
width: { min: 640, ideal: 1280, max: 1920 },
|
||||
height: { min: 400, ideal: 720 },
|
||||
frameRate: { ideal: localUserStore.getVideoQualityValue() },
|
||||
@@ -190,7 +189,7 @@ export const videoConstraintStore = createVideoConstraintStore();
|
||||
* A store that contains video constraints.
|
||||
*/
|
||||
function createAudioConstraintStore() {
|
||||
const { subscribe, set, update } = writable({
|
||||
const { subscribe, update } = writable({
|
||||
//TODO: make these values configurable in the game settings menu and store them in localstorage
|
||||
autoGainControl: false,
|
||||
echoCancellation: true,
|
||||
@@ -242,7 +241,6 @@ export const mediaStreamConstraintsStore = derived(
|
||||
privacyShutdownStore,
|
||||
cameraEnergySavingStore,
|
||||
isSilentStore,
|
||||
visibilityStore,
|
||||
],
|
||||
(
|
||||
[
|
||||
@@ -255,7 +253,6 @@ export const mediaStreamConstraintsStore = derived(
|
||||
$privacyShutdownStore,
|
||||
$cameraEnergySavingStore,
|
||||
$isSilentStore,
|
||||
$visibilityStore,
|
||||
],
|
||||
set
|
||||
) => {
|
||||
|
||||
@@ -2,8 +2,6 @@ import { writable } from "svelte/store";
|
||||
import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
|
||||
import type { RoomConnection } from "../Connexion/RoomConnection";
|
||||
import { getRandomColor } from "../WebRtc/ColorGenerator";
|
||||
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||
import room from "../Api/iframe/room";
|
||||
|
||||
let idCount = 0;
|
||||
|
||||
@@ -30,6 +28,7 @@ function createPlayersStore() {
|
||||
visitCardUrl: message.visitCardUrl,
|
||||
companion: message.companion,
|
||||
userUuid: message.userUuid,
|
||||
away: message.away,
|
||||
color: getRandomColor(),
|
||||
});
|
||||
return users;
|
||||
@@ -59,6 +58,7 @@ function createPlayersStore() {
|
||||
characterLayers: [],
|
||||
visitCardUrl: null,
|
||||
companion: null,
|
||||
away: false,
|
||||
userUuid: "dummy",
|
||||
color: getRandomColor(),
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { visibilityStore } from "./VisibilityStore";
|
||||
function createPrivacyShutdownStore() {
|
||||
let privacyEnabled = false;
|
||||
|
||||
const { subscribe, set, update } = writable(privacyEnabled);
|
||||
const { subscribe, set } = writable(privacyEnabled);
|
||||
|
||||
visibilityStore.subscribe((isVisible) => {
|
||||
if (!isVisible && get(peerStore).size === 0) {
|
||||
|
||||
@@ -9,7 +9,7 @@ declare const navigator: any; // eslint-disable-line @typescript-eslint/no-expli
|
||||
* A store that contains the camera state requested by the user (on or off).
|
||||
*/
|
||||
function createRequestedScreenSharingState() {
|
||||
const { subscribe, set, update } = writable(false);
|
||||
const { subscribe, set } = writable(false);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { derived, writable, Writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const selectCharacterSceneVisibleStore = writable(false);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { derived, writable, Writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const selectCompanionSceneVisibleStore = writable(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { writable } from "svelte/store";
|
||||
* A store that contains the URL of the sound currently playing
|
||||
*/
|
||||
function createSoundPlayingStore() {
|
||||
const { subscribe, set, update } = writable<string | null>(null);
|
||||
const { subscribe, set } = writable<string | null>(null);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Readable, writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
/**
|
||||
* A store that contains the map starting layers names
|
||||
|
||||
@@ -100,7 +100,7 @@ export class PathfindingManager {
|
||||
start: { x: number; y: number },
|
||||
end: { x: number; y: number }
|
||||
): Promise<{ x: number; y: number }[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve) => {
|
||||
this.easyStar.findPath(start.x, start.y, end.x, end.y, (path) => {
|
||||
if (path === null) {
|
||||
resolve([]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import type { Readable, Writable } from "svelte/store";
|
||||
import type { Readable } from "svelte/store";
|
||||
|
||||
export type CoWebsiteState = "asleep" | "loading" | "ready";
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class CoWebsiteManager {
|
||||
trails: number[] | undefined;
|
||||
};
|
||||
|
||||
private resizeObserver = new ResizeObserver((entries) => {
|
||||
private resizeObserver = new ResizeObserver(() => {
|
||||
this.resizeAllIframes();
|
||||
});
|
||||
|
||||
@@ -223,7 +223,7 @@ class CoWebsiteManager {
|
||||
this.fire();
|
||||
};
|
||||
|
||||
this.cowebsiteAsideHolderDom.addEventListener("mousedown", (event) => {
|
||||
this.cowebsiteAsideHolderDom.addEventListener("mousedown", () => {
|
||||
if (this.isFullScreen) return;
|
||||
const coWebsite = this.getMainCoWebsite();
|
||||
|
||||
@@ -240,7 +240,7 @@ class CoWebsiteManager {
|
||||
document.addEventListener("mousemove", movecallback);
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", (event) => {
|
||||
document.addEventListener("mouseup", () => {
|
||||
if (!this.resizing || this.isFullScreen) return;
|
||||
document.removeEventListener("mousemove", movecallback);
|
||||
const coWebsite = this.getMainCoWebsite();
|
||||
@@ -277,7 +277,7 @@ class CoWebsiteManager {
|
||||
document.addEventListener("touchmove", movecallback);
|
||||
});
|
||||
|
||||
document.addEventListener("touchend", (event) => {
|
||||
document.addEventListener("touchend", () => {
|
||||
if (!this.resizing || this.isFullScreen) return;
|
||||
this.previousTouchMoveCoordinates = null;
|
||||
document.removeEventListener("touchmove", movecallback);
|
||||
@@ -298,7 +298,7 @@ class CoWebsiteManager {
|
||||
}
|
||||
|
||||
private transitionListeners() {
|
||||
this.cowebsiteDom.addEventListener("transitionend", (event) => {
|
||||
this.cowebsiteDom.addEventListener("transitionend", () => {
|
||||
if (this.cowebsiteDom.classList.contains("loading")) {
|
||||
this.fire();
|
||||
}
|
||||
@@ -552,7 +552,7 @@ class CoWebsiteManager {
|
||||
}
|
||||
|
||||
coWebsite.unload().catch((err) => {
|
||||
console.error("Cannot unload cowebsite on remove from stack");
|
||||
console.error("Cannot unload cowebsite on remove from stack", err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ export function getColorRgbFromHue(hue: number): { r: number; g: number; b: numb
|
||||
return hsv_to_rgb(hue, 0.5, 0.95);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function stringToDouble(string: string): number {
|
||||
let num = 1;
|
||||
for (const char of string.split("")) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user