Adding support for default variables values
This commit is contained in:
parent
abd53b6251
commit
c30de8c6db
@ -88,13 +88,11 @@ export type IframeQueryMap = {
|
|||||||
getState: {
|
getState: {
|
||||||
query: undefined,
|
query: undefined,
|
||||||
answer: GameStateEvent,
|
answer: GameStateEvent,
|
||||||
callback: () => GameStateEvent|PromiseLike<GameStateEvent>
|
|
||||||
},
|
},
|
||||||
getMapData: {
|
getMapData: {
|
||||||
query: undefined,
|
query: undefined,
|
||||||
answer: MapDataEvent,
|
answer: MapDataEvent,
|
||||||
callback: () => MapDataEvent|PromiseLike<GameStateEvent>
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
export interface IframeQuery<T extends keyof IframeQueryMap> {
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import {Observable, Subject} from "rxjs";
|
import {Observable, Subject} from "rxjs";
|
||||||
|
|
||||||
import { isMapDataEvent } from "../Events/MapDataEvent";
|
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent";
|
||||||
import { isGameStateEvent } from "../Events/GameStateEvent";
|
|
||||||
|
|
||||||
import {IframeApiContribution, queryWorkadventure, sendToWorkadventure} from "./IframeApiContribution";
|
import {IframeApiContribution, queryWorkadventure, sendToWorkadventure} from "./IframeApiContribution";
|
||||||
import { apiCallback } from "./registeredCallbacks";
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
import type {LayerEvent} from "../Events/LayerEvent";
|
|
||||||
import type {SetPropertyEvent} from "../Events/setPropertyEvent";
|
|
||||||
import {isSetVariableEvent, SetVariableEvent} from "../Events/SetVariableEvent";
|
import {isSetVariableEvent, SetVariableEvent} from "../Events/SetVariableEvent";
|
||||||
|
|
||||||
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
||||||
import type { MapDataEvent } from "../Events/MapDataEvent";
|
|
||||||
import type { GameStateEvent } from "../Events/GameStateEvent";
|
|
||||||
|
|
||||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
@ -39,6 +33,16 @@ export const setMapURL = (url: string) => {
|
|||||||
mapURL = url;
|
mapURL = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const initVariables = (_variables: Map<string, unknown>): void => {
|
||||||
|
for (const [name, value] of _variables.entries()) {
|
||||||
|
// In case the user already decided to put values in the variables (before onInit), let's make sure onInit does not override this.
|
||||||
|
if (!variables.has(name)) {
|
||||||
|
variables.set(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
setVariableResolvers.subscribe((event) => {
|
setVariableResolvers.subscribe((event) => {
|
||||||
variables.set(event.key, event.value);
|
variables.set(event.key, event.value);
|
||||||
const subject = variableSubscribers.get(event.key);
|
const subject = variableSubscribers.get(event.key);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ITiledMap, ITiledMapLayer, ITiledMapLayerProperty } from "../Map/ITiledMap";
|
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty } from "../Map/ITiledMap";
|
||||||
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
||||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
||||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||||
@ -19,7 +19,7 @@ export class GameMap {
|
|||||||
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
|
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
|
||||||
private tileNameMap = new Map<string, number>();
|
private tileNameMap = new Map<string, number>();
|
||||||
|
|
||||||
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapLayerProperty> } = {};
|
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapProperty> } = {};
|
||||||
public readonly flatLayers: ITiledMapLayer[];
|
public readonly flatLayers: ITiledMapLayer[];
|
||||||
public readonly phaserLayers: TilemapLayer[] = [];
|
public readonly phaserLayers: TilemapLayer[] = [];
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ export class GameMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPropertiesForIndex(index: number): Array<ITiledMapLayerProperty> {
|
public getPropertiesForIndex(index: number): Array<ITiledMapProperty> {
|
||||||
if (this.tileSetPropertyMap[index]) {
|
if (this.tileSetPropertyMap[index]) {
|
||||||
return this.tileSetPropertyMap[index];
|
return this.tileSetPropertyMap[index];
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ export class GameMap {
|
|||||||
return this.map;
|
return this.map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTileProperty(index: number): Array<ITiledMapLayerProperty> {
|
private getTileProperty(index: number): Array<ITiledMapProperty> {
|
||||||
return this.tileSetPropertyMap[index];
|
return this.tileSetPropertyMap[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectC
|
|||||||
import type {
|
import type {
|
||||||
ITiledMap,
|
ITiledMap,
|
||||||
ITiledMapLayer,
|
ITiledMapLayer,
|
||||||
ITiledMapLayerProperty,
|
ITiledMapProperty,
|
||||||
ITiledMapObject,
|
ITiledMapObject,
|
||||||
ITiledTileSet,
|
ITiledTileSet,
|
||||||
} from "../Map/ITiledMap";
|
} from "../Map/ITiledMap";
|
||||||
@ -1197,12 +1197,12 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined {
|
private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined {
|
||||||
const properties: ITiledMapLayerProperty[] | undefined = layer.properties;
|
const properties: ITiledMapProperty[] | undefined = layer.properties;
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const obj = properties.find(
|
const obj = properties.find(
|
||||||
(property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase()
|
(property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase()
|
||||||
);
|
);
|
||||||
if (obj === undefined) {
|
if (obj === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1211,12 +1211,12 @@ ${escapedMessage}
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getProperties(layer: ITiledMapLayer | ITiledMap, name: string): (string | number | boolean | undefined)[] {
|
private getProperties(layer: ITiledMapLayer | ITiledMap, name: string): (string | number | boolean | undefined)[] {
|
||||||
const properties: ITiledMapLayerProperty[] | undefined = layer.properties;
|
const properties: ITiledMapProperty[] | undefined = layer.properties;
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return properties
|
return properties
|
||||||
.filter((property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase())
|
.filter((property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase())
|
||||||
.map((property) => property.value);
|
.map((property) => property.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,18 +5,28 @@ import type {RoomConnection} from "../../Connexion/RoomConnection";
|
|||||||
import {iframeListener} from "../../Api/IframeListener";
|
import {iframeListener} from "../../Api/IframeListener";
|
||||||
import type {Subscription} from "rxjs";
|
import type {Subscription} from "rxjs";
|
||||||
import type {GameMap} from "./GameMap";
|
import type {GameMap} from "./GameMap";
|
||||||
import type {ITiledMapObject} from "../Map/ITiledMap";
|
import type {ITile, ITiledMapObject} from "../Map/ITiledMap";
|
||||||
|
import type {Var} from "svelte/types/compiler/interfaces";
|
||||||
|
|
||||||
|
interface Variable {
|
||||||
|
defaultValue: unknown
|
||||||
|
}
|
||||||
|
|
||||||
export class SharedVariablesManager {
|
export class SharedVariablesManager {
|
||||||
private _variables = new Map<string, unknown>();
|
private _variables = new Map<string, unknown>();
|
||||||
private iframeListenerSubscription: Subscription;
|
private iframeListenerSubscription: Subscription;
|
||||||
private variableObjects: Map<string, ITiledMapObject>;
|
private variableObjects: Map<string, Variable>;
|
||||||
|
|
||||||
constructor(private roomConnection: RoomConnection, private gameMap: GameMap) {
|
constructor(private roomConnection: RoomConnection, private gameMap: GameMap) {
|
||||||
// We initialize the list of variable object at room start. The objects cannot be edited later
|
// We initialize the list of variable object at room start. The objects cannot be edited later
|
||||||
// (otherwise, this would cause a security issue if the scripting API can edit this list of objects)
|
// (otherwise, this would cause a security issue if the scripting API can edit this list of objects)
|
||||||
this.variableObjects = SharedVariablesManager.findVariablesInMap(gameMap);
|
this.variableObjects = SharedVariablesManager.findVariablesInMap(gameMap);
|
||||||
|
|
||||||
|
// Let's initialize default values
|
||||||
|
for (const [name, variableObject] of this.variableObjects.entries()) {
|
||||||
|
this._variables.set(name, variableObject.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
// When a variable is modified from an iFrame
|
// When a variable is modified from an iFrame
|
||||||
this.iframeListenerSubscription = iframeListener.setVariableStream.subscribe((event) => {
|
this.iframeListenerSubscription = iframeListener.setVariableStream.subscribe((event) => {
|
||||||
const key = event.key;
|
const key = event.key;
|
||||||
@ -33,14 +43,14 @@ export class SharedVariablesManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static findVariablesInMap(gameMap: GameMap): Map<string, ITiledMapObject> {
|
private static findVariablesInMap(gameMap: GameMap): Map<string, Variable> {
|
||||||
const objects = new Map<string, ITiledMapObject>();
|
const objects = new Map<string, Variable>();
|
||||||
for (const layer of gameMap.getMap().layers) {
|
for (const layer of gameMap.getMap().layers) {
|
||||||
if (layer.type === 'objectgroup') {
|
if (layer.type === 'objectgroup') {
|
||||||
for (const object of layer.objects) {
|
for (const object of layer.objects) {
|
||||||
if (object.type === 'variable') {
|
if (object.type === 'variable') {
|
||||||
// We store a copy of the object (to make it immutable)
|
// We store a copy of the object (to make it immutable)
|
||||||
objects.set(object.name, {...object});
|
objects.set(object.name, this.iTiledObjectToVariable(object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,6 +58,21 @@ export class SharedVariablesManager {
|
|||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static iTiledObjectToVariable(object: ITiledMapObject): Variable {
|
||||||
|
const variable: Variable = {
|
||||||
|
defaultValue: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
if (object.properties) {
|
||||||
|
for (const property of object.properties) {
|
||||||
|
if (property.name === 'default') {
|
||||||
|
variable.defaultValue = property.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
public close(): void {
|
public close(): void {
|
||||||
this.iframeListenerSubscription.unsubscribe();
|
this.iframeListenerSubscription.unsubscribe();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
import type { PositionInterface } from "../../Connexion/ConnexionModels";
|
||||||
import type { ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapTileLayer } from "../Map/ITiledMap";
|
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapTileLayer } from "../Map/ITiledMap";
|
||||||
import type { GameMap } from "./GameMap";
|
import type { GameMap } from "./GameMap";
|
||||||
|
|
||||||
const defaultStartLayerName = "start";
|
const defaultStartLayerName = "start";
|
||||||
@ -112,12 +112,12 @@ export class StartPositionCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined {
|
private getProperty(layer: ITiledMapLayer | ITiledMap, name: string): string | boolean | number | undefined {
|
||||||
const properties: ITiledMapLayerProperty[] | undefined = layer.properties;
|
const properties: ITiledMapProperty[] | undefined = layer.properties;
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const obj = properties.find(
|
const obj = properties.find(
|
||||||
(property: ITiledMapLayerProperty) => property.name.toLowerCase() === name.toLowerCase()
|
(property: ITiledMapProperty) => property.name.toLowerCase() === name.toLowerCase()
|
||||||
);
|
);
|
||||||
if (obj === undefined) {
|
if (obj === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -16,7 +16,7 @@ export interface ITiledMap {
|
|||||||
* Map orientation (orthogonal)
|
* Map orientation (orthogonal)
|
||||||
*/
|
*/
|
||||||
orientation: string;
|
orientation: string;
|
||||||
properties?: ITiledMapLayerProperty[];
|
properties?: ITiledMapProperty[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render order (right-down)
|
* Render order (right-down)
|
||||||
@ -33,7 +33,7 @@ export interface ITiledMap {
|
|||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITiledMapLayerProperty {
|
export interface ITiledMapProperty {
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
value: string | boolean | number | undefined;
|
value: string | boolean | number | undefined;
|
||||||
@ -51,7 +51,7 @@ export interface ITiledMapGroupLayer {
|
|||||||
id?: number;
|
id?: number;
|
||||||
name: string;
|
name: string;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
properties?: ITiledMapLayerProperty[];
|
properties?: ITiledMapProperty[];
|
||||||
|
|
||||||
type: "group";
|
type: "group";
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -69,7 +69,7 @@ export interface ITiledMapTileLayer {
|
|||||||
height: number;
|
height: number;
|
||||||
name: string;
|
name: string;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
properties?: ITiledMapLayerProperty[];
|
properties?: ITiledMapProperty[];
|
||||||
encoding?: string;
|
encoding?: string;
|
||||||
compression?: string;
|
compression?: string;
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ export interface ITiledMapObjectLayer {
|
|||||||
height: number;
|
height: number;
|
||||||
name: string;
|
name: string;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
properties?: ITiledMapLayerProperty[];
|
properties?: ITiledMapProperty[];
|
||||||
encoding?: string;
|
encoding?: string;
|
||||||
compression?: string;
|
compression?: string;
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ export interface ITiledMapObject {
|
|||||||
gid: number;
|
gid: number;
|
||||||
height: number;
|
height: number;
|
||||||
name: string;
|
name: string;
|
||||||
properties: { [key: string]: string };
|
properties?: ITiledMapProperty[];
|
||||||
rotation: number;
|
rotation: number;
|
||||||
type: string;
|
type: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -163,7 +163,7 @@ export interface ITiledTileSet {
|
|||||||
imagewidth: number;
|
imagewidth: number;
|
||||||
margin: number;
|
margin: number;
|
||||||
name: string;
|
name: string;
|
||||||
properties: { [key: string]: string };
|
properties?: ITiledMapProperty[];
|
||||||
spacing: number;
|
spacing: number;
|
||||||
tilecount: number;
|
tilecount: number;
|
||||||
tileheight: number;
|
tileheight: number;
|
||||||
@ -182,7 +182,7 @@ export interface ITile {
|
|||||||
id: number;
|
id: number;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
|
||||||
properties?: Array<ITiledMapLayerProperty>;
|
properties?: ITiledMapProperty[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITiledMapTerrain {
|
export interface ITiledMapTerrain {
|
||||||
|
@ -11,7 +11,7 @@ import nav from "./Api/iframe/nav";
|
|||||||
import controls from "./Api/iframe/controls";
|
import controls from "./Api/iframe/controls";
|
||||||
import ui from "./Api/iframe/ui";
|
import ui from "./Api/iframe/ui";
|
||||||
import sound from "./Api/iframe/sound";
|
import sound from "./Api/iframe/sound";
|
||||||
import room, {setMapURL, setRoomId} from "./Api/iframe/room";
|
import room, {initVariables, setMapURL, setRoomId} from "./Api/iframe/room";
|
||||||
import player, {setPlayerName, setTags, setUuid} from "./Api/iframe/player";
|
import player, {setPlayerName, setTags, setUuid} from "./Api/iframe/player";
|
||||||
import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor";
|
import type { ButtonDescriptor } from "./Api/iframe/Ui/ButtonDescriptor";
|
||||||
import type { Popup } from "./Api/iframe/Ui/Popup";
|
import type { Popup } from "./Api/iframe/Ui/Popup";
|
||||||
@ -29,6 +29,7 @@ const initPromise = new Promise<void>((resolve) => {
|
|||||||
setMapURL(state.mapUrl);
|
setMapURL(state.mapUrl);
|
||||||
setTags(state.tags);
|
setTags(state.tags);
|
||||||
setUuid(state.uuid);
|
setUuid(state.uuid);
|
||||||
|
initVariables(state.variables as Map<string, unknown>);
|
||||||
resolve();
|
resolve();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Trying to read variable "doorOpened" whose default property is true. This should display "true".');
|
||||||
|
console.log('doorOpened', WA.room.loadVariable('doorOpened'));
|
||||||
|
|
||||||
console.log('Trying to set variable "not_exists". This should display an error in the console.')
|
console.log('Trying to set variable "not_exists". This should display an error in the console.')
|
||||||
WA.room.saveVariable('not_exists', 'foo');
|
WA.room.saveVariable('not_exists', 'foo');
|
||||||
|
|
||||||
console.log('Trying to set variable "config". This should work.');
|
|
||||||
WA.room.saveVariable('config', {'foo': 'bar'});
|
|
||||||
|
|
||||||
console.log('Trying to read variable "config". This should display a {"foo": "bar"} object.');
|
|
||||||
console.log(WA.room.loadVariable('config'));
|
|
||||||
|
|
||||||
|
console.log('Trying to set variable "config". This should work.');
|
||||||
|
WA.room.saveVariable('config', {'foo': 'bar'});
|
||||||
|
|
||||||
|
console.log('Trying to read variable "config". This should display a {"foo": "bar"} object.');
|
||||||
|
console.log(WA.room.loadVariable('config'));
|
||||||
|
});
|
||||||
|
@ -72,6 +72,24 @@
|
|||||||
"template":"config.tx",
|
"template":"config.tx",
|
||||||
"x":57.5,
|
"x":57.5,
|
||||||
"y":111
|
"y":111
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":0,
|
||||||
|
"id":6,
|
||||||
|
"name":"doorOpened",
|
||||||
|
"point":true,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"default",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"rotation":0,
|
||||||
|
"type":"variable",
|
||||||
|
"visible":true,
|
||||||
|
"width":0,
|
||||||
|
"x":131.38069962269,
|
||||||
|
"y":106.004988169086
|
||||||
}],
|
}],
|
||||||
"opacity":1,
|
"opacity":1,
|
||||||
"type":"objectgroup",
|
"type":"objectgroup",
|
||||||
@ -80,7 +98,7 @@
|
|||||||
"y":0
|
"y":0
|
||||||
}],
|
}],
|
||||||
"nextlayerid":8,
|
"nextlayerid":8,
|
||||||
"nextobjectid":6,
|
"nextobjectid":8,
|
||||||
"orientation":"orthogonal",
|
"orientation":"orthogonal",
|
||||||
"properties":[
|
"properties":[
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user