Merge branch 'gamestate-api-read' of github.com:jonnytest1/workadventure into metadataScriptingApi
This commit is contained in:
commit
201fcf6afa
8393
front/package-lock.json
generated
Normal file
8393
front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
front/src/Api/Events/DataLayerEvent.ts
Normal file
16
front/src/Api/Events/DataLayerEvent.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const isHasDataLayerChangedEvent =
|
||||||
|
new tg.IsInterface().withProperties({
|
||||||
|
data: tg.isObject
|
||||||
|
}).get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers
|
||||||
|
*/
|
||||||
|
export type DataLayerEvent = tg.GuardedType<typeof isHasDataLayerChangedEvent>;
|
||||||
|
|
||||||
|
|
||||||
|
export type HasDataLayerChangedEventCallback = (event: DataLayerEvent) => void
|
27
front/src/Api/Events/GameStateEvent.ts
Normal file
27
front/src/Api/Events/GameStateEvent.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
/*export const isPositionState = new tg.IsInterface().withProperties({
|
||||||
|
x: tg.isNumber,
|
||||||
|
y: tg.isNumber
|
||||||
|
}).get()
|
||||||
|
export const isPlayerState = new tg.IsInterface()
|
||||||
|
.withStringIndexSignature(
|
||||||
|
new tg.IsInterface().withProperties({
|
||||||
|
position: isPositionState,
|
||||||
|
pusherId: tg.isUnion(tg.isNumber, tg.isUndefined)
|
||||||
|
}).get()
|
||||||
|
).get()
|
||||||
|
|
||||||
|
export type PlayerStateObject = tg.GuardedType<typeof isPlayerState>;*/
|
||||||
|
|
||||||
|
export const isGameStateEvent =
|
||||||
|
new tg.IsInterface().withProperties({
|
||||||
|
roomId: tg.isString,
|
||||||
|
mapUrl: tg.isString,
|
||||||
|
uuid: tg.isUnion(tg.isString, tg.isUndefined),
|
||||||
|
startLayerName: tg.isUnion(tg.isString, tg.isNull)
|
||||||
|
}).get();
|
||||||
|
/**
|
||||||
|
* A message sent from the game to the iFrame when the gameState is got by the script
|
||||||
|
*/
|
||||||
|
export type GameStateEvent = tg.GuardedType<typeof isGameStateEvent>;
|
19
front/src/Api/Events/HasPlayerMovedEvent.ts
Normal file
19
front/src/Api/Events/HasPlayerMovedEvent.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const isHasPlayerMovedEvent =
|
||||||
|
new tg.IsInterface().withProperties({
|
||||||
|
direction: tg.isString,
|
||||||
|
moving: tg.isBoolean,
|
||||||
|
x: tg.isNumber,
|
||||||
|
y: tg.isNumber
|
||||||
|
}).get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the game to the iFrame when the player move after the iFrame send a message to the game that it want to listen to the position of the player
|
||||||
|
*/
|
||||||
|
export type HasPlayerMovedEvent = tg.GuardedType<typeof isHasPlayerMovedEvent>;
|
||||||
|
|
||||||
|
|
||||||
|
export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void
|
@ -1,24 +1,25 @@
|
|||||||
|
|
||||||
|
import type { GameStateEvent } from './GameStateEvent';
|
||||||
import type { ButtonClickedEvent } from './ButtonClickedEvent';
|
import type { ButtonClickedEvent } from './ButtonClickedEvent';
|
||||||
import type { ChatEvent } from './ChatEvent';
|
import type { ChatEvent } from './ChatEvent';
|
||||||
import type { ClosePopupEvent } from './ClosePopupEvent';
|
import type { ClosePopupEvent } from './ClosePopupEvent';
|
||||||
import type { EnterLeaveEvent } from './EnterLeaveEvent';
|
import type { EnterLeaveEvent } from './EnterLeaveEvent';
|
||||||
import type { GoToPageEvent } from './GoToPageEvent';
|
import type { GoToPageEvent } from './GoToPageEvent';
|
||||||
|
import type { HasPlayerMovedEvent } from './HasPlayerMovedEvent';
|
||||||
import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent';
|
import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent';
|
||||||
import type { OpenPopupEvent } from './OpenPopupEvent';
|
import type { OpenPopupEvent } from './OpenPopupEvent';
|
||||||
import type { OpenTabEvent } from './OpenTabEvent';
|
import type { OpenTabEvent } from './OpenTabEvent';
|
||||||
import type { UserInputChatEvent } from './UserInputChatEvent';
|
import type { UserInputChatEvent } from './UserInputChatEvent';
|
||||||
|
import type { HasDataLayerChangedEvent } from "./HasDataLayerChangedEvent";
|
||||||
import type { LayerEvent } from './LayerEvent';
|
import type { LayerEvent } from './LayerEvent';
|
||||||
import type { SetPropertyEvent } from "./setPropertyEvent";
|
import type { SetPropertyEvent } from "./setPropertyEvent";
|
||||||
|
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T
|
data: T
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IframeEventMap = {
|
export type IframeEventMap = {
|
||||||
//getState: GameStateEvent,
|
getState: GameStateEvent,
|
||||||
// updateTile: UpdateTileEvent
|
// updateTile: UpdateTileEvent
|
||||||
chat: ChatEvent,
|
chat: ChatEvent,
|
||||||
openPopup: OpenPopupEvent
|
openPopup: OpenPopupEvent
|
||||||
@ -31,6 +32,8 @@ export type IframeEventMap = {
|
|||||||
restorePlayerControls: null
|
restorePlayerControls: null
|
||||||
displayBubble: null
|
displayBubble: null
|
||||||
removeBubble: null
|
removeBubble: null
|
||||||
|
onPlayerMove: undefined
|
||||||
|
onDataLayerChange: undefined
|
||||||
showLayer: LayerEvent
|
showLayer: LayerEvent
|
||||||
hideLayer: LayerEvent
|
hideLayer: LayerEvent
|
||||||
setProperty: SetPropertyEvent
|
setProperty: SetPropertyEvent
|
||||||
@ -49,7 +52,9 @@ export interface IframeResponseEventMap {
|
|||||||
enterEvent: EnterLeaveEvent
|
enterEvent: EnterLeaveEvent
|
||||||
leaveEvent: EnterLeaveEvent
|
leaveEvent: EnterLeaveEvent
|
||||||
buttonClickedEvent: ButtonClickedEvent
|
buttonClickedEvent: ButtonClickedEvent
|
||||||
// gameState: GameStateEvent
|
gameState: GameStateEvent
|
||||||
|
hasPlayerMoved: HasPlayerMovedEvent
|
||||||
|
hasDataLayerChanged: HasDataLayerChangedEvent
|
||||||
}
|
}
|
||||||
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
|
||||||
type: T;
|
type: T;
|
||||||
|
@ -13,6 +13,12 @@ import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMa
|
|||||||
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
|
||||||
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
import { isLayerEvent, LayerEvent } from "./Events/LayerEvent";
|
||||||
import { isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent";
|
import { isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent";
|
||||||
|
import { GameStateEvent } from './Events/GameStateEvent';
|
||||||
|
import { deepFreezeClone as deepFreezeClone } from '../utility';
|
||||||
|
import { HasPlayerMovedEvent } from './Events/HasPlayerMovedEvent';
|
||||||
|
import { Math } from 'phaser';
|
||||||
|
import { HasDataLayerChangedEvent } from "./Events/HasDataLayerChangedEvent";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,6 +26,7 @@ import { isSetPropertyEvent, SetPropertyEvent} from "./Events/setPropertyEvent";
|
|||||||
* Also allows to send messages to those iframes.
|
* Also allows to send messages to those iframes.
|
||||||
*/
|
*/
|
||||||
class IframeListener {
|
class IframeListener {
|
||||||
|
|
||||||
private readonly _chatStream: Subject<ChatEvent> = new Subject();
|
private readonly _chatStream: Subject<ChatEvent> = new Subject();
|
||||||
public readonly chatStream = this._chatStream.asObservable();
|
public readonly chatStream = this._chatStream.asObservable();
|
||||||
|
|
||||||
@ -62,8 +69,14 @@ class IframeListener {
|
|||||||
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
||||||
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
||||||
|
|
||||||
|
private readonly _gameStateStream: Subject<void> = new Subject();
|
||||||
|
public readonly gameStateStream = this._gameStateStream.asObservable();
|
||||||
|
|
||||||
|
|
||||||
private readonly iframes = new Set<HTMLIFrameElement>();
|
private readonly iframes = new Set<HTMLIFrameElement>();
|
||||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||||
|
private sendPlayerMove: boolean = false;
|
||||||
|
private sendDataLayerChange: boolean = false;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
window.addEventListener("message", (message: TypedMessageEvent<IframeEvent<keyof IframeEventMap>>) => {
|
window.addEventListener("message", (message: TypedMessageEvent<IframeEvent<keyof IframeEventMap>>) => {
|
||||||
@ -117,12 +130,16 @@ class IframeListener {
|
|||||||
}
|
}
|
||||||
else if (payload.type === 'restorePlayerControls') {
|
else if (payload.type === 'restorePlayerControls') {
|
||||||
this._enablePlayerControlStream.next();
|
this._enablePlayerControlStream.next();
|
||||||
}
|
} else if (payload.type === 'displayBubble') {
|
||||||
else if (payload.type === 'displayBubble') {
|
|
||||||
this._displayBubbleStream.next();
|
this._displayBubbleStream.next();
|
||||||
}
|
} else if (payload.type === 'removeBubble') {
|
||||||
else if (payload.type === 'removeBubble') {
|
|
||||||
this._removeBubbleStream.next();
|
this._removeBubbleStream.next();
|
||||||
|
} else if (payload.type == "getState") {
|
||||||
|
this._gameStateStream.next();
|
||||||
|
} else if (payload.type == "onPlayerMove") {
|
||||||
|
this.sendPlayerMove = true
|
||||||
|
} else if (payload.type == "onDataLayerChange") {
|
||||||
|
this.sendDataLayerChange = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +148,14 @@ class IframeListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sendFrozenGameStateEvent(gameStateEvent: GameStateEvent) {
|
||||||
|
this.postMessage({
|
||||||
|
'type': 'gameState',
|
||||||
|
'data': gameStateEvent //deepFreezeClone(gameStateEvent)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the passed iFrame to send/receive messages via the API.
|
* Allows the passed iFrame to send/receive messages via the API.
|
||||||
*/
|
*/
|
||||||
@ -234,6 +259,24 @@ class IframeListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasPlayerMoved(event: HasPlayerMovedEvent) {
|
||||||
|
if (this.sendPlayerMove) {
|
||||||
|
this.postMessage({
|
||||||
|
'type': 'hasPlayerMoved',
|
||||||
|
'data': event
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasDataLayerChanged(event: HasDataLayerChangedEvent) {
|
||||||
|
if (this.sendDataLayerChange) {
|
||||||
|
this.postMessage({
|
||||||
|
'type' : 'hasDataLayerChanged',
|
||||||
|
'data' : event
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sendButtonClickedEvent(popupId: number, buttonId: number): void {
|
sendButtonClickedEvent(popupId: number, buttonId: number): void {
|
||||||
this.postMessage({
|
this.postMessage({
|
||||||
'type': 'buttonClickedEvent',
|
'type': 'buttonClickedEvent',
|
||||||
|
@ -86,7 +86,6 @@ export class RoomConnection implements RoomConnection {
|
|||||||
url += '&bottom=' + Math.floor(viewport.bottom);
|
url += '&bottom=' + Math.floor(viewport.bottom);
|
||||||
url += '&left=' + Math.floor(viewport.left);
|
url += '&left=' + Math.floor(viewport.left);
|
||||||
url += '&right=' + Math.floor(viewport.right);
|
url += '&right=' + Math.floor(viewport.right);
|
||||||
|
|
||||||
if (typeof companion === 'string') {
|
if (typeof companion === 'string') {
|
||||||
url += '&companion=' + encodeURIComponent(companion);
|
url += '&companion=' + encodeURIComponent(companion);
|
||||||
}
|
}
|
||||||
@ -170,9 +169,9 @@ export class RoomConnection implements RoomConnection {
|
|||||||
} else if (message.hasWorldfullmessage()) {
|
} else if (message.hasWorldfullmessage()) {
|
||||||
worldFullMessageStream.onMessage();
|
worldFullMessageStream.onMessage();
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
} else if (message.hasWorldconnexionmessage()) {
|
// // } else if (message.hasWorldconnexionmessage()) {
|
||||||
worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage());
|
// worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage());
|
||||||
this.closed = true;
|
// this.closed = true;
|
||||||
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
} else if (message.hasWebrtcsignaltoclientmessage()) {
|
||||||
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
|
||||||
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
|
||||||
|
@ -8,12 +8,7 @@ import {SelectCharacterSceneName} from "../Login/SelectCharacterScene";
|
|||||||
import {EnableCameraSceneName} from "../Login/EnableCameraScene";
|
import {EnableCameraSceneName} from "../Login/EnableCameraScene";
|
||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export interface HasMovedEvent {
|
|
||||||
direction: string;
|
|
||||||
moving: boolean;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class should be responsible for any scene starting/stopping
|
* This class should be responsible for any scene starting/stopping
|
||||||
|
@ -91,8 +91,9 @@ import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
|||||||
import { PinchManager } from "../UserInput/PinchManager";
|
import { PinchManager } from "../UserInput/PinchManager";
|
||||||
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
|
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
|
import { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||||
import {LayerEvent} from "../../Api/Events/LayerEvent";
|
import {LayerEvent} from "../../Api/Events/LayerEvent";
|
||||||
import {SetPropertyEvent} from "../../Api/Events/setPropertyEvent";
|
import {SetPropertyEvent} from "../../Api/Events/setPropertyEve
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null,
|
initPosition: PointInterface | null,
|
||||||
@ -163,7 +164,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
|
|
||||||
currentTick!: number;
|
currentTick!: number;
|
||||||
lastSentTick!: number; // The last tick at which a position was sent.
|
lastSentTick!: number; // The last tick at which a position was sent.
|
||||||
lastMoveEventSent: HasMovedEvent = {
|
lastMoveEventSent: HasPlayerMovedEvent = {
|
||||||
direction: '',
|
direction: '',
|
||||||
moving: false,
|
moving: false,
|
||||||
x: -1000,
|
x: -1000,
|
||||||
@ -630,7 +631,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
//listen event to share position of user
|
//listen event to share position of user
|
||||||
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this))
|
this.CurrentPlayer.on(hasMovedEventName, this.pushPlayerPosition.bind(this))
|
||||||
this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this))
|
this.CurrentPlayer.on(hasMovedEventName, this.outlineItem.bind(this))
|
||||||
this.CurrentPlayer.on(hasMovedEventName, (event: HasMovedEvent) => {
|
this.CurrentPlayer.on(hasMovedEventName, (event: HasPlayerMovedEvent) => {
|
||||||
this.gameMap.setPosition(event.x, event.y);
|
this.gameMap.setPosition(event.x, event.y);
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -863,6 +864,15 @@ ${escapedMessage}
|
|||||||
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(() => {
|
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(() => {
|
||||||
this.userInputManager.restoreControls();
|
this.userInputManager.restoreControls();
|
||||||
}));
|
}));
|
||||||
|
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => {
|
||||||
|
iframeListener.sendFrozenGameStateEvent({
|
||||||
|
mapUrl: this.MapUrlFile,
|
||||||
|
startLayerName: this.startLayerName,
|
||||||
|
uuid: localUserStore.getLocalUser()?.uuid,
|
||||||
|
roomId: this.RoomId,
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
let scriptedBubbleSprite: Sprite;
|
let scriptedBubbleSprite: Sprite;
|
||||||
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(() => {
|
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(() => {
|
||||||
scriptedBubbleSprite = new Sprite(this, this.CurrentPlayer.x + 25, this.CurrentPlayer.y, 'circleSprite-white');
|
scriptedBubbleSprite = new Sprite(this, this.CurrentPlayer.x + 25, this.CurrentPlayer.y, 'circleSprite-white');
|
||||||
@ -1170,7 +1180,7 @@ ${escapedMessage}
|
|||||||
this.createCollisionWithPlayer();
|
this.createCollisionWithPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
pushPlayerPosition(event: HasMovedEvent) {
|
pushPlayerPosition(event: HasPlayerMovedEvent) {
|
||||||
if (this.lastMoveEventSent === event) {
|
if (this.lastMoveEventSent === event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1200,7 +1210,7 @@ ${escapedMessage}
|
|||||||
* Finds the correct item to outline and outline it (if there is an item to be outlined)
|
* Finds the correct item to outline and outline it (if there is an item to be outlined)
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
private outlineItem(event: HasMovedEvent): void {
|
private outlineItem(event: HasPlayerMovedEvent): void {
|
||||||
let x = event.x;
|
let x = event.x;
|
||||||
let y = event.y;
|
let y = event.y;
|
||||||
switch (event.direction) {
|
switch (event.direction) {
|
||||||
@ -1239,7 +1249,7 @@ ${escapedMessage}
|
|||||||
this.outlinedItem?.selectable();
|
this.outlinedItem?.selectable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private doPushPlayerPosition(event: HasMovedEvent): void {
|
private doPushPlayerPosition(event: HasPlayerMovedEvent): void {
|
||||||
this.lastMoveEventSent = event;
|
this.lastMoveEventSent = event;
|
||||||
this.lastSentTick = this.currentTick;
|
this.lastSentTick = this.currentTick;
|
||||||
const camera = this.cameras.main;
|
const camera = this.cameras.main;
|
||||||
@ -1249,6 +1259,7 @@ ${escapedMessage}
|
|||||||
right: camera.scrollX + camera.width,
|
right: camera.scrollX + camera.width,
|
||||||
bottom: camera.scrollY + camera.height,
|
bottom: camera.scrollY + camera.height,
|
||||||
});
|
});
|
||||||
|
iframeListener.hasPlayerMoved(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1300,7 +1311,7 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
// Let's move all users
|
// Let's move all users
|
||||||
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
const updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
||||||
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: number) => {
|
updatedPlayersPositions.forEach((moveEvent: HasPlayerMovedEvent, userId: number) => {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
const player: RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
||||||
if (player === undefined) {
|
if (player === undefined) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import type {HasMovedEvent} from "./GameManager";
|
import type {HasMovedEvent} from "./GameManager";
|
||||||
import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable";
|
import { MAX_EXTRAPOLATION_TIME } from "../../Enum/EnvironmentVariable";
|
||||||
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
||||||
|
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||||
|
|
||||||
export class PlayerMovement {
|
export class PlayerMovement {
|
||||||
public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasMovedEvent, private endTick: number) {
|
public constructor(private startPosition: PositionInterface, private startTick: number, private endPosition: HasPlayerMovedEvent, private endTick: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public isOutdated(tick: number): boolean {
|
public isOutdated(tick: number): boolean {
|
||||||
@ -17,7 +18,7 @@ export class PlayerMovement {
|
|||||||
return tick > this.endTick + MAX_EXTRAPOLATION_TIME;
|
return tick > this.endTick + MAX_EXTRAPOLATION_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPosition(tick: number): HasMovedEvent {
|
public getPosition(tick: number): HasPlayerMovedEvent {
|
||||||
// Special case: end position reached and end position is not moving
|
// Special case: end position reached and end position is not moving
|
||||||
if (tick >= this.endTick && this.endPosition.moving === false) {
|
if (tick >= this.endTick && this.endPosition.moving === false) {
|
||||||
//console.log('Movement finished ', this.endPosition)
|
//console.log('Movement finished ', this.endPosition)
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* This class is in charge of computing the position of all players.
|
* This class is in charge of computing the position of all players.
|
||||||
* Player movement is delayed by 200ms so position depends on ticks.
|
* Player movement is delayed by 200ms so position depends on ticks.
|
||||||
*/
|
*/
|
||||||
|
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||||
import type { PlayerMovement } from "./PlayerMovement";
|
import type { PlayerMovement } from "./PlayerMovement";
|
||||||
import type {HasMovedEvent} from "./GameManager";
|
|
||||||
|
|
||||||
export class PlayersPositionInterpolator {
|
export class PlayersPositionInterpolator {
|
||||||
playerMovements: Map<number, PlayerMovement> = new Map<number, PlayerMovement>();
|
playerMovements: Map<number, PlayerMovement> = new Map<number, PlayerMovement>();
|
||||||
@ -16,8 +16,8 @@ export class PlayersPositionInterpolator {
|
|||||||
this.playerMovements.delete(userId);
|
this.playerMovements.delete(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUpdatedPositions(tick: number) : Map<number, HasMovedEvent> {
|
getUpdatedPositions(tick: number): Map<number, HasPlayerMovedEvent> {
|
||||||
const positions = new Map<number, HasMovedEvent>();
|
const positions = new Map<number, HasPlayerMovedEvent>();
|
||||||
this.playerMovements.forEach((playerMovement: PlayerMovement, userId: number) => {
|
this.playerMovements.forEach((playerMovement: PlayerMovement, userId: number) => {
|
||||||
if (playerMovement.isOutdated(tick)) {
|
if (playerMovement.isOutdated(tick)) {
|
||||||
//console.log("outdated")
|
//console.log("outdated")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { ChatEvent } from "./Api/Events/ChatEvent";
|
import type { ChatEvent } from "./Api/Events/ChatEvent";
|
||||||
import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent";
|
import { IframeEvent, IframeEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent";
|
||||||
import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent";
|
import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent";
|
import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent";
|
||||||
@ -11,6 +11,9 @@ import type { GoToPageEvent } from "./Api/Events/GoToPageEvent";
|
|||||||
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
||||||
import type { LayerEvent } from "./Api/Events/LayerEvent";
|
import type { LayerEvent } from "./Api/Events/LayerEvent";
|
||||||
import type { SetPropertyEvent } from "./Api/Events/setPropertyEvent";
|
import type { SetPropertyEvent } from "./Api/Events/setPropertyEvent";
|
||||||
|
import { GameStateEvent, isGameStateEvent } from './Api/Events/GameStateEvent';
|
||||||
|
import { HasPlayerMovedEvent, HasPlayerMovedEventCallback, isHasPlayerMovedEvent } from './Api/Events/HasPlayerMovedEvent';
|
||||||
|
import { HasDataLayerChangedEvent, HasDataLayerChangedEventCallback, isHasDataLayerChangedEvent} from "./Api/Events/HasDataLayerChangedEvent";
|
||||||
|
|
||||||
interface WorkAdventureApi {
|
interface WorkAdventureApi {
|
||||||
sendChatMessage(message: string, author: string): void;
|
sendChatMessage(message: string, author: string): void;
|
||||||
@ -29,6 +32,18 @@ interface WorkAdventureApi {
|
|||||||
showLayer(layer: string) : void;
|
showLayer(layer: string) : void;
|
||||||
hideLayer(layer: string) : void;
|
hideLayer(layer: string) : void;
|
||||||
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void;
|
setProperty(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void;
|
||||||
|
disablePlayerControls(): void;
|
||||||
|
restorePlayerControls(): void;
|
||||||
|
displayBubble(): void;
|
||||||
|
removeBubble(): void;
|
||||||
|
getMapUrl(): Promise<string>;
|
||||||
|
getUuid(): Promise<string | undefined>;
|
||||||
|
getRoomId(): Promise<string>;
|
||||||
|
getStartLayerName(): Promise<string | null>;
|
||||||
|
|
||||||
|
|
||||||
|
onPlayerMove(callback: (playerMovedEvent: HasPlayerMovedEvent) => void): void
|
||||||
|
onDataLayerChange(callback: (dataLayerChangedEvent: HasDataLayerChangedEvent) => void): void
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -78,8 +93,82 @@ class Popup {
|
|||||||
}, '*');
|
}, '*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function uuidv4() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||||
|
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getGameState(): Promise<GameStateEvent> {
|
||||||
|
if (immutableData) {
|
||||||
|
return Promise.resolve(immutableData);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new Promise<GameStateEvent>((resolver, thrower) => {
|
||||||
|
stateResolvers.push(resolver);
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: "getState"
|
||||||
|
}, "*")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateResolvers: Array<(event: GameStateEvent) => void> = []
|
||||||
|
let immutableData: GameStateEvent;
|
||||||
|
|
||||||
|
const callbackPlayerMoved: { [type: string]: HasPlayerMovedEventCallback | ((arg?: HasPlayerMovedEvent | never) => void) } = {}
|
||||||
|
const callbackDataLayerChanged: { [type: string]: HasDataLayerChangedEventCallback | ((arg?: HasDataLayerChangedEvent | never) => void) } = {}
|
||||||
|
|
||||||
|
|
||||||
|
function postToParent(content: IframeEvent<keyof IframeEventMap>) {
|
||||||
|
window.parent.postMessage(content, "*")
|
||||||
|
}
|
||||||
|
let playerUuid: string | undefined;
|
||||||
|
|
||||||
window.WA = {
|
window.WA = {
|
||||||
|
|
||||||
|
onPlayerMove(callback: HasPlayerMovedEventCallback): void {
|
||||||
|
playerUuid = uuidv4();
|
||||||
|
callbackPlayerMoved[playerUuid] = callback;
|
||||||
|
postToParent({
|
||||||
|
type: "onPlayerMove",
|
||||||
|
data: undefined
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onDataLayerChange(callback: HasDataLayerChangedEventCallback): void {
|
||||||
|
callbackDataLayerChanged['test'] = callback;
|
||||||
|
postToParent({
|
||||||
|
type : "onDataLayerChange",
|
||||||
|
data: undefined
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getMapUrl() {
|
||||||
|
return getGameState().then((res) => {
|
||||||
|
return res.mapUrl;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getUuid() {
|
||||||
|
return getGameState().then((res) => {
|
||||||
|
return res.uuid;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getRoomId() {
|
||||||
|
return getGameState().then((res) => {
|
||||||
|
return res.roomId;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getStartLayerName() {
|
||||||
|
return getGameState().then((res) => {
|
||||||
|
return res.startLayerName;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message in the chat.
|
* Send a message in the chat.
|
||||||
* Only the local user will receive this message.
|
* Only the local user will receive this message.
|
||||||
@ -255,6 +344,15 @@ window.addEventListener('message', message => {
|
|||||||
if (callback) {
|
if (callback) {
|
||||||
callback(popup);
|
callback(popup);
|
||||||
}
|
}
|
||||||
|
} else if (payload.type == "gameState" && isGameStateEvent(payloadData)) {
|
||||||
|
stateResolvers.forEach(resolver => {
|
||||||
|
resolver(payloadData);
|
||||||
|
})
|
||||||
|
immutableData = payloadData;
|
||||||
|
} else if (payload.type == "hasPlayerMoved" && isHasPlayerMovedEvent(payloadData) && playerUuid) {
|
||||||
|
callbackPlayerMoved[playerUuid](payloadData)
|
||||||
|
} else if (payload.type == "hasDataLayerChanged" && isHasDataLayerChangedEvent(payloadData)) {
|
||||||
|
callbackDataLayerChanged['test'](payloadData)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
230
maps/tests/Metadata/map.json
Normal file
230
maps/tests/Metadata/map.json
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 33, 34, 34, 34, 34, 34, 34, 35, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 41, 42, 42, 42, 42, 42, 42, 43, 46, 46, 49, 50, 50, 50, 50, 50, 50, 51, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"bottom",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":4,
|
||||||
|
"name":"metadata",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":5,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 0, 0, 0, 0, 0, 0, 0, 11, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19],
|
||||||
|
"height":10,
|
||||||
|
"id":3,
|
||||||
|
"name":"wall",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":6,
|
||||||
|
"nextobjectid":1,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"script",
|
||||||
|
"type":"string",
|
||||||
|
"value":"script.js"
|
||||||
|
}],
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.4.3",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":8,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset_dungeon.png",
|
||||||
|
"imageheight":256,
|
||||||
|
"imagewidth":256,
|
||||||
|
"margin":0,
|
||||||
|
"name":"TDungeon",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":64,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":0,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":2,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":3,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":4,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":8,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":9,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":10,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":11,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":12,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":16,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":17,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":18,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":19,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":20,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.4,
|
||||||
|
"width":10
|
||||||
|
}
|
9
maps/tests/Metadata/script.js
Normal file
9
maps/tests/Metadata/script.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
WA.getMapUrl().then((map) => {console.log('mapUrl : ', map)});
|
||||||
|
WA.getUuid().then((uuid) => {console.log('Uuid : ',uuid)});
|
||||||
|
WA.getRoomId().then((roomId) => console.log('roomID : ',roomId));
|
||||||
|
|
||||||
|
WA.listenPositionPlayer(console.log);
|
||||||
|
|
||||||
|
|
BIN
maps/tests/Metadata/tileset_dungeon.png
Normal file
BIN
maps/tests/Metadata/tileset_dungeon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
Loading…
x
Reference in New Issue
Block a user