Adding the abaility to track users entering/leaving a zone in the script language.

This commit is contained in:
David Négrier 2021-03-08 18:57:59 +01:00
parent 6fbf165c91
commit 2bef328d8a
6 changed files with 103 additions and 8 deletions

View File

@ -0,0 +1,10 @@
import * as tg from "generic-type-guard";
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>;

View File

@ -4,6 +4,7 @@ import {IframeEvent, isIframeEventWrapper} from "./Events/IframeEvent";
import {UserInputChatEvent} from "./Events/UserInputChatEvent"; import {UserInputChatEvent} from "./Events/UserInputChatEvent";
import * as crypto from "crypto"; import * as crypto from "crypto";
import {HtmlUtils} from "../WebRtc/HtmlUtils"; import {HtmlUtils} from "../WebRtc/HtmlUtils";
import {EnterLeaveEvent} from "./Events/EnterLeaveEvent";
@ -130,6 +131,24 @@ class IframeListener {
}); });
} }
sendEnterEvent(name: string) {
this.postMessage({
'type': 'enterEvent',
'data': {
"name": name
} as EnterLeaveEvent
});
}
sendLeaveEvent(name: string) {
this.postMessage({
'type': 'leaveEvent',
'data': {
"name": name
} as EnterLeaveEvent
});
}
/** /**
* Sends the message... to all allowed iframes. * Sends the message... to all allowed iframes.
*/ */

View File

@ -725,6 +725,14 @@ export class GameScene extends ResizableScene implements CenterListener {
this.playAudio(newValue, true); this.playAudio(newValue, true);
}); });
this.gameMap.onPropertyChange('zone', (newValue, oldValue) => {
if (newValue === undefined || newValue === false || newValue === '') {
iframeListener.sendLeaveEvent(oldValue as string);
} else {
iframeListener.sendEnterEvent(newValue as string);
}
});
} }
private onMapExit(exitKey: string) { private onMapExit(exitKey: string) {

View File

@ -2,10 +2,13 @@ import {ChatEvent, isChatEvent} from "./Api/Events/ChatEvent";
import {isIframeEventWrapper} from "./Api/Events/IframeEvent"; import {isIframeEventWrapper} 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";
interface WorkAdventureApi { interface WorkAdventureApi {
sendChatMessage(message: string, author: string): void; sendChatMessage(message: string, author: string): void;
onChatMessage(callback: (message: string) => void): void; onChatMessage(callback: (message: string) => void): void;
onEnterZone(name: string, callback: () => void): void;
onLeaveZone(name: string, callback: () => void): void;
} }
declare global { declare global {
@ -16,6 +19,8 @@ declare global {
type ChatMessageCallback = (message: string) => void; type ChatMessageCallback = (message: string) => void;
const userInputChatStream: Subject<UserInputChatEvent> = new Subject(); const userInputChatStream: Subject<UserInputChatEvent> = new Subject();
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
window.WA = { window.WA = {
@ -39,19 +44,42 @@ window.WA = {
userInputChatStream.subscribe((userInputChatEvent) => { userInputChatStream.subscribe((userInputChatEvent) => {
callback(userInputChatEvent.message); callback(userInputChatEvent.message);
}); });
} },
onEnterZone(name: string, callback: () => void): void {
let subject = enterStreams.get(name);
if (subject === undefined) {
subject = new Subject<EnterLeaveEvent>();
enterStreams.set(name, subject);
}
subject.subscribe(callback);
},
onLeaveZone(name: string, callback: () => void): void {
let subject = leaveStreams.get(name);
if (subject === undefined) {
subject = new Subject<EnterLeaveEvent>();
leaveStreams.set(name, subject);
}
subject.subscribe(callback);
},
} }
window.addEventListener('message', message => { window.addEventListener('message', message => {
if (message.source !== window.parent) { if (message.source !== window.parent) {
console.log('MESSAGE SKIPPED!!!')
return; // Skip message in this event listener return; // Skip message in this event listener
} }
const payload = message.data; const payload = message.data;
console.log(payload);
if (isIframeEventWrapper(payload)) { if (isIframeEventWrapper(payload)) {
if (payload.type === 'userInputChat' && isUserInputChatEvent(payload.data)) { const payloadData = payload.data;
userInputChatStream.next(payload.data); if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) {
userInputChatStream.next(payloadData);
} else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) {
enterStreams.get(payloadData.name)?.next();
} else if (payload.type === 'leaveEvent' && isEnterLeaveEvent(payloadData)) {
leaveStreams.get(payloadData.name)?.next();
} }
} }

View File

@ -6,3 +6,15 @@ WA.onChatMessage((message => {
console.log('CHAT MESSAGE RECEIVED BY SCRIPT'); console.log('CHAT MESSAGE RECEIVED BY SCRIPT');
WA.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot'); WA.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot');
})); }));
WA.onEnterZone('myTrigger', () => {
WA.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
})
WA.onLeaveZone('myTrigger', () => {
WA.sendChatMessage("Thanks!", 'Poly Parrot');
})
WA.onEnterZone('notExist', () => {
WA.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot');
})

View File

@ -20,7 +20,25 @@
"width":10, "width":10,
"x":0, "x":0,
"y":0 "y":0
}, },
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":10,
"id":6,
"name":"triggerZone",
"opacity":1,
"properties":[
{
"name":"zone",
"type":"string",
"value":"myTrigger"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{ {
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":10, "height":10,
@ -32,7 +50,7 @@
"width":10, "width":10,
"x":0, "x":0,
"y":0 "y":0
}, },
{ {
"draworder":"topdown", "draworder":"topdown",
"id":3, "id":3,
@ -44,7 +62,7 @@
"x":0, "x":0,
"y":0 "y":0
}], }],
"nextlayerid":6, "nextlayerid":7,
"nextobjectid":1, "nextobjectid":1,
"orientation":"orthogonal", "orientation":"orthogonal",
"properties":[ "properties":[
@ -74,4 +92,4 @@
"type":"map", "type":"map",
"version":1.2, "version":1.2,
"width":10 "width":10
} }