Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
8a8a537a51 |
@ -5,7 +5,7 @@ JITSI_PRIVATE_MODE=false
|
||||
JITSI_ISS=
|
||||
SECRET_JITSI_KEY=
|
||||
ADMIN_API_TOKEN=123
|
||||
START_ROOM_URL=/_/global/maps.workadventure.localhost/starter/map.json
|
||||
START_ROOM_URL=/_/global/maps.workadventure.localhost/Floor0/floor0.json
|
||||
# If your Turn server is configured to use the Turn REST API, you should put the shared auth secret here.
|
||||
# If you are using Coturn, this is the value of the "static-auth-secret" parameter in your coturn config file.
|
||||
# Keep empty if you are sharing hard coded / clear text credentials.
|
||||
@ -22,10 +22,3 @@ MAX_USERNAME_LENGTH=8
|
||||
OPID_CLIENT_ID=
|
||||
OPID_CLIENT_SECRET=
|
||||
OPID_CLIENT_ISSUER=
|
||||
OPID_CLIENT_REDIRECT_URL=
|
||||
OPID_LOGIN_SCREEN_PROVIDER=http://pusher.workadventure.localhost/login-screen
|
||||
OPID_PROFILE_SCREEN_PROVIDER=
|
||||
DISABLE_ANONYMOUS=
|
||||
|
||||
# If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want
|
||||
CONTACT_URL=
|
2
.github/workflows/build-and-deploy.yml
vendored
@ -190,8 +190,6 @@ jobs:
|
||||
SECRET_JITSI_KEY: ${{ secrets.SECRET_JITSI_KEY }}
|
||||
TURN_STATIC_AUTH_SECRET: ${{ secrets.TURN_STATIC_AUTH_SECRET }}
|
||||
DEPLOY_REF: ${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }}
|
||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
|
||||
with:
|
||||
namespace: workadventure-${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }}
|
||||
|
||||
|
9
.github/workflows/continuous_integration.yml
vendored
@ -61,14 +61,15 @@ jobs:
|
||||
run: yarn run lint
|
||||
working-directory: "front"
|
||||
|
||||
- name: "Pretty"
|
||||
run: yarn run pretty-check
|
||||
working-directory: "front"
|
||||
|
||||
- name: "Jasmine"
|
||||
run: yarn test
|
||||
working-directory: "front"
|
||||
|
||||
# We will enable prettier checks on front in a few month, when most PRs without prettier have been merged
|
||||
# - name: "Prettier"
|
||||
# run: yarn run pretty-check
|
||||
# working-directory: "front"
|
||||
|
||||
continuous-integration-pusher:
|
||||
name: "Continuous Integration Pusher"
|
||||
|
||||
|
60
.github/workflows/end_to_end_tests.yml
vendored
@ -1,60 +0,0 @@
|
||||
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
|
||||
|
||||
name: "End to end tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
end-to-end-tests:
|
||||
name: "End-to-end testcafe tests"
|
||||
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v2.0.0"
|
||||
|
||||
- name: "Setup .env file"
|
||||
run: cp .env.template .env
|
||||
|
||||
- name: "Edit ownership of file for test cases"
|
||||
run: sudo chown 1000:1000 -R .
|
||||
|
||||
- name: "Start environment"
|
||||
run: docker-compose up -d
|
||||
|
||||
- name: "Wait for environment to build (and downloading testcafe image)"
|
||||
run: (docker-compose -f docker-compose.testcafe.yml pull &) && docker-compose logs -f --tail=0 front | grep -q "Compiled successfully"
|
||||
|
||||
# - name: "temp debug: display logs"
|
||||
# run: docker-compose logs
|
||||
#
|
||||
# - name: "Wait for back start"
|
||||
# run: docker-compose logs -f back | grep -q "WorkAdventure HTTP API starting on port"
|
||||
#
|
||||
# - name: "Wait for pusher start"
|
||||
# run: docker-compose logs -f pusher | grep -q "WorkAdventure starting on port"
|
||||
|
||||
- name: "Run tests"
|
||||
run: docker-compose -f docker-compose.testcafe.yml up --exit-code-from testcafe
|
||||
|
||||
- name: Upload failed tests
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: my-artifact
|
||||
path: './tests/screenshots/'
|
||||
|
||||
- name: Display state
|
||||
if: ${{ failure() }}
|
||||
run: docker-compose ps
|
||||
|
||||
- name: Display logs
|
||||
if: ${{ failure() }}
|
||||
run: docker-compose logs
|
48
CHANGELOG.md
@ -1,53 +1,5 @@
|
||||
## Version develop
|
||||
|
||||
### Updates
|
||||
- Added multi Co-Website management
|
||||
|
||||
### Bugfix
|
||||
- Moving a discussion over a user will now add this user to the discussion
|
||||
- Being in a silent zone new forces mediaConstraints to false (#1508)
|
||||
- Fixes for the emote menu (#1501)
|
||||
- Fixing chat message attributed to wrong user (#1507 #1528)
|
||||
|
||||
## Version 1.5.0
|
||||
### Updates
|
||||
- Added support for login with OpenID Connect
|
||||
- New scripting library available to extend WorkAdventure: see [Scripting API Extra](https://github.com/workadventure/scripting-api-extra/)
|
||||
- New menu design!
|
||||
- New `openTab` property (#1419)
|
||||
- Possible integration with Posthog (#1458)
|
||||
|
||||
### Bugfix
|
||||
- Fixing layers flattened several times (#1427 @Lurkars)
|
||||
- Fixing CSS of video elements
|
||||
- Chat now scrolls to bottom when opened (#1450)
|
||||
- Fixing silent zone not respected when exiting from Jitsi (#1456)
|
||||
- Fixing "yarn install" failing because of missing rights on some Docker installs (#1457)
|
||||
- Fixing audio not shut down when exiting a room (#1459)
|
||||
|
||||
### Misc
|
||||
- Finished migrating "Build your map" documentation into the "/docs" directory of this repository (#1417 #1385)
|
||||
- Refactoring documentation (dedicated page for variables) (#1414)
|
||||
- Front container code is now completely linted (#1413)
|
||||
|
||||
## Version 1.4.15
|
||||
|
||||
### Updates
|
||||
- New scripting API features :
|
||||
- Use `WA.ui.registerMenuCommand(commandDescriptor: string, options: MenuOptions): Menu` to add a custom menu or an iframe to the menu.
|
||||
- New `jitsiWidth` parameter to set the width of Jitsi and Cowebsite (#1398 @tabascoeye)
|
||||
- Refactored the way videos are displayed to better cope for vertical videos (on mobile)
|
||||
- Fixing reconnection issues after 5 minutes of an inactive tab on Google Chrome
|
||||
- Changes performed in `WA.room.setPropertyLayer` now have a real-time impact (#1395)
|
||||
|
||||
### Bugfixes
|
||||
- Fixing streams in bubbles sometimes improperly muted when there are more than 2 people in the bubble (#1400 #1402)
|
||||
- Properly displaying carriage returns in popups (#1388)
|
||||
- `WA.state` now answers correctly to "in" keyword (#1393)
|
||||
- Variables can now be nested in group layers (#1406)
|
||||
|
||||
## Version 1.4.14
|
||||
|
||||
### Updates
|
||||
- New scripting API features :
|
||||
- Use `WA.room.loadTileset(url: string) : Promise<number>` to load a tileset from a JSON file.
|
||||
|
BIN
README-INTRO.jpg
Normal file
After Width: | Height: | Size: 386 KiB |
Before Width: | Height: | Size: 16 KiB |
BIN
README-MAP.png
Before Width: | Height: | Size: 60 KiB |
17
README.md
@ -1,18 +1,17 @@
|
||||
 [](https://discord.gg/YGtngdh9gt)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
Live demo [here](https://play.workadventu.re/@/tcm/workadventure/wa-village).
|
||||
Demo here : [https://workadventu.re/](https://workadventu.re/).
|
||||
|
||||
# WorkAdventure
|
||||
# Work Adventure
|
||||
|
||||
WorkAdventure is a web-based collaborative workspace presented in the form of a
|
||||
Work Adventure is a web-based collaborative workspace for small to medium teams (2-100 people) presented in the form of a
|
||||
16-bit video game.
|
||||
|
||||
In WorkAdventure you can move around your office and talk to your colleagues (using a video-chat system, triggered when you approach someone).
|
||||
In Work Adventure, you can move around your office and talk to your colleagues (using a video-chat feature that is
|
||||
triggered when you move next to a colleague).
|
||||
|
||||
See more features for your virtual office: https://workadventu.re/virtual-office
|
||||
|
||||
## Setting up a development environment
|
||||
|
||||
@ -21,7 +20,6 @@ Install Docker.
|
||||
Run:
|
||||
|
||||
```
|
||||
cp .env.template .env
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
@ -37,9 +35,6 @@ Note: on some OSes, you will need to add this line to your `/etc/hosts` file:
|
||||
127.0.0.1 workadventure.localhost
|
||||
```
|
||||
|
||||
Note: If on the first run you get a page with "network error". Try to ``docker-compose stop`` , then ``docker-compose start``.
|
||||
Note 2: If you are still getting "network error". Make sure you are authorizing the self-signed certificate by entering https://pusher.workadventure.localhost and accepting them.
|
||||
|
||||
### MacOS developers, your environment with Vagrant
|
||||
|
||||
If you are using MacOS, you can increase Docker performance using Vagrant. If you want more explanations, you can read [this medium article](https://medium.com/better-programming/vagrant-to-increase-docker-performance-with-macos-25b354b0c65c).
|
||||
|
@ -40,8 +40,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/thecodingmachine/workadventure#readme",
|
||||
"dependencies": {
|
||||
"@workadventure/tiled-map-type-guard": "^1.0.3",
|
||||
"axios": "^0.21.2",
|
||||
"@workadventure/tiled-map-type-guard": "^1.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"busboy": "^0.3.1",
|
||||
"circular-json": "^0.5.9",
|
||||
"debug": "^4.3.1",
|
||||
@ -54,6 +54,7 @@
|
||||
"prom-client": "^12.0.0",
|
||||
"query-string": "^6.13.3",
|
||||
"redis": "^3.1.2",
|
||||
"systeminformation": "^4.31.1",
|
||||
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
||||
"uuidv4": "^6.0.7"
|
||||
},
|
||||
|
@ -9,12 +9,12 @@ const JITSI_ISS = process.env.JITSI_ISS || "";
|
||||
const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || "";
|
||||
const HTTP_PORT = parseInt(process.env.HTTP_PORT || "8080") || 8080;
|
||||
const GRPC_PORT = parseInt(process.env.GRPC_PORT || "50051") || 50051;
|
||||
export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 30; // maximum time (in second) without activity before a socket is closed
|
||||
export const TURN_STATIC_AUTH_SECRET = process.env.TURN_STATIC_AUTH_SECRET || "";
|
||||
export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4");
|
||||
export const REDIS_HOST = process.env.REDIS_HOST || undefined;
|
||||
export const REDIS_PORT = parseInt(process.env.REDIS_PORT || "6379") || 6379;
|
||||
export const REDIS_PASSWORD = process.env.REDIS_PASSWORD || undefined;
|
||||
export const STORE_VARIABLES_FOR_LOCAL_MAPS = process.env.STORE_VARIABLES_FOR_LOCAL_MAPS === "true";
|
||||
|
||||
export {
|
||||
MINIMUM_DISTANCE,
|
||||
|
@ -26,7 +26,6 @@ import { VariablesManager } from "../Services/VariablesManager";
|
||||
import { ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
||||
import { LocalUrlError } from "../Services/LocalUrlError";
|
||||
import { emitErrorOnRoomSocket } from "../Services/MessageHelpers";
|
||||
import { VariableError } from "../Services/VariableError";
|
||||
|
||||
export type ConnectCallback = (user: User, group: Group) => void;
|
||||
export type DisconnectCallback = (user: User, group: Group) => void;
|
||||
@ -182,7 +181,6 @@ export class GameRoom {
|
||||
|
||||
private updateUserGroup(user: User): void {
|
||||
user.group?.updatePosition();
|
||||
user.group?.searchForNearbyUsers();
|
||||
|
||||
if (user.silent) {
|
||||
return;
|
||||
@ -208,7 +206,6 @@ export class GameRoom {
|
||||
const group: Group = new Group(
|
||||
this.roomUrl,
|
||||
[user, closestUser],
|
||||
this.groupRadius,
|
||||
this.connectCallback,
|
||||
this.disconnectCallback,
|
||||
this.positionNotifier
|
||||
@ -337,62 +334,30 @@ export class GameRoom {
|
||||
// First, let's check if "user" is allowed to modify the variable.
|
||||
const variableManager = await this.getVariableManager();
|
||||
|
||||
try {
|
||||
const readableBy = variableManager.setVariable(name, value, user);
|
||||
const readableBy = variableManager.setVariable(name, value, user);
|
||||
|
||||
// If the variable was not changed, let's not dispatch anything.
|
||||
if (readableBy === false) {
|
||||
return;
|
||||
}
|
||||
// If the variable was not changed, let's not dispatch anything.
|
||||
if (readableBy === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: should we batch those every 100ms?
|
||||
const variableMessage = new VariableWithTagMessage();
|
||||
variableMessage.setName(name);
|
||||
variableMessage.setValue(value);
|
||||
if (readableBy) {
|
||||
variableMessage.setReadableby(readableBy);
|
||||
}
|
||||
// TODO: should we batch those every 100ms?
|
||||
const variableMessage = new VariableWithTagMessage();
|
||||
variableMessage.setName(name);
|
||||
variableMessage.setValue(value);
|
||||
if (readableBy) {
|
||||
variableMessage.setReadableby(readableBy);
|
||||
}
|
||||
|
||||
const subMessage = new SubToPusherRoomMessage();
|
||||
subMessage.setVariablemessage(variableMessage);
|
||||
const subMessage = new SubToPusherRoomMessage();
|
||||
subMessage.setVariablemessage(variableMessage);
|
||||
|
||||
const batchMessage = new BatchToPusherRoomMessage();
|
||||
batchMessage.addPayload(subMessage);
|
||||
const batchMessage = new BatchToPusherRoomMessage();
|
||||
batchMessage.addPayload(subMessage);
|
||||
|
||||
// Dispatch the message on the room listeners
|
||||
for (const socket of this.roomListeners) {
|
||||
socket.write(batchMessage);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof VariableError) {
|
||||
// Ok, we have an error setting a variable. Either the user is trying to hack the map... or the map
|
||||
// is not up to date. So let's try to reload the map from scratch.
|
||||
if (this.variableManagerLastLoad === undefined) {
|
||||
throw e;
|
||||
}
|
||||
const lastLoaded = new Date().getTime() - this.variableManagerLastLoad.getTime();
|
||||
if (lastLoaded < 10000) {
|
||||
console.log(
|
||||
'An error occurred while setting the "' +
|
||||
name +
|
||||
"\" variable. But we tried to reload the map less than 10 seconds ago, so let's fail."
|
||||
);
|
||||
// Do not try to reload if we tried to reload less than 10 seconds ago.
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Reset the variable manager
|
||||
this.variableManagerPromise = undefined;
|
||||
this.mapPromise = undefined;
|
||||
|
||||
console.log(
|
||||
'An error occurred while setting the "' + name + "\" variable. Let's reload the map and try again"
|
||||
);
|
||||
// Try to set the variable again!
|
||||
await this.setVariable(name, value, user);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
// Dispatch the message on the room listeners
|
||||
for (const socket of this.roomListeners) {
|
||||
socket.write(batchMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,11 +447,9 @@ export class GameRoom {
|
||||
}
|
||||
|
||||
private variableManagerPromise: Promise<VariablesManager> | undefined;
|
||||
private variableManagerLastLoad: Date | undefined;
|
||||
|
||||
private getVariableManager(): Promise<VariablesManager> {
|
||||
if (!this.variableManagerPromise) {
|
||||
this.variableManagerLastLoad = new Date();
|
||||
this.variableManagerPromise = this.getMap()
|
||||
.then((map) => {
|
||||
const variablesManager = new VariablesManager(this.roomUrl, map);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ConnectCallback, DisconnectCallback, GameRoom } from "./GameRoom";
|
||||
import { ConnectCallback, DisconnectCallback } from "./GameRoom";
|
||||
import { User } from "./User";
|
||||
import { PositionInterface } from "_Model/PositionInterface";
|
||||
import { Movable } from "_Model/Movable";
|
||||
import { PositionNotifier } from "_Model/PositionNotifier";
|
||||
import { gaugeManager } from "../Services/GaugeManager";
|
||||
import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable";
|
||||
import type { Zone } from "../Model/Zone";
|
||||
|
||||
export class Group implements Movable {
|
||||
private static nextId: number = 1;
|
||||
@ -13,14 +13,13 @@ export class Group implements Movable {
|
||||
private users: Set<User>;
|
||||
private x!: number;
|
||||
private y!: number;
|
||||
private hasEditedGauge: boolean = false;
|
||||
private wasDestroyed: boolean = false;
|
||||
private roomId: string;
|
||||
private currentZone: Zone | null = null;
|
||||
|
||||
constructor(
|
||||
roomId: string,
|
||||
users: User[],
|
||||
private groupRadius: number,
|
||||
private connectCallback: ConnectCallback,
|
||||
private disconnectCallback: DisconnectCallback,
|
||||
private positionNotifier: PositionNotifier
|
||||
@ -29,6 +28,13 @@ export class Group implements Movable {
|
||||
this.users = new Set<User>();
|
||||
this.id = Group.nextId;
|
||||
Group.nextId++;
|
||||
//we only send a event for prometheus metrics if the group lives more than 5 seconds
|
||||
setTimeout(() => {
|
||||
if (!this.wasDestroyed) {
|
||||
this.hasEditedGauge = true;
|
||||
gaugeManager.incNbGroupsPerRoomGauge(roomId);
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
users.forEach((user: User) => {
|
||||
this.join(user);
|
||||
@ -79,22 +85,9 @@ export class Group implements Movable {
|
||||
this.y = y;
|
||||
|
||||
if (oldX === undefined) {
|
||||
this.currentZone = this.positionNotifier.enter(this);
|
||||
this.positionNotifier.enter(this);
|
||||
} else {
|
||||
this.currentZone = this.positionNotifier.updatePosition(this, { x, y }, { x: oldX, y: oldY });
|
||||
}
|
||||
}
|
||||
|
||||
searchForNearbyUsers(): void {
|
||||
if (!this.currentZone) return;
|
||||
|
||||
for (const user of this.positionNotifier.getAllUsersInSquareAroundZone(this.currentZone)) {
|
||||
if (user.group || this.isFull()) return; //we ignore users that are already in a group.
|
||||
const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), this.getPosition());
|
||||
if (distance < this.groupRadius) {
|
||||
this.join(user);
|
||||
this.updatePosition();
|
||||
}
|
||||
this.positionNotifier.updatePosition(this, { x, y }, { x: oldX, y: oldY });
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +126,7 @@ export class Group implements Movable {
|
||||
* Usually used when there is only one user left.
|
||||
*/
|
||||
destroy(): void {
|
||||
if (this.hasEditedGauge) gaugeManager.decNbGroupsPerRoomGauge(this.roomId);
|
||||
for (const user of this.users) {
|
||||
this.leave(user);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { EmoteCallback, EntersCallback, LeavesCallback, MovesCallback, Zone } fr
|
||||
import { Movable } from "_Model/Movable";
|
||||
import { PositionInterface } from "_Model/PositionInterface";
|
||||
import { ZoneSocket } from "../RoomManager";
|
||||
import { User } from "../Model/User";
|
||||
import { User } from "_Model/User";
|
||||
import { EmoteEventMessage } from "../Messages/generated/messages_pb";
|
||||
|
||||
interface ZoneDescriptor {
|
||||
@ -20,17 +20,6 @@ interface ZoneDescriptor {
|
||||
j: number;
|
||||
}
|
||||
|
||||
export function* getNearbyDescriptorsMatrix(middleZoneDescriptor: ZoneDescriptor): Generator<ZoneDescriptor> {
|
||||
for (let n = 0; n < 9; n++) {
|
||||
const i = middleZoneDescriptor.i + ((n % 3) - 1);
|
||||
const j = middleZoneDescriptor.j + (Math.floor(n / 3) - 1);
|
||||
|
||||
if (i >= 0 && j >= 0) {
|
||||
yield { i, j };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PositionNotifier {
|
||||
// TODO: we need a way to clean the zones if no one is in the zone and no one listening (to free memory!)
|
||||
|
||||
@ -52,15 +41,14 @@ export class PositionNotifier {
|
||||
};
|
||||
}
|
||||
|
||||
public enter(thing: Movable): Zone {
|
||||
public enter(thing: Movable): void {
|
||||
const position = thing.getPosition();
|
||||
const zoneDesc = this.getZoneDescriptorFromCoordinates(position.x, position.y);
|
||||
const zone = this.getZone(zoneDesc.i, zoneDesc.j);
|
||||
zone.enter(thing, null, position);
|
||||
return zone;
|
||||
}
|
||||
|
||||
public updatePosition(thing: Movable, newPosition: PositionInterface, oldPosition: PositionInterface): Zone {
|
||||
public updatePosition(thing: Movable, newPosition: PositionInterface, oldPosition: PositionInterface): void {
|
||||
// Did we change zone?
|
||||
const oldZoneDesc = this.getZoneDescriptorFromCoordinates(oldPosition.x, oldPosition.y);
|
||||
const newZoneDesc = this.getZoneDescriptorFromCoordinates(newPosition.x, newPosition.y);
|
||||
@ -74,11 +62,9 @@ export class PositionNotifier {
|
||||
|
||||
// Enter new zone
|
||||
newZone.enter(thing, oldZone, newPosition);
|
||||
return newZone;
|
||||
} else {
|
||||
const zone = this.getZone(oldZoneDesc.i, oldZoneDesc.j);
|
||||
zone.move(thing, newPosition);
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,16 +106,4 @@ export class PositionNotifier {
|
||||
const zone = this.getZone(zoneDesc.i, zoneDesc.j);
|
||||
zone.emitEmoteEvent(emoteEventMessage);
|
||||
}
|
||||
|
||||
public *getAllUsersInSquareAroundZone(zone: Zone): Generator<User> {
|
||||
const zoneDescriptor = this.getZoneDescriptorFromCoordinates(zone.x, zone.y);
|
||||
for (const d of getNearbyDescriptorsMatrix(zoneDescriptor)) {
|
||||
const zone = this.getZone(d.i, d.j);
|
||||
for (const thing of zone.getThings()) {
|
||||
if (thing instanceof User) {
|
||||
yield thing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,15 @@ class GaugeManager {
|
||||
this.nbClientsGauge.dec();
|
||||
this.nbClientsPerRoomGauge.dec({ room: roomId });
|
||||
}
|
||||
|
||||
incNbGroupsPerRoomGauge(roomId: string): void {
|
||||
this.nbGroupsPerRoomCounter.inc({ room: roomId });
|
||||
this.nbGroupsPerRoomGauge.inc({ room: roomId });
|
||||
}
|
||||
|
||||
decNbGroupsPerRoomGauge(roomId: string): void {
|
||||
this.nbGroupsPerRoomGauge.dec({ room: roomId });
|
||||
}
|
||||
}
|
||||
|
||||
export const gaugeManager = new GaugeManager();
|
||||
|
@ -5,13 +5,12 @@ import { promisify } from "util";
|
||||
import { LocalUrlError } from "./LocalUrlError";
|
||||
import { ITiledMap } from "@workadventure/tiled-map-type-guard";
|
||||
import { isTiledMap } from "@workadventure/tiled-map-type-guard/dist";
|
||||
import { STORE_VARIABLES_FOR_LOCAL_MAPS } from "../Enum/EnvironmentVariable";
|
||||
|
||||
class MapFetcher {
|
||||
async fetchMap(mapUrl: string): Promise<ITiledMap> {
|
||||
// Before trying to make the query, let's verify the map is actually on the open internet (and not a local test map)
|
||||
|
||||
if ((await this.isLocalUrl(mapUrl)) && !STORE_VARIABLES_FOR_LOCAL_MAPS) {
|
||||
if (await this.isLocalUrl(mapUrl)) {
|
||||
throw new LocalUrlError('URL for map "' + mapUrl + '" targets a local map');
|
||||
}
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Errors related to variable handling.
|
||||
*/
|
||||
export class VariableError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, VariableError.prototype);
|
||||
}
|
||||
}
|
@ -1,16 +1,10 @@
|
||||
/**
|
||||
* Handles variables shared between the scripting API and the server.
|
||||
*/
|
||||
import {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapObject,
|
||||
ITiledMapObjectLayer,
|
||||
} from "@workadventure/tiled-map-type-guard/dist";
|
||||
import { ITiledMap, ITiledMapObject, ITiledMapObjectLayer } from "@workadventure/tiled-map-type-guard/dist";
|
||||
import { User } from "_Model/User";
|
||||
import { variablesRepository } from "./Repository/VariablesRepository";
|
||||
import { redisClient } from "./RedisClient";
|
||||
import { VariableError } from "./VariableError";
|
||||
|
||||
interface Variable {
|
||||
defaultValue?: string;
|
||||
@ -89,31 +83,23 @@ export class VariablesManager {
|
||||
private static findVariablesInMap(map: ITiledMap): Map<string, Variable> {
|
||||
const objects = new Map<string, Variable>();
|
||||
for (const layer of map.layers) {
|
||||
this.recursiveFindVariablesInLayer(layer, objects);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
if (layer.type === "objectgroup") {
|
||||
for (const object of (layer as ITiledMapObjectLayer).objects) {
|
||||
if (object.type === "variable") {
|
||||
if (object.template) {
|
||||
console.warn(
|
||||
'Warning, a variable object is using a Tiled "template". WorkAdventure does not support objects generated from Tiled templates.'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
private static recursiveFindVariablesInLayer(layer: ITiledMapLayer, objects: Map<string, Variable>): void {
|
||||
if (layer.type === "objectgroup") {
|
||||
for (const object of layer.objects) {
|
||||
if (object.type === "variable") {
|
||||
if (object.template) {
|
||||
console.warn(
|
||||
'Warning, a variable object is using a Tiled "template". WorkAdventure does not support objects generated from Tiled templates.'
|
||||
);
|
||||
continue;
|
||||
// We store a copy of the object (to make it immutable)
|
||||
objects.set(object.name, this.iTiledObjectToVariable(object));
|
||||
}
|
||||
|
||||
// We store a copy of the object (to make it immutable)
|
||||
objects.set(object.name, this.iTiledObjectToVariable(object));
|
||||
}
|
||||
}
|
||||
} else if (layer.type === "group") {
|
||||
for (const innerLayer of layer.layers) {
|
||||
this.recursiveFindVariablesInLayer(innerLayer, objects);
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
private static iTiledObjectToVariable(object: ITiledMapObject): Variable {
|
||||
@ -175,13 +161,11 @@ export class VariablesManager {
|
||||
if (this.variableObjects) {
|
||||
variableObject = this.variableObjects.get(name);
|
||||
if (variableObject === undefined) {
|
||||
throw new VariableError(
|
||||
'Trying to set a variable "' + name + '" that is not defined as an object in the map.'
|
||||
);
|
||||
throw new Error('Trying to set a variable "' + name + '" that is not defined as an object in the map.');
|
||||
}
|
||||
|
||||
if (variableObject.writableBy && !user.tags.includes(variableObject.writableBy)) {
|
||||
throw new VariableError(
|
||||
throw new Error(
|
||||
'Trying to set a variable "' +
|
||||
name +
|
||||
'". User "' +
|
||||
|
@ -1,67 +0,0 @@
|
||||
import "jasmine";
|
||||
import { getNearbyDescriptorsMatrix } from "../src/Model/PositionNotifier";
|
||||
|
||||
describe("getNearbyDescriptorsMatrix", () => {
|
||||
it("should create a matrix of coordinates in a square around the parameter", () => {
|
||||
const matrix = [];
|
||||
for (const d of getNearbyDescriptorsMatrix({ i: 1, j: 1 })) {
|
||||
matrix.push(d);
|
||||
}
|
||||
|
||||
expect(matrix).toEqual([
|
||||
{ i: 0, j: 0 },
|
||||
{ i: 1, j: 0 },
|
||||
{ i: 2, j: 0 },
|
||||
{ i: 0, j: 1 },
|
||||
{ i: 1, j: 1 },
|
||||
{ i: 2, j: 1 },
|
||||
{ i: 0, j: 2 },
|
||||
{ i: 1, j: 2 },
|
||||
{ i: 2, j: 2 },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should create a matrix of coordinates in a square around the parameter bis", () => {
|
||||
const matrix = [];
|
||||
for (const d of getNearbyDescriptorsMatrix({ i: 8, j: 3 })) {
|
||||
matrix.push(d);
|
||||
}
|
||||
|
||||
expect(matrix).toEqual([
|
||||
{ i: 7, j: 2 },
|
||||
{ i: 8, j: 2 },
|
||||
{ i: 9, j: 2 },
|
||||
{ i: 7, j: 3 },
|
||||
{ i: 8, j: 3 },
|
||||
{ i: 9, j: 3 },
|
||||
{ i: 7, j: 4 },
|
||||
{ i: 8, j: 4 },
|
||||
{ i: 9, j: 4 },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should not create a matrix with negative coordinates", () => {
|
||||
const matrix = [];
|
||||
for (const d of getNearbyDescriptorsMatrix({ i: 0, j: 0 })) {
|
||||
matrix.push(d);
|
||||
}
|
||||
|
||||
expect(matrix).toEqual([
|
||||
{ i: 0, j: 0 },
|
||||
{ i: 1, j: 0 },
|
||||
{ i: 0, j: 1 },
|
||||
{ i: 1, j: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
/*it("should not create a matrix with coordinates bigger than its dimmensions", () => {
|
||||
const matrix = getNearbyDescriptorsMatrix({i: 4, j: 4}, 5, 5);
|
||||
|
||||
expect(matrix).toEqual([
|
||||
{i: 3,j: 3},
|
||||
{i: 4,j: 3},
|
||||
{i: 3,j: 4},
|
||||
{i: 4,j: 4},
|
||||
])
|
||||
});*/
|
||||
});
|
@ -194,10 +194,10 @@
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@workadventure/tiled-map-type-guard@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@workadventure/tiled-map-type-guard/-/tiled-map-type-guard-1.0.3.tgz#62c2061cacbe1360b84162af0b7e4639ed8bfa7e"
|
||||
integrity sha512-pUMxBBZHYAFkpnGWZAVAE8+M+Wn9UtzqZhXvBBBbB1gEakHIka7ahdTGfh0DgRaWrVszVXOP3tf49Dhdmn9pDg==
|
||||
"@workadventure/tiled-map-type-guard@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@workadventure/tiled-map-type-guard/-/tiled-map-type-guard-1.0.0.tgz#02524602ee8b2688429a1f56df1d04da3fc171ba"
|
||||
integrity sha512-Mc0SE128otQnYlScQWVaQVyu1+CkailU/FTBh09UTrVnBAhyMO+jIn9vT9+Dv244xq+uzgQDpXmiVdjgrYFQ+A==
|
||||
dependencies:
|
||||
generic-type-guard "^3.4.1"
|
||||
|
||||
@ -381,12 +381,12 @@ atob@^2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
axios@^0.21.2:
|
||||
version "0.21.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017"
|
||||
integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.0"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -554,7 +554,7 @@ chokidar@^3.4.0:
|
||||
optionalDependencies:
|
||||
fsevents "~2.1.2"
|
||||
|
||||
chownr@^1.1.4:
|
||||
chownr@^1.1.1:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||
@ -1142,10 +1142,10 @@ flatted@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
|
||||
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
|
||||
|
||||
follow-redirects@^1.14.0:
|
||||
version "1.14.4"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
|
||||
integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||
|
||||
for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
@ -1159,7 +1159,7 @@ fragment-cache@^0.2.1:
|
||||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
fs-minipass@^1.2.7:
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
|
||||
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
|
||||
@ -1969,7 +1969,7 @@ minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minipass@^2.6.0, minipass@^2.9.0:
|
||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
|
||||
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
|
||||
@ -1977,7 +1977,7 @@ minipass@^2.6.0, minipass@^2.9.0:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.3.3:
|
||||
minizlib@^1.2.1:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
|
||||
integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
|
||||
@ -1992,7 +1992,7 @@ mixin-deep@^1.2.0:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
|
||||
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
|
||||
@ -2290,9 +2290,9 @@ path-key@^3.0.0, path-key@^3.1.0:
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
@ -2578,7 +2578,7 @@ rxjs@^6.6.7:
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1:
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
@ -2962,6 +2962,11 @@ supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
systeminformation@^4.31.1:
|
||||
version "4.31.1"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-4.31.1.tgz#2e02c26987494d4b6a4d2d83138724593bc98d50"
|
||||
integrity sha512-dVCDWNMN8ncMZo5vbMCA5dpAdMgzafK2ucuJy5LFmGtp1cG6farnPg8QNvoOSky9SkFoEX1Aw0XhcOFV6TnLYA==
|
||||
|
||||
table@^5.2.3:
|
||||
version "5.4.6"
|
||||
resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
|
||||
@ -2973,17 +2978,17 @@ table@^5.2.3:
|
||||
string-width "^3.0.0"
|
||||
|
||||
tar@^4.4.2:
|
||||
version "4.4.19"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
|
||||
integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==
|
||||
version "4.4.13"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
|
||||
integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
|
||||
dependencies:
|
||||
chownr "^1.1.4"
|
||||
fs-minipass "^1.2.7"
|
||||
minipass "^2.9.0"
|
||||
minizlib "^1.3.3"
|
||||
mkdirp "^0.5.5"
|
||||
safe-buffer "^5.2.1"
|
||||
yallist "^3.1.1"
|
||||
chownr "^1.1.1"
|
||||
fs-minipass "^1.2.5"
|
||||
minipass "^2.8.6"
|
||||
minizlib "^1.2.1"
|
||||
mkdirp "^0.5.0"
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.3"
|
||||
|
||||
tdigest@^0.1.1:
|
||||
version "0.1.1"
|
||||
@ -3277,7 +3282,7 @@ y18n@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
|
||||
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
|
||||
|
||||
yallist@^3.0.0, yallist@^3.1.1:
|
||||
yallist@^3.0.0, yallist@^3.0.3:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
6
benchmark/package-lock.json
generated
@ -429,9 +429,9 @@
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
|
||||
},
|
||||
"path-type": {
|
||||
"version": "1.1.0",
|
||||
|
@ -315,8 +315,8 @@ path-is-absolute@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
|
@ -38,7 +38,6 @@ services:
|
||||
JITSI_URL: $JITSI_URL
|
||||
JITSI_PRIVATE_MODE: "$JITSI_PRIVATE_MODE"
|
||||
PUSHER_URL: //pusher.${DOMAIN}
|
||||
ICON_URL: //icon.${DOMAIN}
|
||||
TURN_SERVER: "${TURN_SERVER}"
|
||||
TURN_USER: "${TURN_USER}"
|
||||
TURN_PASSWORD: "${TURN_PASSWORD}"
|
||||
@ -66,7 +65,6 @@ services:
|
||||
API_URL: back:50051
|
||||
JITSI_URL: $JITSI_URL
|
||||
JITSI_ISS: $JITSI_ISS
|
||||
FRONT_URL: https://play.${DOMAIN}
|
||||
labels:
|
||||
- "traefik.http.routers.pusher.rule=Host(`pusher.${DOMAIN}`)"
|
||||
- "traefik.http.routers.pusher.entryPoints=web,traefik"
|
||||
@ -100,15 +98,3 @@ services:
|
||||
- "traefik.http.routers.back-ssl.service=back"
|
||||
- "traefik.http.routers.back-ssl.tls.certresolver=myresolver"
|
||||
restart: unless-stopped
|
||||
|
||||
icon:
|
||||
image: matthiasluedtke/iconserver:v3.13.0
|
||||
labels:
|
||||
- "traefik.http.routers.icon.rule=Host(`icon.${DOMAIN}`)"
|
||||
- "traefik.http.routers.icon.entryPoints=web,traefik"
|
||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.icon-ssl.rule=Host(`icon.${DOMAIN}`)"
|
||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||
- "traefik.http.routers.icon-ssl.tls=true"
|
||||
- "traefik.http.routers.icon-ssl.service=icon"
|
||||
- "traefik.http.routers.icon-ssl.tls.certresolver=myresolver"
|
||||
|
2
debian/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*~
|
||||
\#*\#
|
10
debian/README.Debian
vendored
@ -1,10 +0,0 @@
|
||||
workadventure for Debian
|
||||
-----------------------
|
||||
|
||||
To install:
|
||||
- Install workadventure-back workadventure-front workadventure-pusher
|
||||
- Go to "/var/lib/workadvenure/{back,pusher}" and run "yarn install --production"
|
||||
- Serve "/usr/src/workadventure/front" as web page
|
||||
- Provide configuration for the UI in "/usr/src/workadventure/front/config.js"
|
||||
|
||||
-- unknown <felix@localhost> Sat, 17 Apr 2021 14:06:51 +0200
|
24
debian/changelog
vendored
@ -1,24 +0,0 @@
|
||||
workadventure (1.6.3-1) unstable; urgency=medium
|
||||
|
||||
* Update to 1.6.3
|
||||
|
||||
-- unknown <felix@localhost> Mon, 29 Nov 2021 20:10:29 +0200
|
||||
|
||||
workadventure (1.4.12-1) unstable; urgency=medium
|
||||
|
||||
* Update to 1.4.12
|
||||
|
||||
-- unknown <felix@localhost> Fri, 06 Aug 2021 15:00:35 +0200
|
||||
|
||||
workadventure (1.2.4-2) unstable; urgency=medium
|
||||
|
||||
* Fix chat dialog spacing
|
||||
* Improve systemd unit for backend
|
||||
|
||||
-- unknown <felix@localhost> Wed, 21 Apr 2021 21:55:41 +0200
|
||||
|
||||
workadventure (1.2.4-1) unstable; urgency=medium
|
||||
|
||||
* Initial release
|
||||
|
||||
-- unknown <felix@localhost> Sat, 17 Apr 2021 14:06:51 +0200
|
32
debian/control
vendored
@ -1,32 +0,0 @@
|
||||
Source: workadventure
|
||||
Section: unknown
|
||||
Priority: optional
|
||||
Maintainer: unknown <felix@localhost>
|
||||
Build-Depends: debhelper-compat (= 12), yarnpkg
|
||||
Standards-Version: 4.5.1
|
||||
Homepage: <insert the upstream URL, if relevant>
|
||||
Rules-Requires-Root: no
|
||||
|
||||
Package: workadventure-back
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, yarnpkg
|
||||
Description: <insert up to 60 chars description>
|
||||
<insert long description, indented with spaces>
|
||||
|
||||
Package: workadventure-pusher
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, yarnpkg
|
||||
Description: <insert up to 60 chars description>
|
||||
<insert long description, indented with spaces>
|
||||
|
||||
Package: workadventure-front
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}
|
||||
Description: <insert up to 60 chars description>
|
||||
<insert long description, indented with spaces>
|
||||
|
||||
Package: workadventure-front-map
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, workadventure-front
|
||||
Description: <insert up to 60 chars description>
|
||||
<insert long description, indented with spaces>
|
32
debian/copyright
vendored
@ -1,32 +0,0 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: workadventure
|
||||
Upstream-Contact: <preferred name and address to reach the upstream project>
|
||||
Source: <url://example.com>
|
||||
|
||||
Files: *
|
||||
Copyright: 2021 TheCodingMachine
|
||||
License: AGPL-3 with Commons Clause
|
||||
<Put the license of the package here indented by 1 space>
|
||||
<This follows the format of Description: lines in control file>
|
||||
.
|
||||
<Including paragraphs>
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2021 unknown <felix@localhost>
|
||||
License: GPL-2+
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
||||
|
49
debian/rules
vendored
@ -1,49 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_install:
|
||||
install -Dt debian/workadventure-front/usr/src/workadventure/front front/dist/index.html
|
||||
install -d debian/workadventure-front/usr/src/workadventure/front/js
|
||||
cp -r front/dist/static front/dist/fonts front/dist/resources front/dist/*.js front/dist/*.png front/dist/*.css debian/workadventure-front/usr/src/workadventure/front
|
||||
cp -r front/dist/js/*.js debian/workadventure-front/usr/src/workadventure/front/js
|
||||
|
||||
|
||||
install -d debian/workadventure-front-map/usr/src/workadventure/front/js
|
||||
cp -r front/dist/*.js.map front/dist/*.css.map debian/workadventure-front-map/usr/src/workadventure/front
|
||||
cp -r front/dist/js/*.js.map debian/workadventure-front-map/usr/src/workadventure/front/js
|
||||
|
||||
install -d debian/workadventure-back/usr/src/workadventure/back
|
||||
cp -r back/dist/server.js back/dist/src debian/workadventure-back/usr/src/workadventure/back
|
||||
cp back/yarn.lock back/package.json debian/workadventure-back/usr/src/workadventure/back
|
||||
install -d debian/workadventure-back/var/lib/workadventure/back
|
||||
ln -s /usr/src/workadventure/back/package.json /usr/src/workadventure/back/yarn.lock /usr/src/workadventure/back/src /usr/src/workadventure/back/server.js debian/workadventure-back/var/lib/workadventure/back/
|
||||
|
||||
install -d debian/workadventure-pusher/usr/src/workadventure/pusher
|
||||
cp -r pusher/dist/server.js pusher/dist/src debian/workadventure-pusher/usr/src/workadventure/pusher
|
||||
cp pusher/yarn.lock pusher/package.json debian/workadventure-pusher/usr/src/workadventure/pusher
|
||||
install -d debian/workadventure-back/var/lib/workadventure/pusher
|
||||
ln -s /usr/src/workadventure/pusher/package.json /usr/src/workadventure/pusher/yarn.lock /usr/src/workadventure/pusher/src /usr/src/workadventure/pusher/server.js debian/workadventure-back/var/lib/workadventure/pusher/
|
||||
|
||||
|
||||
front/src/Messages/generated:
|
||||
ln -s ../../../messages/generated front/src/Messages
|
||||
|
||||
back/src/Messages/generated:
|
||||
ln -s ../../../messages/generated back/src/Messages
|
||||
|
||||
pusher/src/Messages/generated:
|
||||
ln -s ../../../messages/generated pusher/src/Messages
|
||||
|
||||
override_dh_auto_build: front/src/Messages/generated back/src/Messages/generated pusher/src/Messages/generated
|
||||
cd messages && yarnpkg install && yarnpkg run proto
|
||||
rm -Rf front/dist/js
|
||||
cd front && ./templater.sh && yarnpkg install && yarnpkg run build
|
||||
cd back && yarnpkg install && yarnpkg run tsc
|
||||
cd pusher && yarnpkg install && yarnpkg run tsc
|
||||
|
||||
# dh_make generated override targets
|
||||
# This is example for Cmake (See https://bugs.debian.org/641051 )
|
||||
#override_dh_auto_configure:
|
||||
# dh_auto_configure -- \
|
||||
# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
|
1
debian/source/format
vendored
@ -1 +0,0 @@
|
||||
3.0 (quilt)
|
13
debian/workadventure-back.service
vendored
@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description="Workadventure Backend"
|
||||
|
||||
[Service]
|
||||
User=webspace-user
|
||||
WorkingDirectory=/var/lib/workadventure/back
|
||||
Environment=NODE_PATH=node_modules
|
||||
ExecStart=node --max-old-space-size=4096 server.js
|
||||
ProtectSystem=Full
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
2
debian/workadventure-docs.docs
vendored
@ -1,2 +0,0 @@
|
||||
README.source
|
||||
README.Debian
|
15
debian/workadventure-pusher.service
vendored
@ -1,15 +0,0 @@
|
||||
[Unit]
|
||||
Description="Workadventure Pusher"
|
||||
|
||||
[Service]
|
||||
User=webspace-user
|
||||
WorkingDirectory=/var/lib/workadventure/pusher
|
||||
Environment=NODE_PATH=node_modules
|
||||
Environment=PUSHER_HTTP_PORT=8081
|
||||
Environment=API_URL=localhost:50051
|
||||
ExecStart=node --max-old-space-size=4096 server.js
|
||||
ProtectSystem=Full
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -4,7 +4,7 @@
|
||||
local tag = namespace,
|
||||
local url = namespace+".test.workadventu.re",
|
||||
// develop branch does not use admin because of issue with SSL certificate of admin as of now.
|
||||
local adminUrl = if std.startsWith(namespace, "admin") then "https://"+url else null,
|
||||
local adminUrl = if namespace == "master" || namespace == "develop" || std.startsWith(namespace, "admin") then "https://"+url else null,
|
||||
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
||||
"version": "1.0",
|
||||
"containers": {
|
||||
@ -17,6 +17,7 @@
|
||||
"ports": [8080, 50051],
|
||||
"env": {
|
||||
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
"JITSI_ISS": env.JITSI_ISS,
|
||||
"JITSI_URL": env.JITSI_URL,
|
||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||
@ -24,7 +25,6 @@
|
||||
"REDIS_HOST": "redis",
|
||||
} + (if adminUrl != null then {
|
||||
"ADMIN_API_URL": adminUrl,
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
} else {})
|
||||
},
|
||||
"back2": {
|
||||
@ -36,6 +36,7 @@
|
||||
"ports": [8080, 50051],
|
||||
"env": {
|
||||
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
"JITSI_ISS": env.JITSI_ISS,
|
||||
"JITSI_URL": env.JITSI_URL,
|
||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||
@ -43,7 +44,6 @@
|
||||
"REDIS_HOST": "redis",
|
||||
} + (if adminUrl != null then {
|
||||
"ADMIN_API_URL": adminUrl,
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
} else {})
|
||||
},
|
||||
"pusher": {
|
||||
@ -55,15 +55,13 @@
|
||||
"ports": [8080],
|
||||
"env": {
|
||||
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
"JITSI_ISS": env.JITSI_ISS,
|
||||
"JITSI_URL": env.JITSI_URL,
|
||||
"API_URL": "back1:50051,back2:50051",
|
||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||
"FRONT_URL": "https://play-"+url
|
||||
} + (if adminUrl != null then {
|
||||
"ADMIN_API_URL": adminUrl,
|
||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||
"ADMIN_SOCKETS_TOKEN": env.ADMIN_SOCKETS_TOKEN,
|
||||
} else {})
|
||||
},
|
||||
"front": {
|
||||
@ -77,13 +75,11 @@
|
||||
"UPLOADER_URL": "//uploader-"+url,
|
||||
"ADMIN_URL": "//"+url,
|
||||
"JITSI_URL": env.JITSI_URL,
|
||||
#POSTHOG
|
||||
"POSTHOG_API_KEY": if namespace == "master" then env.POSTHOG_API_KEY else "",
|
||||
"POSTHOG_URL": if namespace == "master" then env.POSTHOG_URL else "",
|
||||
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
|
||||
"JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false",
|
||||
"START_ROOM_URL": "/_/global/maps-"+url+"/starter/map.json"
|
||||
"START_ROOM_URL": "/_/global/maps-"+url+"/Floor0/floor0.json"
|
||||
//"GA_TRACKING_ID": "UA-10196481-11"
|
||||
}
|
||||
},
|
||||
"uploader": {
|
||||
@ -105,7 +101,6 @@
|
||||
},
|
||||
"redis": {
|
||||
"image": "redis:6",
|
||||
"ports": [6379]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
@ -28,9 +28,8 @@ services:
|
||||
NODE_ENV: development
|
||||
PUSHER_URL: /pusher
|
||||
UPLOADER_URL: /uploader
|
||||
#ADMIN_URL: /admin
|
||||
ADMIN_URL: /admin
|
||||
MAPS_URL: /maps
|
||||
ICON_URL: /icon
|
||||
STARTUP_COMMAND_1: ./templater.sh
|
||||
STARTUP_COMMAND_2: yarn install
|
||||
TURN_SERVER: "turn:localhost:3478,turns:localhost:5349"
|
||||
@ -41,7 +40,6 @@ services:
|
||||
TURN_USER: ""
|
||||
TURN_PASSWORD: ""
|
||||
START_ROOM_URL: "$START_ROOM_URL"
|
||||
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
||||
command: yarn run start
|
||||
volumes:
|
||||
- ./front:/usr/src/app
|
||||
@ -62,8 +60,6 @@ services:
|
||||
environment:
|
||||
DEBUG: "*"
|
||||
STARTUP_COMMAND_1: yarn install
|
||||
# wait for files generated by "messages" container to exists
|
||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||
SECRET_KEY: yourSecretKey
|
||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
||||
@ -74,9 +70,6 @@ services:
|
||||
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
||||
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
||||
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
||||
OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL
|
||||
OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER
|
||||
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
|
||||
volumes:
|
||||
- ./pusher:/usr/src/app
|
||||
labels:
|
||||
@ -124,8 +117,6 @@ services:
|
||||
environment:
|
||||
DEBUG: "*"
|
||||
STARTUP_COMMAND_1: yarn install
|
||||
# wait for files generated by "messages" container to exists
|
||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||
SECRET_KEY: yourSecretKey
|
||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||
ALLOW_ARTILLERY: "true"
|
||||
@ -186,20 +177,6 @@ services:
|
||||
redis:
|
||||
image: redis:6
|
||||
|
||||
icon:
|
||||
image: matthiasluedtke/iconserver:v3.13.0
|
||||
labels:
|
||||
- "traefik.http.middlewares.strip-icon-prefix.stripprefix.prefixes=/icon"
|
||||
- "traefik.http.routers.icon.rule=PathPrefix(`/icon`)"
|
||||
- "traefik.http.routers.icon.middlewares=strip-icon-prefix@docker"
|
||||
- "traefik.http.routers.icon.entryPoints=web"
|
||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.icon-ssl.rule=PathPrefix(`/icon`)"
|
||||
- "traefik.http.routers.icon-ssl.middlewares=strip-icon-prefix@docker"
|
||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||
- "traefik.http.routers.icon-ssl.tls=true"
|
||||
- "traefik.http.routers.icon-ssl.service=icon"
|
||||
|
||||
# coturn:
|
||||
# image: coturn/coturn:4.5.2
|
||||
# command:
|
||||
|
@ -1,12 +0,0 @@
|
||||
version: "3"
|
||||
services:
|
||||
testcafe:
|
||||
image: testcafe/testcafe:1.17.1
|
||||
working_dir: /tests
|
||||
environment:
|
||||
BROWSER: "chromium --use-fake-device-for-media-stream"
|
||||
volumes:
|
||||
- ./tests:/tests
|
||||
- ./maps:/maps
|
||||
# security_opt:
|
||||
# - seccomp:unconfined
|
@ -17,12 +17,6 @@ services:
|
||||
- front
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
- 'play.workadventure.localhost'
|
||||
- 'pusher.workadventure.localhost'
|
||||
- 'maps.workadventure.localhost'
|
||||
|
||||
front:
|
||||
image: thecodingmachine/nodejs:14
|
||||
@ -34,8 +28,7 @@ services:
|
||||
NODE_ENV: development
|
||||
PUSHER_URL: //pusher.workadventure.localhost
|
||||
UPLOADER_URL: //uploader.workadventure.localhost
|
||||
#ADMIN_URL: //workadventure.localhost
|
||||
ICON_URL: //icon.workadventure.localhost
|
||||
ADMIN_URL: //workadventure.localhost
|
||||
STARTUP_COMMAND_1: ./templater.sh
|
||||
STARTUP_COMMAND_2: yarn install
|
||||
STUN_SERVER: "stun:stun.l.google.com:19302"
|
||||
@ -49,8 +42,6 @@ services:
|
||||
START_ROOM_URL: "$START_ROOM_URL"
|
||||
MAX_PER_GROUP: "$MAX_PER_GROUP"
|
||||
MAX_USERNAME_LENGTH: "$MAX_USERNAME_LENGTH"
|
||||
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
||||
OPID_LOGIN_SCREEN_PROVIDER: "$OPID_LOGIN_SCREEN_PROVIDER"
|
||||
command: yarn run start
|
||||
volumes:
|
||||
- ./front:/usr/src/app
|
||||
@ -69,8 +60,6 @@ services:
|
||||
environment:
|
||||
DEBUG: "socket:*"
|
||||
STARTUP_COMMAND_1: yarn install
|
||||
# wait for files generated by "messages" container to exists
|
||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||
SECRET_KEY: yourSecretKey
|
||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
||||
@ -81,9 +70,6 @@ services:
|
||||
OPID_CLIENT_ID: $OPID_CLIENT_ID
|
||||
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
|
||||
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
|
||||
OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL
|
||||
OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER
|
||||
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
|
||||
volumes:
|
||||
- ./pusher:/usr/src/app
|
||||
labels:
|
||||
@ -125,8 +111,6 @@ services:
|
||||
environment:
|
||||
DEBUG: "*"
|
||||
STARTUP_COMMAND_1: yarn install
|
||||
# wait for files generated by "messages" container to exists
|
||||
STARTUP_COMMAND_2: while [ ! -f /usr/src/app/src/Messages/generated/messages_pb.js ]; do sleep 1; done
|
||||
SECRET_KEY: yourSecretKey
|
||||
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||
ALLOW_ARTILLERY: "true"
|
||||
@ -137,7 +121,6 @@ services:
|
||||
MAX_PER_GROUP: "MAX_PER_GROUP"
|
||||
REDIS_HOST: redis
|
||||
NODE_ENV: development
|
||||
STORE_VARIABLES_FOR_LOCAL_MAPS: "true"
|
||||
volumes:
|
||||
- ./back:/usr/src/app
|
||||
labels:
|
||||
@ -194,17 +177,6 @@ services:
|
||||
- "traefik.http.routers.redisinsight-ssl.tls=true"
|
||||
- "traefik.http.routers.redisinsight-ssl.service=redisinsight"
|
||||
|
||||
icon:
|
||||
image: matthiasluedtke/iconserver:v3.13.0
|
||||
labels:
|
||||
- "traefik.http.routers.icon.rule=Host(`icon.workadventure.localhost`)"
|
||||
- "traefik.http.routers.icon.entryPoints=web"
|
||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||
- "traefik.http.routers.icon-ssl.rule=Host(`icon.workadventure.localhost`)"
|
||||
- "traefik.http.routers.icon-ssl.entryPoints=websecure"
|
||||
- "traefik.http.routers.icon-ssl.tls=true"
|
||||
- "traefik.http.routers.icon-ssl.service=icon"
|
||||
|
||||
# coturn:
|
||||
# image: coturn/coturn:4.5.2
|
||||
# command:
|
||||
|
@ -7,14 +7,14 @@ not overwrite existing ones) and click on the animation editor:
|
||||
|
||||
|
||||
<div class="px-5 card rounded d-inline-block">
|
||||
<img class="document-img" src="images/anims/camera.png" alt="" />
|
||||
<img class="document-img" src="https://workadventu.re/img/docs/anims/camera.png" alt="" />
|
||||
</div>
|
||||
|
||||
You can now add all tiles that should be part of the animation via drag and drop to the "playlist" and adjust the frame duration:
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img class="figure-img img-fluid rounded" src="images/anims/animation_editor.png" alt="" />
|
||||
<img class="figure-img img-fluid rounded" src="https://workadventu.re/img/docs/anims/animation_editor.png" alt="" />
|
||||
<figcaption class="figure-caption">The tile animation editor</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
@ -24,7 +24,7 @@ You can preview animations directly in Tiled, using the "Show tile animations" o
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img class="figure-img img-fluid rounded" src="images/anims/settings_show_animations.png" alt="" />
|
||||
<img class="figure-img img-fluid rounded" src="https://workadventu.re/img/docs/anims/settings_show_animations.png" alt="" />
|
||||
<figcaption class="figure-caption">The Show Tile Animations option</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@ When controls are disabled, the user cannot move anymore using keyboard input. T
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
WA.room.onEnterLayer('myZone').subscribe(() => {
|
||||
WA.room.onEnterZone('myZone', () => {
|
||||
WA.controls.disablePlayerControls();
|
||||
WA.ui.openPopup("popupRectangle", 'This is an imporant message!', [{
|
||||
label: "Got it!",
|
||||
@ -25,5 +25,5 @@ WA.room.onEnterLayer('myZone').subscribe(() => {
|
||||
popup.close();
|
||||
}
|
||||
}]);
|
||||
})
|
||||
});
|
||||
```
|
||||
|
@ -3,21 +3,18 @@
|
||||
|
||||
The list of functions below is **deprecated**. You should not use those but. use the replacement functions.
|
||||
|
||||
- Method `WA.sendChatMessage` is deprecated. It has been renamed to [`WA.chat.sendChatMessage`](api-chat.md#sending-a-message-in-the-chat).
|
||||
- Method `WA.disablePlayerControls` is deprecated. It has been renamed to [`WA.controls.disablePlayerControls`](api-controls.md#disabling--restoring-controls).
|
||||
- Method `WA.restorePlayerControls` is deprecated. It has been renamed to [`WA.controls.restorePlayerControls`](api-controls.md#disabling--restoring-controls).
|
||||
- Method `WA.sendChatMessage` is deprecated. It has been renamed to `WA.chat.sendChatMessage`.
|
||||
- Method `WA.disablePlayerControls` is deprecated. It has been renamed to `WA.controls.disablePlayerControls`.
|
||||
- Method `WA.restorePlayerControls` is deprecated. It has been renamed to `WA.controls.restorePlayerControls`.
|
||||
- Method `WA.displayBubble` is deprecated. It has been renamed to `WA.ui.displayBubble`.
|
||||
- Method `WA.removeBubble` is deprecated. It has been renamed to `WA.ui.removeBubble`.
|
||||
- Method `WA.openTab` is deprecated. It has been renamed to [`WA.nav.openTab`](api-nav.md#opening-a-web-page-in-a-new-tab).
|
||||
- Method `WA.loadSound` is deprecated. It has been renamed to [`WA.sound.loadSound`](api-sound.md#load-a-sound-from-an-url).
|
||||
- Method `WA.goToPage` is deprecated. It has been renamed to [`WA.nav.goToPage`](api-nav.md#opening-a-web-page-in-the-current-tab).
|
||||
- Method `WA.goToRoom` is deprecated. It has been renamed to [`WA.nav.goToRoom`](api-nav.md#going-to-a-different-map-from-the-script).
|
||||
- Method `WA.openCoWebSite` is deprecated. It has been renamed to [`WA.nav.openCoWebSite`](api-nav.md#openingclosing-web-page-in-co-websites).
|
||||
- Method `WA.closeCoWebSite` is deprecated. It has been remove and [replace by a function close](api-nav.md#openingclosing-web-page-in-co-websites).
|
||||
- Method `WA.openPopup` is deprecated. It has been renamed to [`WA.ui.openPopup`](api-ui.md#opening-a-popup).
|
||||
- Method `WA.onChatMessage` is deprecated. It has been renamed to [`WA.chat.onChatMessage`](api-chat.md#listening-to-messages-from-the-chat).
|
||||
- Method `WA.onEnterZone` is deprecated. It has been renamed to [`WA.room.onEnterZone`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||
- Method `WA.onLeaveZone` is deprecated. It has been renamed to [`WA.room.onLeaveZone`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||
- Method `WA.ui.registerMenuCommand` parameter `callback` is deprecated. Use [`WA.ui.registerMenuCommand(commandDescriptor: string, options: MenuOptions)`](api-ui.md#add-custom-menu).
|
||||
- Method `WA.room.onEnterZone` is deprecated. Use instead [`WA.room.onEnterLayer`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||
- Method `WA.room.onLeaveZone` is deprecated. Use instead [`WA.room.onLeaveLayer`](api-room.md#detecting-when-the-user-entersleaves-a-layer).
|
||||
- Method `WA.openTab` is deprecated. It has been renamed to `WA.nav.openTab`.
|
||||
- Method `WA.loadSound` is deprecated. It has been renamed to `WA.sound.loadSound`.
|
||||
- Method `WA.goToPage` is deprecated. It has been renamed to `WA.nav.goToPage`.
|
||||
- Method `WA.goToRoom` is deprecated. It has been renamed to `WA.nav.goToRoom`.
|
||||
- Method `WA.openCoWebSite` is deprecated. It has been renamed to `WA.nav.openCoWebSite`.
|
||||
- Method `WA.closeCoWebSite` is deprecated. It has been renamed to `WA.nav.closeCoWebSite`.
|
||||
- Method `WA.openPopup` is deprecated. It has been renamed to `WA.ui.openPopup`.
|
||||
- Method `WA.onChatMessage` is deprecated. It has been renamed to `WA.chat.onChatMessage`.
|
||||
- Method `WA.onEnterZone` is deprecated. It has been renamed to `WA.room.onEnterZone`.
|
||||
- Method `WA.onLeaveZone` is deprecated. It has been renamed to `WA.room.onLeaveZone`.
|
||||
|
@ -49,34 +49,19 @@ WA.nav.goToRoom('../otherMap/map.json');
|
||||
WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
||||
```
|
||||
|
||||
### Opening/closing web page in Co-Websites
|
||||
### Opening/closing a web page in an iFrame
|
||||
|
||||
```
|
||||
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number = 0): Promise<CoWebsite>
|
||||
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = ""): void
|
||||
WA.nav.closeCoWebSite(): void
|
||||
```
|
||||
|
||||
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow), position in whitch slot the web page will be open.
|
||||
You can have only 5 co-wbesites open simultaneously.
|
||||
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow).
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/');
|
||||
const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 1);
|
||||
WA.nav.openCoWebSite('https://www.wikipedia.org/');
|
||||
// ...
|
||||
coWebsite.close();
|
||||
```
|
||||
|
||||
### Get all Co-Websites
|
||||
|
||||
```
|
||||
WA.nav.getCoWebSites(): Promise<CoWebsite[]>
|
||||
```
|
||||
|
||||
Get all opened co-websites with their ids and positions.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const coWebsites = await WA.nav.getCowebSites();
|
||||
WA.nav.closeCoWebSite();
|
||||
```
|
||||
|
@ -68,9 +68,7 @@ The event has the following attributes :
|
||||
* **moving (boolean):** **true** when the current player is moving, **false** otherwise.
|
||||
* **direction (string):** **"right"** | **"left"** | **"down"** | **"top"** the direction where the current player is moving.
|
||||
* **x (number):** coordinate X of the current player.
|
||||
* **y (number):** coordinate Y of the current player.
|
||||
* **oldX (number):** old coordinate X of the current player.
|
||||
* **oldY (number):** old coordinate Y of the current player.
|
||||
* **y (number):** coordinate Y of the current player.
|
||||
|
||||
**callback:** the function that will be called when the current player is moving. It contains the event.
|
||||
|
||||
|
@ -7,7 +7,7 @@ If you use group layers in your map, to reference a layer in a group you will ne
|
||||
Example :
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="images/groupLayer.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/groupLayer.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -17,27 +17,35 @@ The name of the layers of this map are :
|
||||
* `bottom/build/carpet`
|
||||
* `wall`
|
||||
|
||||
### Detecting when the user enters/leaves a layer
|
||||
### Detecting when the user enters/leaves a zone
|
||||
|
||||
```
|
||||
WA.room.onEnterLayer(name: string): Subscription
|
||||
WA.room.onLeaveLayer(name: string): Subscription
|
||||
WA.room.onEnterZone(name: string, callback: () => void): void
|
||||
WA.room.onLeaveZone(name: string, callback: () => void): void
|
||||
```
|
||||
|
||||
Listens to the position of the current user. The event is triggered when the user enters or leaves a given layer.
|
||||
Listens to the position of the current user. The event is triggered when the user enters or leaves a given zone. The name of the zone is stored in the map, on a dedicated layer with the `zone` property.
|
||||
|
||||
* **name**: the name of the layer who as defined in Tiled.
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="https://workadventu.re/img/docs/trigger_event.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The `zone` property, applied on a layer</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
* **name**: the name of the zone, as defined in the `zone` property.
|
||||
* **callback**: the function that will be called when a user enters or leaves the zone.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
WA.room.onEnterLayer('myLayer').subscribe(() => {
|
||||
WA.room.onEnterZone('myZone', () => {
|
||||
WA.chat.sendChatMessage("Hello!", 'Mr Robot');
|
||||
});
|
||||
})
|
||||
|
||||
WA.room.onLeaveLayer('myLayer').subscribe(() => {
|
||||
WA.room.onLeaveZone('myZone', () => {
|
||||
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
### Show / Hide a layer
|
||||
@ -63,7 +71,7 @@ WA.room.setProperty(layerName : string, propertyName : string, propertyValue : s
|
||||
|
||||
Set the value of the `propertyName` property of the layer `layerName` at `propertyValue`. If the property doesn't exist, create the property `propertyName` and set the value of the property at `propertyValue`.
|
||||
|
||||
Note :
|
||||
Note :
|
||||
To unset a property from a layer, use `setProperty` with `propertyValue` set to `undefined`.
|
||||
|
||||
Example :
|
||||
@ -123,7 +131,7 @@ console.log("Map generated with Tiled version ", map.tiledversion);
|
||||
|
||||
Check the [Tiled documentation to learn more about the format of the JSON map](https://doc.mapeditor.org/en/stable/reference/json-map-format/).
|
||||
|
||||
### Changing tiles
|
||||
### Changing tiles
|
||||
```
|
||||
WA.room.setTiles(tiles: TileDescriptor[]): void
|
||||
```
|
||||
@ -132,11 +140,11 @@ Replace the tile at the `x` and `y` coordinates in the layer named `layer` by th
|
||||
If `tile` is a string, it's not the id of the tile but the value of the property `name`.
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="images/nameIndexProperty.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/nameIndexProperty.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`TileDescriptor` has the following attributes :
|
||||
`TileDescriptor` has the following attributes :
|
||||
* **x (number) :** The coordinate x of the tile that you want to replace.
|
||||
* **y (number) :** The coordinate y of the tile that you want to replace.
|
||||
* **tile (number | string) :** The id of the tile that will be placed in the map.
|
||||
@ -146,7 +154,7 @@ If `tile` is a string, it's not the id of the tile but the value of the property
|
||||
|
||||
Note: If you want to unset a tile, use `setTiles` with `tile` set to `null`.
|
||||
|
||||
Example :
|
||||
Example :
|
||||
```javascript
|
||||
WA.room.setTiles([
|
||||
{x: 6, y: 4, tile: 'blue', layer: 'setTiles'},
|
||||
@ -168,102 +176,4 @@ You can create a tileset file in Tile Editor.
|
||||
WA.room.loadTileset("Assets/Tileset.json").then((firstId) => {
|
||||
WA.room.setTiles([{x: 4, y: 4, tile: firstId, layer: 'bottom'}]);
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
## Embedding websites in a map
|
||||
|
||||
You can use the scripting API to embed websites in a map, or to edit websites that are already embedded (using the ["website" objects](website-in-map.md)).
|
||||
|
||||
### Getting an instance of a website already embedded in the map
|
||||
|
||||
```
|
||||
WA.room.website.get(objectName: string): Promise<EmbeddedWebsite>
|
||||
```
|
||||
|
||||
You can get an instance of an embedded website by using the `WA.room.website.get()` method.
|
||||
It returns a promise of an `EmbeddedWebsite` instance.
|
||||
|
||||
```javascript
|
||||
// Get an existing website object where 'my_website' is the name of the object (on any layer object of the map)
|
||||
const website = await WA.room.website.get('my_website');
|
||||
website.url = 'https://example.com';
|
||||
website.visible = true;
|
||||
```
|
||||
|
||||
|
||||
### Adding a new website in a map
|
||||
|
||||
```
|
||||
WA.room.website.create(website: CreateEmbeddedWebsiteEvent): EmbeddedWebsite
|
||||
|
||||
interface CreateEmbeddedWebsiteEvent {
|
||||
name: string; // A unique name for this iframe
|
||||
url: string; // The URL the iframe points to.
|
||||
position: {
|
||||
x: number, // In pixels, relative to the map coordinates
|
||||
y: number, // In pixels, relative to the map coordinates
|
||||
width: number, // In pixels, sensitive to zoom level
|
||||
height: number, // In pixels, sensitive to zoom level
|
||||
},
|
||||
visible?: boolean, // Whether to display the iframe or not
|
||||
allowApi?: boolean, // Whether the scripting API should be available to the iframe
|
||||
allow?: string, // The list of feature policies allowed
|
||||
}
|
||||
```
|
||||
|
||||
You can create an instance of an embedded website by using the `WA.room.website.create()` method.
|
||||
It returns an `EmbeddedWebsite` instance.
|
||||
|
||||
```javascript
|
||||
// Create a new website object
|
||||
const website = WA.room.website.create({
|
||||
name: "my_website",
|
||||
url: "https://example.com",
|
||||
position: {
|
||||
x: 64,
|
||||
y: 128,
|
||||
width: 320,
|
||||
height: 240,
|
||||
},
|
||||
visible: true,
|
||||
allowApi: true,
|
||||
allow: "fullscreen",
|
||||
});
|
||||
```
|
||||
|
||||
### Deleting a website from a map
|
||||
|
||||
```
|
||||
WA.room.website.delete(name: string): Promise<void>
|
||||
```
|
||||
|
||||
Use `WA.room.website.delete` to completely remove an embedded website from your map.
|
||||
|
||||
|
||||
### The EmbeddedWebsite class
|
||||
|
||||
Instances of the `EmbeddedWebsite` class represent the website displayed on the map.
|
||||
|
||||
```typescript
|
||||
class EmbeddedWebsite {
|
||||
readonly name: string;
|
||||
url: string;
|
||||
visible: boolean;
|
||||
allow: string;
|
||||
allowApi: boolean;
|
||||
x: number; // In pixels, relative to the map coordinates
|
||||
y: number; // In pixels, relative to the map coordinates
|
||||
width: number; // In pixels, sensitive to zoom level
|
||||
height: number; // In pixels, sensitive to zoom level
|
||||
}
|
||||
```
|
||||
|
||||
When you modify a property of an `EmbeddedWebsite` instance, the iframe is automatically modified in the map.
|
||||
|
||||
|
||||
{.alert.alert-warning}
|
||||
The websites you add/edit/delete via the scripting API are only shown locally. If you want them
|
||||
to be displayed for every player, you can use [variables](api-start.md) to share a common state
|
||||
between all users.
|
||||
|
||||
```
|
@ -9,12 +9,11 @@ Moreover, `WA.state` functions can be used to persist this state across reloads.
|
||||
```
|
||||
WA.state.saveVariable(key : string, data : unknown): void
|
||||
WA.state.loadVariable(key : string) : unknown
|
||||
WA.state.hasVariable(key : string) : boolean
|
||||
WA.state.onVariableChange(key : string).subscribe((data: unknown) => {}) : Subscription
|
||||
WA.state.[any property]: unknown
|
||||
```
|
||||
|
||||
These methods and properties can be used to save, load and track changes in [variables related to the current room](variables.md).
|
||||
These methods and properties can be used to save, load and track changes in variables related to the current room.
|
||||
|
||||
Variables stored in `WA.state` can be any value that is serializable in JSON.
|
||||
|
||||
@ -63,11 +62,44 @@ that you get the expected type).
|
||||
For security reasons, the list of variables you are allowed to access and modify is **restricted** (otherwise, anyone on your map could set any data).
|
||||
Variables storage is subject to an authorization process. Read below to learn more.
|
||||
|
||||
## Defining a variable
|
||||
### Declaring allowed keys
|
||||
|
||||
Out of the box, you cannot edit *any* variable. Variables MUST be declared in the map.
|
||||
In order to declare allowed keys related to a room, you need to add **objects** in an "object layer" of the map.
|
||||
|
||||
Each object will represent a variable.
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="https://workadventu.re/img/docs/object_variable.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
The name of the variable is the name of the object.
|
||||
The object **type** MUST be **variable**.
|
||||
|
||||
You can set a default value for the object in the `default` property.
|
||||
|
||||
### Persisting variables state
|
||||
|
||||
Use the `persist` property to save the state of the variable in database. If `persist` is false, the variable will stay
|
||||
in the memory of the WorkAdventure servers but will be wiped out of the memory as soon as the room is empty (or if the
|
||||
server restarts).
|
||||
|
||||
{.alert.alert-info}
|
||||
Do not use `persist` for highly dynamic values that have a short life spawn.
|
||||
|
||||
### Managing access rights to variables
|
||||
|
||||
With `readableBy` and `writableBy`, you control who can read of write in this variable. The property accepts a string
|
||||
representing a "tag". Anyone having this "tag" can read/write in the variable.
|
||||
|
||||
{.alert.alert-warning}
|
||||
`readableBy` and `writableBy` are specific to the "online" version of WorkAdventure because the notion of tags
|
||||
is not available unless you have an "admin" server (that is not part of the self-hosted version of WorkAdventure).
|
||||
|
||||
Finally, the `jsonSchema` property can contain [a complete JSON schema](https://json-schema.org/) to validate the content of the variable.
|
||||
Trying to set a variable to a value that is not compatible with the schema will fail.
|
||||
|
||||
Check the [dedicated variables page](variables.md) to learn how to declare a variable in a map.
|
||||
|
||||
## Tracking variables changes
|
||||
|
||||
|
@ -9,10 +9,10 @@ You can position this popup by using a "rectangle" object in Tiled that you will
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="images/screen_popup_tiled.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/screen_popup_tiled.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<img src="images/screen_popup_in_game.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/screen_popup_in_game.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,7 +49,7 @@ Example:
|
||||
let helloWorldPopup;
|
||||
|
||||
// Open the popup when we enter a given zone
|
||||
helloWorldPopup = WA.room.onEnterLayer("myZone").subscribe(() => {
|
||||
helloWorldPopup = WA.room.onEnterZone('myZone', () => {
|
||||
WA.ui.openPopup("popupRectangle", 'Hello world!', [{
|
||||
label: "Close",
|
||||
className: "primary",
|
||||
@ -57,108 +57,33 @@ helloWorldPopup = WA.room.onEnterLayer("myZone").subscribe(() => {
|
||||
// Close the popup when the "Close" button is pressed.
|
||||
popup.close();
|
||||
}
|
||||
}]);
|
||||
});
|
||||
});
|
||||
}]);
|
||||
|
||||
// Close the popup when we leave the zone.
|
||||
WA.room.onLeaveLayer("myZone").subscribe(() => {
|
||||
WA.room.onLeaveZone('myZone', () => {
|
||||
helloWorldPopup.close();
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Add custom menu
|
||||
|
||||
```typescript
|
||||
WA.ui.registerMenuCommand(menuCommand: string, callback: (menuCommand: string) => void): void
|
||||
```
|
||||
WA.ui.registerMenuCommand(commandDescriptor: string, options: MenuOptions): Menu
|
||||
```
|
||||
Add a custom menu item containing the text `commandDescriptor` in the navbar of the menu.
|
||||
`options` attribute accepts an object with three properties :
|
||||
- `callback : (commandDescriptor: string) => void` : A click on the custom menu will trigger the `callback`.
|
||||
- `iframe: string` : A click on the custom menu will open the `iframe` inside the menu.
|
||||
- `allowApi?: boolean` : Allow the iframe of the custom menu to use the Scripting API.
|
||||
|
||||
Important : `options` accepts only `callback` or `iframe` not both.
|
||||
|
||||
Add a custom menu item containing the text `commandDescriptor` in the main menu. A click on the menu will trigger the `callback`.
|
||||
Custom menu exist only until the map is unloaded, or you leave the iframe zone of the script.
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="images/custom-menu-navbar.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<img src="images/custom-menu-iframe.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const menu = WA.ui.registerMenuCommand('menu test',
|
||||
{
|
||||
callback: () => {
|
||||
WA.chat.sendChatMessage('test');
|
||||
}
|
||||
})
|
||||
|
||||
// Some time later, if you want to remove the menu:
|
||||
menu.remove();
|
||||
```
|
||||
|
||||
Please note that `registerMenuCommand` returns an object of the `Menu` class.
|
||||
|
||||
The `Menu` class contains a single method: `remove(): void`. This will obviously remove the menu when called.
|
||||
|
||||
```javascript
|
||||
class Menu {
|
||||
/**
|
||||
* Remove the menu
|
||||
*/
|
||||
remove() {};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Awaiting User Confirmation (with space bar)
|
||||
|
||||
```
|
||||
WA.ui.displayActionMessage({
|
||||
message: string,
|
||||
callback: () => void,
|
||||
type?: "message"|"warning",
|
||||
}): ActionMessage
|
||||
```
|
||||
|
||||
Displays a message at the bottom of the screen (that will disappear when space bar is pressed).
|
||||
|
||||
<div class="col">
|
||||
<img src="images/trigger_message.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
const triggerMessage = WA.ui.displayActionMessage({
|
||||
message: "press 'space' to confirm",
|
||||
callback: () => {
|
||||
WA.chat.sendChatMessage("confirmed", "trigger message logic")
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
// later
|
||||
triggerMessage.remove();
|
||||
}, 1000)
|
||||
WA.ui.registerMenuCommand("test", () => {
|
||||
WA.chat.sendChatMessage("test clicked", "menu cmd")
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
Please note that `displayActionMessage` returns an object of the `ActionMessage` class.
|
||||
|
||||
The `ActionMessage` class contains a single method: `remove(): Promise<void>`. This will obviously remove the message when called.
|
||||
|
||||
```javascript
|
||||
class ActionMessage {
|
||||
/**
|
||||
* Hides the message
|
||||
*/
|
||||
remove() {};
|
||||
}
|
||||
```
|
||||
<div class="col">
|
||||
<img src="https://workadventu.re/img/docs/menu-command.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
@ -1,67 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Entries and exits
|
||||
|
||||
[Building your map - Defined entries and exits](https://www.youtube.com/watch?v=MuhVgu8H7U0)
|
||||
|
||||
## Defining a default entry point
|
||||
|
||||
In order to define a default start position, you MUST create a layer named "`start`" on your map. This layer MUST contain at least one tile. The players will start on the tile of this layer. If the layer contains many tiles, the players will start randomly on one of those tiles.
|
||||
|
||||

|
||||
|
||||
In the screenshot above, the start layer is made of the 2 white tiles. These tiles are not visible to the end user because they are hidden below the "bottom" layer that displays the floor of the map.
|
||||
|
||||
{.alert.alert-info}
|
||||
**Pro tip**: if you expect many people to connect to your map at the same time (for instance, if you are organizing a big event), consider making a large start zone. This way, users will not all appear at the same position and will not pop randomly in a chat with someone connecting at the same moment.
|
||||
|
||||
## Defining exits
|
||||
|
||||
In order to place an exit on your scene that leads to another scene:
|
||||
|
||||
* You must create a specific layer. When a character reaches ANY tile of that layer, it will exit the scene.
|
||||
* In layer properties, you MUST add "`exitUrl`" property. It represents the URL of the next scene. You can put relative or absolute URLs.
|
||||
* If you want to have multiple exits, you can create many layers. Each layer has a different key `exitUrl` and has tiles that represent exits to another scene.
|
||||
|
||||

|
||||
|
||||
{.alert.alert-warning}
|
||||
**Note:** in older releases of WorkAdventure, you could link to a map file directly using properties `exitSceneUrl` and `exitInstance`. Those properties are now **deprecated**. Use "`exitUrl`" instead.
|
||||
|
||||
## Understanding map URLs in WorkAdventure
|
||||
|
||||
There are 2 kinds of URLs in WorkAdventure:
|
||||
|
||||
* Public URLs are in the form `https://play.workadventu.re/_/[instance]/[server]/[path to map]`
|
||||
* Private URLs (used in paid accounts) are in the form `https://play.workadventu.re/@/[organization]/[world]/[map]`
|
||||
|
||||
Assuming your JSON map is hosted at "`https://example.com/my/map.json`", then you can browse your map at "`https://play.workadventu.re/_/global/example.com/my/map.json`". Here, "global" is a name of an "instance" of your map. You can put anything instead of "global" here. People on the same instance of the map can see each others. If 2 users use 2 different instances, they are on the same map, but in 2 parallel universes. They cannot see each other.
|
||||
|
||||
## Defining several entry points
|
||||
|
||||
Often your map will have several exits, and therefore, several entry points. For instance, if there is an exit by a door that leads to the garden map, when you come back from the garden you expect to come back by the same door. Therefore, a map can have several entry points. Those entry points are "named" (they have a name).
|
||||
|
||||
In order to create a named entry point:
|
||||
|
||||
You can create a new layer for your entry point or use an existing layer with named tiles.
|
||||
|
||||
* If you don't use the layer named "`start`", you MUST add a boolean "`startLayer`" property to the layer properties. It MUST be set to true.
|
||||
* If you use this method, when a character enters the map by this entry point, it will enter randomly on ANY tile of that layer. The name of the entry point is the name of that layer.
|
||||
|
||||

|
||||
|
||||
You can also use the tiles properties to create entry point.
|
||||
|
||||
* To do that, you will need to have a layer named "`start`" or with the "`startLayer`" property. Then you MUST add a string "`start`" property to a tile than you use in that layer. The name of the entry point is the value that property.
|
||||
* If you use this method, when a character enters the map by this entry point, it will enter on ANY tile of the same kind in that layer.
|
||||
|
||||

|
||||
|
||||
Notes :
|
||||
|
||||
* Two tiles with a string "start" property with different value can be in the same layer of entries.
|
||||
* A tile with a string "start" property that is not in a layer of entries won't usable as an entry point.
|
||||
|
||||
How to use entry point :
|
||||
|
||||
* To enter via this entry point, simply add a hash with the entry point name to the URL ("#[_entryPointName_]"). For instance: "`https://workadventu.re/_/global/mymap.com/path/map.json#my-entry-point`".
|
||||
* You can of course use the "#" notation in an exit scene URL (so an exit scene URL will point to a given entry scene URL)
|
@ -1,25 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Hosting your map
|
||||
|
||||
The [Getting Started](.) page proposes to use a "starter kit" that is relying on GitHub pages for hosting the map. This is a fairly good solution as GitHub pages offers a free and performant hosting.
|
||||
|
||||
But using GitHub pages is not necessary. You can host your maps on any webserver.
|
||||
|
||||
{.alert.alert-warning}
|
||||
If you decide to host your maps on your own webserver, you must **configure CORS headers** in your browser to allow access from WorkAdventure.
|
||||
|
||||
## Configuring CORS headers
|
||||
|
||||
CORS headers ([Cross Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)) are useful when a website want to make some resources accessible to another website. This is exactly what we want to do. We want the map you are designing to be accessible from the WorkAdventure domain (`play.workadventu.re`).
|
||||
|
||||
### Enabling CORS for Apache
|
||||
|
||||
In order to enable CORS in your Apache configuration, you will need to ensure the `headers` module is enabled.
|
||||
|
||||
In your Apache configuration file, simply add the following line inside either the `<Directory>`, `<Location>`, `<Files>` or `<VirtualHost>` sections, or within a `.htaccess` file.
|
||||
|
||||
Header set Access-Control-Allow-Origin "*"
|
||||
|
||||
### Enabling CORS on another webserver
|
||||
|
||||
Check out [enable-cors.org](https://enable-cors.org/server.html) which has detailed instructions on how to enable CORS on many different webservers.
|
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 290 KiB |
Before Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 191 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 401 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 95 KiB |
@ -1,128 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Create your map
|
||||
|
||||
## Tools you will need
|
||||
|
||||
In order to build your own map for WorkAdventure, you need:
|
||||
|
||||
* the [Tiled editor](https://www.mapeditor.org/) software
|
||||
* "tiles" (i.e. images) to create your map
|
||||
* a web-server to serve your map
|
||||
|
||||
WorkAdventure comes with a "map starter kit" that we recommend using to start designing your map quickly. It contains **a good default tileset** for building an office and it proposes to **use Github static pages as a web-server** which is both free and performant. It also comes with a local webserver for testing purpose and with Typescript support (if you are looking to use the [map scripting API]({{url('/map-building/scripting')}}).
|
||||
|
||||
{.alert.alert-info}
|
||||
If you are looking to host your maps on your own webserver, be sure to read the [Self-hosting your map](hosting.md) guide.
|
||||
|
||||
[Building your map - Create your map](https://www.youtube.com/watch?v=lu1IZgBJJD4)
|
||||
|
||||
## Getting started
|
||||
|
||||
Start by [creating a GitHub account](https://github.com/join) if you don't already have one.
|
||||
|
||||
Then, go to the [Github map starter kit repository page](https://github.com/thecodingmachine/workadventure-map-starter-kit) and click the **"Use this template"** button.
|
||||
|
||||
<figure class="figure my-5">
|
||||
<img src="images/use_this_template.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The "Use this template" button</figcaption>
|
||||
</figure>
|
||||
|
||||
You will be prompted to enter a repository name for your map.
|
||||
|
||||
<figure class="figure my-5">
|
||||
<img src="images/create_repo.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The "create a new repository" page</figcaption>
|
||||
</figure>
|
||||
|
||||
**Make sure to check the "Include all branches" checkbox, otherwise the Github Pages deployment process will not be setup automatically.**
|
||||
|
||||
If you miss that step, don't worry, you can always fix that by clicking on the **Settings tab** of your repository and scroll down to the **GitHub Pages** section. Then select the **gh-pages** branch. It might already be selected, but please be sure to click on it nonetheless (otherwise GitHub will not enable GitHub pages).
|
||||
|
||||
{.alert.alert-info}
|
||||
If you only see a "master" branch and if the **gh-pages** branch does not appear here, simply wait a few minutes and refresh your page. When you created the project, Github Actions triggered a job that is in charge of creating the **gh-pages** branch. Maybe the job is not finished yet.
|
||||
|
||||
<figure class="figure my-5">
|
||||
<img src="images/github_pages.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The GitHub pages configuration section</figcaption>
|
||||
</figure>
|
||||
|
||||
Wait a few minutes... Github will deploy a new website with the content of the repository. The address of the website is visible in the "GitHub Pages" section.
|
||||
|
||||
<figure class="figure my-5">
|
||||
<img src="images/website_address.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">Your website is ready!</figcaption>
|
||||
</figure>
|
||||
|
||||
Click on the link. You should be redirected directly to WorkAdventure, on your map!
|
||||
|
||||
## Customizing your map
|
||||
|
||||
Your map is now up and online, but this is still the demo map from the starter kit. You need to customize it.
|
||||
|
||||
### Cloning the map
|
||||
|
||||
Start by cloning the map. If you are used to Git and GitHub, simply clone the map to your computer using your preferred tool and [jump to the next chapter](#loading-the-map-in-tiled).
|
||||
|
||||
If you are new to Git, cloning the map means downloading the map to your computer. To do this, you will need Git, or a Git compatible tool. Our advice is to use [GitHub Desktop](https://desktop.github.com/). We recommend you take some time mastering the notion of pull / commit / push as this will make uploading your maps really easier.
|
||||
|
||||
As an (easier) alternative, you can simply use the "Export" button to download the code of the map in a big Zip file. When you want to upload your work again, you will simply drag'n'drop your files in the GitHub website.
|
||||
|
||||
### Loading the map in Tiled
|
||||
|
||||
The sample map is in the file `map.json`. You can load this file in [Tiled](https://www.mapeditor.org/).
|
||||
|
||||
Now, it's up to you to edit the map and write your own map.
|
||||
|
||||
Some resources regarding Tiled:
|
||||
|
||||
* [Tiled documentation](https://doc.mapeditor.org/en/stable/manual/introduction/)
|
||||
* [Tiled video tutorials](https://www.gamefromscratch.com/post/2015/10/14/Tiled-Map-Editor-Tutorial-Series.aspx)
|
||||
|
||||
### Testing your map locally
|
||||
|
||||
In order to test your map, you need a webserver to host your map. The "map starter kit" comes with a local webserver that you can use to test your map.
|
||||
|
||||
In order to start the webserver, you will need [Node.JS](https://nodejs.org/en/). When it is downloaded, open your command line and from the directory of the map, run this command:
|
||||
|
||||
$ npm install
|
||||
|
||||
This will install the local webserver.
|
||||
|
||||
$ npm run start
|
||||
|
||||
This command will start the webserver and open the welcome page. You should see a page looking like this:
|
||||
|
||||
<figure class="figure my-5">
|
||||
<img src="images/start_kit_start_screen.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The welcome page of the "map start kit"</figcaption>
|
||||
</figure>
|
||||
|
||||
From here, you simply need to click the "Test this map" button to test your map in WorkAdventure.
|
||||
|
||||
{.alert.alert-warning}
|
||||
The local web server can only be used to test your map locally. In particular, the link will only work on your computer. You cannot share it with other people.
|
||||
|
||||
### Pushing the map
|
||||
|
||||
When your changes are ready, you need to "commit" and "push" (i.e. "upload") the changes back to GitHub. Just wait a few minutes, and your map will be propagated automatically to the GitHub pages web-server.
|
||||
|
||||
## Testing your map
|
||||
|
||||
To test your map, you need to find its URL. There are 2 kinds of URLs in WorkAdventure:
|
||||
|
||||
* Test URLs are in the form `https://play.workadventu.re/_/[instance]/[server]/[path to map]`
|
||||
* Registered URLs are in the form `https://play.workadventu.re/@/[organization]/[world]/[map]`
|
||||
|
||||
Assuming your JSON map is hosted at "`https://myuser.github.io/myrepo/map.json`", then you can browse your map at "`https://play.workadventu.re/_/global/myuser.github.io/myrepo/map.json`". Here, "global" is a name of an "instance" of your map. You can put anything instead of "global" here. People on the same instance of the map can see each others. If 2 users use 2 different instances, they are on the same map, but in 2 parallel universes. They cannot see each other.
|
||||
|
||||
This will connect you to a "public" instance. Anyone can come and connect to a public instance. If you want to manage invitations, or to perform some moderation, you will need to create a "private" instance. Private instances are available in "pro" accounts.
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 id="need-some-help">Need some help?</h3>
|
||||
<p>WorkAdventure is a constantly evolving project and there is plenty of room for improvement regarding map editing.</p>
|
||||
<p>If you are facing any troubles, do not hesitate to open an "issue" in the
|
||||
<a href="https://github.com/thecodingmachine/workadventure/issues" target="_blank">GitHub WorkAdventure account</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -1,82 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Meeting rooms
|
||||
|
||||
[Building your map - Meeting room](https://www.youtube.com/watch?v=cN9VMWHN0eo)
|
||||
|
||||
## Opening a Jitsi meet when walking on the map
|
||||
|
||||
On your map, you can define special zones (meeting rooms) that will trigger the opening of a Jitsi meet. When a player will pass over these zones, a Jitsi meet will open (as an iframe on the right side of the screen)
|
||||
|
||||
In order to create Jitsi meet zones:
|
||||
|
||||
* You must create a specific layer.
|
||||
* In layer properties, you MUST add a "`jitsiRoom`" property (of type "`string`"). The value of the property is the name of the room in Jitsi. Note: the name of the room will be "slugified" and prepended with the name of the instance of the map (so that different instances of the map have different rooms)
|
||||
* You may also use "jitsiWidth" property (of type "number" between 0 and 100) to control the width of the iframe containing the meeting room.
|
||||
|
||||
## Triggering of the "Jitsi meet" action
|
||||
|
||||
By default, Jitsi meet will open when a user enters the zone defined on the map.
|
||||
|
||||
It is however possible to trigger Jitsi only on user action. You can do this with the `jitsiTrigger` property.
|
||||
|
||||
If you set `jitsiTrigger: onaction`, when the user walks on the layer, an alert message will be displayed at the bottom of the screen:
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/click_space_jitsi.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">Jitsi meet will only open if the user clicks Space</figcaption>
|
||||
</figure>
|
||||
|
||||
If you set `jitsiTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to enter in jitsi meet room'.
|
||||
|
||||
## Customizing your "Jitsi meet"
|
||||
|
||||
Your Jitsi meet experience can be customized using Jitsi specific config options. The `jitsiConfig` and `jitsiInterfaceConfig` properties can be used on the Jitsi layer to change the way Jitsi looks and behaves. Those 2 properties are accepting a JSON string.
|
||||
|
||||
For instance, use `jitsiConfig: { "startWithAudioMuted": true }` to automatically mute the microphone when someone enters a room. Or use `jitsiInterfaceConfig: { "DEFAULT_BACKGROUND": "#77ee77" }` to change the background color of Jitsi.
|
||||
|
||||
The `jitsiConfig` property will override the Jitsi [config.js](https://github.com/jitsi/jitsi-meet/blob/master/config.js) file
|
||||
|
||||
The `jitsiInterfaceConfig` property will override the Jitsi [interface_config.js](https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js) file
|
||||
|
||||
<div class="alert alert-warning">If your customizations are not working:
|
||||
<ul>
|
||||
<li>First, check that the JSON you are entering is valid. Take a look at the console in your browser. If the JSON string is invalid, you should see a warning.</li>
|
||||
<li>Then, check that the JSON you are using is matching the version of Jitsi used.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
## Granting moderator controls in Jitsi
|
||||
|
||||
{.alert.alert-info}
|
||||
Moderator controls are linked to member tags. You need a pro account to edit member tags.
|
||||
|
||||
You can grant moderator rights to some of your members. Jitsi moderators can:
|
||||
|
||||
* Publish a Jitsi meeting on Youtube Live (you will need a Youtube Live account)
|
||||
* Record a meeting to Dropbox (you will need a Dropbox account)
|
||||
* Mute someone
|
||||
* Mute everybody expect one speaker
|
||||
* Kick users out of the meeting
|
||||
|
||||
In order to grant moderator rights to a given user, you can add a `jitsiRoomAdminTag` property to your Jitsi layer. For instance, if you write a property:
|
||||
|
||||
jitsiRoomAdminTag: speaker
|
||||
|
||||
then, any of your member with the `speaker` tag will be automatically granted moderator rights over this Jitsi instance.
|
||||
|
||||
You can read more about [managing member tags in the admin documentation](/admin-guide/manage-members).
|
||||
|
||||
## Using another Jitsi server
|
||||
|
||||
WorkAdventure usually comes with a default Jitsi meet installation. If you are using the online version at `workadventu.re`, we are handling a Jitsi meet cluster for you. If you are running the self-hosted version of WorkAdventure, the administrator probably set up a Jitsi meet instance too.
|
||||
|
||||
You have the possibility, in your map, to override the Jitsi meet instance that will be used by default. This can be useful for regulatory reasons. Maybe your company wants to keep control on the video streams and therefore, wants to self-host a Jitsi instance? Or maybe you want to use a very special configuration or very special version of Jitsi?
|
||||
|
||||
Use the `jitsiUrl` property to in the Jitsi layer to specify the Jitsi instance that should be used. Beware, `jitsiUrl` takes in parameter a **domain name**, without the protocol. So you should use:
|
||||
`jitsiUrl: meet.jit.si`
|
||||
and not
|
||||
`jitsiUrl: https://meet.jit.si`
|
||||
|
||||
{.alert.alert-info}
|
||||
When you use `jitsiUrl`, the targeted Jitsi instance must be public. You cannot use moderation features or the JWT
|
||||
tokens authentication with maps configured using the `jitsiUrl` property.
|
@ -1,154 +0,0 @@
|
||||
<?php
|
||||
$extraMenu = require __DIR__.'/../../scripting_api_extra_doc/menu.php';
|
||||
$extraUtilsMenu = require __DIR__.'/../../scripting_api_extra_doc/menu_functions.php';
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => 'Getting started',
|
||||
'url' => '/map-building/',
|
||||
'markdown' => 'maps.index',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/index.md',
|
||||
],
|
||||
[
|
||||
'title' => 'WorkAdventure maps',
|
||||
'url' => '/map-building/wa-maps.md',
|
||||
'markdown' => 'maps.wa-maps',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/wa-maps.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Entries and exits',
|
||||
'url' => '/map-building/entry-exit.md',
|
||||
'markdown' => 'maps.entry-exit',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/entry-exit.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Opening a website',
|
||||
'url' => '/map-building/opening-a-website.md',
|
||||
'markdown' => 'maps.opening-a-website',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/opening-a-website.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Meeting rooms',
|
||||
'url' => '/map-building/meeting-rooms.md',
|
||||
'markdown' => 'maps.meeting-rooms',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/meeting-rooms.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Special zones',
|
||||
'url' => '/map-building/special-zones.md',
|
||||
'markdown' => 'maps.special-zones',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/special-zones.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Animations',
|
||||
'url' => '/map-building/animations.md',
|
||||
'markdown' => 'maps.animations',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/animations.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Integrated websites',
|
||||
'url' => '/map-building/website-in-map.md',
|
||||
'markdown' => 'maps.website-in-map',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/website-in-map.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Variables',
|
||||
'url' => '/map-building/variables.md',
|
||||
'markdown' => 'maps.variables',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/variables.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Self-hosting your map',
|
||||
'url' => '/map-building/hosting.md',
|
||||
'markdown' => 'maps.hosting',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/hosting.md',
|
||||
],
|
||||
$extraMenu,
|
||||
[
|
||||
'title' => 'Scripting maps',
|
||||
'url' => '/map-building/scripting.md',
|
||||
'markdown' => 'maps.scripting',
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Using Typescript',
|
||||
'url' => '/map-building/using-typescript.md',
|
||||
'markdown' => 'maps.using-typescript',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/using-typescript.md',
|
||||
],
|
||||
[
|
||||
'title' => 'API Reference',
|
||||
'url' => '/map-building/api-reference',
|
||||
'markdown' => 'maps.api-reference',
|
||||
'collapse' => true,
|
||||
'children' => [
|
||||
[
|
||||
'title' => 'Initialization',
|
||||
'url' => '/map-building/api-start.md',
|
||||
'markdown' => 'maps.api-start',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-start.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Navigation',
|
||||
'url' => '/map-building/api-nav.md',
|
||||
'markdown' => 'maps.api-nav',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-nav.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Chat',
|
||||
'url' => '/map-building/api-chat.md',
|
||||
'markdown' => 'maps.api-chat',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-chat.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Room',
|
||||
'url' => '/map-building/api-room.md',
|
||||
'markdown' => 'maps.api-room',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-room.md',
|
||||
],
|
||||
[
|
||||
'title' => 'State',
|
||||
'url' => '/map-building/api-state.md',
|
||||
'markdown' => 'maps.api-state',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-state.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Player',
|
||||
'url' => '/map-building/api-player.md',
|
||||
'markdown' => 'maps.api-player',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-player.md',
|
||||
],
|
||||
[
|
||||
'title' => 'UI',
|
||||
'url' => '/map-building/api-ui.md',
|
||||
'markdown' => 'maps.api-ui',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-ui.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Sound',
|
||||
'url' => '/map-building/api-sound.md',
|
||||
'markdown' => 'maps.api-sound',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-sound.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Controls',
|
||||
'url' => '/map-building/api-controls.md',
|
||||
'markdown' => 'maps.api-controls',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-controls.md',
|
||||
],
|
||||
[
|
||||
'title' => 'Deprecated',
|
||||
'url' => '/map-building/api-deprecated.md',
|
||||
'markdown' => 'maps.api-deprecated',
|
||||
'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/api-deprecated.md',
|
||||
],
|
||||
]
|
||||
],
|
||||
$extraUtilsMenu
|
||||
]
|
||||
],
|
||||
[
|
||||
'title' => 'Troubleshooting',
|
||||
'url' => '/map-building/troubleshooting',
|
||||
'view' => 'content.map.troubleshooting'
|
||||
],
|
||||
];
|
@ -1,76 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Opening a website when walking on the map
|
||||
|
||||
[Building your map - Opening a website](https://www.youtube.com/watch?v=Me8cu5lLN3A)
|
||||
|
||||
## The openWebsite property
|
||||
|
||||
On your map, you can define special zones. When a player will pass over these zones, a website will open (as an iframe
|
||||
on the right side of the screen)
|
||||
|
||||
In order to create a zone that opens websites:
|
||||
|
||||
* You must create a specific layer.
|
||||
* In layer properties, you MUST add a "`openWebsite`" property (of type "`string`"). The value of the property is the URL of the website to open (the URL must start with "https://")
|
||||
* You may also use "`openWebsiteWidth`" property (of type "`int`" or "`float`" between 0 and 100) to control the width of the iframe.
|
||||
* You may also use "`openTab`" property (of type "`string`") to open in a new tab instead.
|
||||
|
||||
{.alert.alert-warning}
|
||||
A website can explicitly forbid another website from loading it in an iFrame using
|
||||
the [X-Frame-Options HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).
|
||||
|
||||
## Integrating a Youtube video
|
||||
|
||||
A common use case is to use `openWebsite` to open a Youtube video.
|
||||
|
||||
The global Youtube page cannot be embedded into an iFrame (it has the `X-Frame-Options` HTTP header).
|
||||
|
||||
To embed a Youtube video, be sure to **use the "embed" link**. You can get this link be clicking "Share > Embed" in Youtube.
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/youtube.jpg" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">Find the URL of your video in the "embed Video" HTML snippet on Youtube</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/open_website.jpg" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">Put this URL in the "openWebsite" property</figcaption>
|
||||
</figure>
|
||||
|
||||
### Triggering of the "open website" action
|
||||
|
||||
By default, the iFrame will open when a user enters the zone defined on the map.
|
||||
|
||||
It is however possible to trigger the iFrame only on user action. You can do this with the `openWebsiteTrigger` property.
|
||||
|
||||
If you set `openWebsiteTrigger: onaction`, when the user walks on the layer, an alert message will be displayed at the bottom of the screen:
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/click_space_open_website.jpg" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The iFrame will only open if the user clicks Space</figcaption>
|
||||
</figure>
|
||||
|
||||
If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'.
|
||||
|
||||
### Setting the iFrame "allow" attribute
|
||||
|
||||
By default, iFrames have limited rights in browsers. For instance, they cannot put their content in fullscreen, they cannot start your webcam, etc...
|
||||
|
||||
If you want to grant additional access rights to your iFrame, you should use the `openWebsitePolicy` property. The value of this property will be directly used for the [`allow` atttribute of your iFrame](https://developer.mozilla.org/en-US/docs/Web/HTTP/Feature_Policy/Using_Feature_Policy#the_iframe_allow_attribute).
|
||||
|
||||
For instance, if you want an iFrame to be able to go in fullscreen, you will use the property `openWebsitePolicy: fullscreen`
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/open_website_policy.jpg" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The generated iFrame will have the allow attribute set to: <code><iframe allow="fullscreen"></code></figcaption>
|
||||
</figure>
|
||||
|
||||
### Open a Jitsi with a co-website
|
||||
|
||||
Cowebsites allow you to have several sites open at the same time.
|
||||
|
||||
If you want to open a Jitsi and another page it's easy!
|
||||
|
||||
You have just to [add a Jitsi to the map](meeting-rooms.md) and [add a co-website](opening-a-website.md#the-openwebsite-property) on the same layer.
|
||||
|
||||
It's done!
|
@ -46,7 +46,7 @@ You can put relative URLs. If your script file is next to your map, you can simp
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/script_property.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/script_property.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The script property</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
@ -72,7 +72,7 @@ In order to allow communication with WorkAdventure, you need to add an additiona
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/open_website_allow_api.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<img src="https://workadventu.re/img/docs/open_website_allow_api.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The `openWebsiteAllowApi` property</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
@ -1,27 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Other special zones
|
||||
|
||||
## Making a "silent" zone
|
||||
|
||||
[Building your map - Special zones](https://www.youtube.com/watch?v=z7XLo06o-ow)
|
||||
|
||||
On your map, you can define special silent zones where nobody is allowed to talk. In these zones, users will not speak to each others, even if they are next to each others.
|
||||
|
||||
In order to create a silent zone:
|
||||
|
||||
* You must create a specific layer.
|
||||
* In layer properties, you MUST add a boolean "`silent`" property. If the silent property is checked, the users are entering the silent zone when they walk on any tile of the layer.
|
||||
|
||||
## Playing sounds or background music
|
||||
|
||||
Your map can define special zones where a sound or background music will automatically be played.
|
||||
|
||||
In order to create a zone that triggers sounds/music:
|
||||
|
||||
* You must create a specific layer.
|
||||
* In layer properties, you MUST add a "`playAudio`" property. The value of the property is a URL to an MP3 file that will be played. The URL can be relative to the URL of the map.
|
||||
* You may use the boolean property "`audioLoop`" to make the sound loop (thanks captain obvious).
|
||||
* If the "`audioVolume`" property is set, the audio player uses either the value of the property or the last volume set by the user - whichever is smaller. This property is a float from 0 to 1.0
|
||||
|
||||
{.alert.alert-info}
|
||||
"`playAudioLoop`" is deprecated and should not be used anymore.
|
@ -29,7 +29,7 @@ font that has support for a variety of accents. It renders great when used at *8
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/text-object.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<img src="https://workadventu.re/img/docs/text-object.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">The "font-family" property</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
@ -1,183 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Using Typescript with the scripting API
|
||||
|
||||
{.alert.alert-info}
|
||||
The easiest way to get started with writing scripts in Typescript is to use the
|
||||
[Github map starter kit repository](https://github.com/thecodingmachine/workadventure-map-starter-kit). It comes with
|
||||
Typescript enabled. If you are **not** using the "map starter kit", this page explains how to add Typescript to your
|
||||
own scripts.
|
||||
|
||||
## The short story
|
||||
|
||||
In this page, we will assume you already know Typescript and know how to set it up with Webpack.
|
||||
|
||||
To work with the scripting API in Typescript, you will need the typings of the `WA` object. These typings can be downloaded from the `@workadventure/iframe-api-typings` package.
|
||||
|
||||
```console
|
||||
$ npm install --save-dev @workadventure/iframe-api-typings
|
||||
```
|
||||
|
||||
Furthermore, you need to make the global `WA` object available. To do this, edit the entry point of your project (usually, it is a file called `index.ts` in the root directory).
|
||||
|
||||
Add this line at the top of the file:
|
||||
|
||||
**index.ts**
|
||||
```typescript
|
||||
/// <reference path="../node_modules/@workadventure/iframe-api-typings/iframe_api.d.ts" />
|
||||
```
|
||||
|
||||
From there, you should be able to use Typescript in your project.
|
||||
|
||||
## The long story
|
||||
|
||||
Below is a step by step guide explaining how to set up Typescript + Webpack along your WorkAdventure map.
|
||||
|
||||
In your map directory, start by adding a `package.json` file. This file will contain dependencies on Webpack, Typescript and the Workadventure typings:
|
||||
|
||||
**package.json**
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"@workadventure/iframe-api-typings": "^1.2.1",
|
||||
"eslint": "^7.24.0",
|
||||
"html-webpack-plugin": "^5.3.1",
|
||||
"ts-loader": "^8.1.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.2.4",
|
||||
"webpack": "^5.31.2",
|
||||
"webpack-cli": "^4.6.0",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --open",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can now install the dependencies:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
```
|
||||
|
||||
We now need to add a Webpack configuration file (for development mode). This Webpack file will:
|
||||
|
||||
* Start a local webserver that will be in charge of serving the map
|
||||
* Compile Typescript into Javascript and serve it automatically
|
||||
|
||||
**webpack.config.js**
|
||||
```js
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: './src/index.ts',
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
// The test webserver serves static files from the root directory.
|
||||
// It comes with CORS enabled (important for WorkAdventure to be able to load the map)
|
||||
static: {
|
||||
directory: ".",
|
||||
serveIndex: true,
|
||||
watch: true,
|
||||
},
|
||||
host: 'localhost',
|
||||
allowedHosts: "all",
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ '.tsx', '.ts', '.js' ],
|
||||
},
|
||||
output: {
|
||||
filename: 'script.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/'
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
We need to configure Typescript, using a `tsconfig.json` file.
|
||||
|
||||
**tsconfig.json**
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"module": "CommonJS",
|
||||
"target": "ES2015",
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"jsx": "react",
|
||||
"allowJs": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create your entry point (the Typescript file at the root of your project).
|
||||
|
||||
**src/index.ts**
|
||||
```typescript
|
||||
/// <reference path="../node_modules/@workadventure/iframe-api-typings/iframe_api.d.ts" />
|
||||
|
||||
console.log('Hello world!');
|
||||
```
|
||||
|
||||
The first comment line is important in order to get `WA` typings.
|
||||
|
||||
Now, you can start Webpack in dev mode!
|
||||
|
||||
```console
|
||||
$ npm run start
|
||||
```
|
||||
|
||||
This will automatically compile Typescript, and serve it (along the map) on your local webserver (so at `http://localhost:8080/script.js`). Please note that the `script.js` file is never written to the disk. So do not worry if you don't see it appearing, you need to "build" it to actually write it to the disk.
|
||||
|
||||
Final step, you must reference the script inside your map, by adding a `script` property at the root of your map:
|
||||
|
||||
<figure class="figure">
|
||||
<img src="images/script_property.png" class="figure-img img-fluid rounded" alt="" />
|
||||
<figcaption class="figure-caption">The script property</figcaption>
|
||||
</figure>
|
||||
|
||||
### Building the final script
|
||||
|
||||
We now have a correct development setup. But we still need to be able to build the production script from Typescript files. We are not going to use the development server in production. To do this, we will add an additional `webpack.prod.js` file.
|
||||
|
||||
**webpack.prod.js**
|
||||
```javascript
|
||||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.config.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
devtool: 'source-map'
|
||||
});
|
||||
```
|
||||
|
||||
This file will simply switch the Webpack config file in "production" mode. You can simply run:
|
||||
|
||||
```console
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
and the `script.js` file will be generated in the `dist/` folder. Beware, you will need to move it at the root of map for it to be read by the map.
|
@ -1,59 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Variables
|
||||
|
||||
Maps can contain **variables**. Variables are piece of information that store some data. In computer science, we like
|
||||
to say variables are storing the "state" of the room.
|
||||
|
||||
- Variables are shared amongst all players in a given room. When the value of a variable changes for one player, it changes
|
||||
for everyone.
|
||||
- Variables are **invisible**. There are plenty of ways they can act on the room, but by default, you don't see them.
|
||||
|
||||
## Declaring a variable
|
||||
|
||||
In order to declare allowed variables in a room, you need to add **objects** in an "object layer" of the map.
|
||||
|
||||
Each object will represent a variable.
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<img src="images/object_variable.png" class="figure-img img-fluid rounded" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
The name of the variable is the name of the object.
|
||||
The object **type** MUST be **variable**.
|
||||
|
||||
You can set a default value for the object in the `default` property.
|
||||
|
||||
## Persisting variables state
|
||||
|
||||
Use the `persist` property to save the state of the variable in database. If `persist` is false, the variable will stay
|
||||
in the memory of the WorkAdventure servers but will be wiped out of the memory as soon as the room is empty (or if the
|
||||
server restarts).
|
||||
|
||||
{.alert.alert-info}
|
||||
Do not use `persist` for highly dynamic values that have a short life spawn.
|
||||
|
||||
## Managing access rights to variables
|
||||
|
||||
With `readableBy` and `writableBy`, you control who can read of write in this variable. The property accepts a string
|
||||
representing a "tag". Anyone having this "tag" can read/write in the variable.
|
||||
|
||||
{.alert.alert-warning}
|
||||
`readableBy` and `writableBy` are specific to the "online" version of WorkAdventure because the notion of tags
|
||||
is not available unless you have an "admin" server (that is not part of the self-hosted version of WorkAdventure).
|
||||
|
||||
In a future release, the `jsonSchema` property will contain [a complete JSON schema](https://json-schema.org/) to validate the content of the variable.
|
||||
Trying to set a variable to a value that is not compatible with the schema will fail.
|
||||
|
||||
## Using variables
|
||||
|
||||
There are plenty of ways to use variables in WorkAdventure:
|
||||
|
||||
- Using the [scripting API](api-state.md), you can read, edit or track the content of variables.
|
||||
- Using the [Action zones](https://workadventu.re/map-building-extra/generic-action-zones.md), you can set the value of a variable when someone is entering or leaving a zone
|
||||
- By [binding variable values to properties in the map](https://workadventu.re/map-building-extra/variable-to-property-binding.md)
|
||||
- By [using automatically generated configuration screens](https://workadventu.re/map-building-extra/automatic-configuration.md) to create forms to edit the value of variables
|
||||
|
||||
In general, variables can be used by third party libraries that you can embed in your map to add extra features.
|
||||
A good example of such a library is the ["Scripting API Extra" library](https://workadventu.re/map-building-extra/about.md)
|
@ -49,36 +49,34 @@ A few things to notice:
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/tiled_screenshot_1.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<img src="https://workadventu.re/img/docs/tiled_screenshot_1.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">"floorLayer" is compulsory</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
## Building walls and "collidable" areas
|
||||
|
||||
[Building your map - Collides](https://www.youtube.com/watch?v=qTK50ymhMIE)
|
||||
|
||||
By default, the characters can traverse any tiles. If you want to prevent your character from going through a tile (like a wall or a desktop), you must make this tile "collidable". You can do this by settings the `collides` property on a given tile.
|
||||
|
||||
To make a tile "collidable", you should:
|
||||
|
||||
1. select the relevant tileset and switch to "edit" mode:
|
||||
|
||||
{.document-img}
|
||||
{.document-img}
|
||||
|
||||
2. right click on a tile of the tileset to select it:
|
||||
|
||||
{.document-img}
|
||||
{.document-img}
|
||||
|
||||
3. on the left pane in the custom properties section, right click and select "Add properties":
|
||||
|
||||
{.document-img}
|
||||
{.document-img}
|
||||
|
||||
Please add a `collides` property. The type of the property must be **bool**.
|
||||
|
||||
4. finally, check the checkbox for the `collides` property:
|
||||
|
||||
{.document-img}
|
||||
{.document-img}
|
||||
|
||||
Repeat for every tile that should be "collidable".
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
{.section-title.accent.text-primary}
|
||||
# Putting a website inside a map
|
||||
|
||||
You can inject a website directly into your map, at a given position.
|
||||
|
||||
To do this in Tiled:
|
||||
|
||||
- Select an object layer
|
||||
- Create a rectangular object, at the position where you want your website to appear
|
||||
- Add a `url` property to your object pointing to the URL you want to open
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/website_url_property.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">A "website" object</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
The `url` can be absolute, or relative to your map.
|
||||
|
||||
{.alert.alert-info}
|
||||
Internally, WorkAdventure will create an "iFrame" to load the website.
|
||||
Some websites forbid being opened by iframes using the [`X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
|
||||
HTTP header.
|
||||
|
||||
{.alert.alert-warning}
|
||||
Please note that the website always appears **on top** of the tiles (even if you put the object layer that
|
||||
contains the "website" object under the tiles).
|
||||
|
||||
## Allowing the scripting API in your iframe
|
||||
|
||||
If you are planning to use the WorkAdventure scripting API inside your iframe, you need
|
||||
to explicitly allow it, by setting an additional `allowApi` property to `true`.
|
||||
|
||||
<div>
|
||||
<figure class="figure">
|
||||
<img src="images/website_allowapi_property.png" class="figure-img img-fluid rounded" alt="" style="width: 70%" />
|
||||
<figcaption class="figure-caption">A "website" object that can communicate using the Iframe API</figcaption>
|
||||
</figure>
|
||||
</div>
|
@ -26,6 +26,7 @@
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
|
||||
// TODO: remove those ignored rules and write a stronger code!
|
||||
"@typescript-eslint/no-floating-promises": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
|
@ -1,13 +1,13 @@
|
||||
FROM node:14.15.4-buster-slim@sha256:cbae886186467bbfd274b82a234a1cdfbbd31201c2a6ee63a6893eefcf3c6e76 as builder
|
||||
WORKDIR /usr/src
|
||||
COPY messages .
|
||||
FROM thecodingmachine/workadventure-back-base:latest as builder
|
||||
WORKDIR /var/www/messages
|
||||
COPY --chown=docker:docker messages .
|
||||
RUN yarn install && yarn proto
|
||||
|
||||
# we are rebuilding on each deploy to cope with the PUSHER_URL environment URL
|
||||
FROM thecodingmachine/nodejs:14-apache
|
||||
|
||||
COPY --chown=docker:docker front .
|
||||
COPY --from=builder --chown=docker:docker /usr/src/generated /var/www/html/src/Messages/generated
|
||||
COPY --from=builder --chown=docker:docker /var/www/messages/generated /var/www/html/src/Messages/generated
|
||||
|
||||
# Removing the iframe.html file from the final image as this adds a XSS attack.
|
||||
# iframe.html is only in dev mode to circumvent a limitation
|
||||
|
2
front/dist/.htaccess
vendored
@ -22,5 +22,3 @@ RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule "^[_@]/" "/index.html" [L]
|
||||
RewriteRule "^register/" "/index.html" [L]
|
||||
RewriteRule "^login" "/index.html" [L]
|
||||
RewriteRule "^jwt" "/index.html" [L]
|
||||
|
102
front/dist/index.tmpl.html
vendored
@ -34,57 +34,10 @@
|
||||
<title>WorkAdventure</title>
|
||||
</head>
|
||||
<body id="body" style="margin: 0; background-color: #000">
|
||||
|
||||
<div class="main-container" id="main-container">
|
||||
<!-- Create the editor container -->
|
||||
<div id="game" class="game">
|
||||
<div id="cowebsite-container">
|
||||
<div id="cowebsite-container-main">
|
||||
<div id="cowebsite-slot-1">
|
||||
<div class="actions">
|
||||
<button type="button" class="nes-btn is-primary expand">></button>
|
||||
<button type="button" class="nes-btn is-error close">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cowebsite-container-sub">
|
||||
<div id="cowebsite-slot-2">
|
||||
<div class="overlay">
|
||||
<div class="actions">
|
||||
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||
</div>
|
||||
<div class="actions-move">
|
||||
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cowebsite-slot-3">
|
||||
<div class="overlay">
|
||||
<div class="actions">
|
||||
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||
</div>
|
||||
<div class="actions-move">
|
||||
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cowebsite-slot-4">
|
||||
<div class="overlay">
|
||||
<div class="actions">
|
||||
<button type="button" title="Close" class="nes-btn is-error close">×</button>
|
||||
</div>
|
||||
<div class="actions-move">
|
||||
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
|
||||
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">Ξ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="svelte-overlay"></div>
|
||||
<div id="game-overlay" class="game-overlay">
|
||||
<div id="main-section" class="main-section">
|
||||
@ -96,24 +49,44 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="cowebsite" class="cowebsite hidden">
|
||||
<aside id="cowebsite-aside" class="noselect">
|
||||
<div id="cowebsite-aside-buttons">
|
||||
<button class="top-right-btn nes-btn is-error" id="cowebsite-close" alt="close all co-websites">
|
||||
×
|
||||
</button>
|
||||
<button class="top-right-btn nes-btn is-primary" id="cowebsite-fullscreen" alt="fullscreen mode">
|
||||
<img id="cowebsite-fullscreen-close" style="display: none;" src="resources/logos/fullscreen-exit.svg"/>
|
||||
<img id="cowebsite-fullscreen-open" src="resources/logos/fullscreen.svg"/>
|
||||
</button>
|
||||
</div>
|
||||
<div id="cowebsite-aside-holder">
|
||||
<img src="/static/images/menu.svg" alt="hold to resize"/>
|
||||
</div>
|
||||
<div id="cowebsite-sub-icons"></div>
|
||||
<aside id="cowebsite-aside">
|
||||
<img src="/static/images/menu.svg" alt="hold to resize"/>
|
||||
</aside>
|
||||
<main id="cowebsite-slot-0"></main>
|
||||
<main id="cowebsite-main">
|
||||
</main>
|
||||
<button class="top-right-btn" id="cowebsite-fullscreen" alt="fullscreen mode">
|
||||
<img id="cowebsite-fullscreen-open" src="resources/logos/fullscreen.svg"/>
|
||||
<img id="cowebsite-fullscreen-close" style="display: none;" src="resources/logos/fullscreen-exit.svg"/>
|
||||
</button>
|
||||
<button class="top-right-btn" id="cowebsite-close" alt="close the iframe">
|
||||
<img src="resources/logos/close.svg"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="audioplayerctrl" class="hidden">
|
||||
<div class="audioplayer">
|
||||
<button type="button" id="audioplayer_mute" class="fa fa-volump-up">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
||||
<g id="audioplayer_volume_icon_playing">
|
||||
<path d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z" />
|
||||
<path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z" />
|
||||
<path d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z" />
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="audioplayer">
|
||||
<input type="range" id="audioplayer_volume" min="0" max="1" step="0.025" value="1" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="audioplayer">
|
||||
<label id="label-audioplayer_decrease_while_talking" for="audioplayer_decrease_while_talking" title="decrease background volume by 50% when entering conversations">
|
||||
reduce in conversations
|
||||
<input type="checkbox" id="audioplayer_decrease_while_talking" checked />
|
||||
</label>
|
||||
<div id="audioplayer" style="visibility: hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="cowebsite-buffer"></div>
|
||||
</div>
|
||||
|
||||
<div id="activeScreenSharing" class="active-screen-sharing active">
|
||||
@ -121,7 +94,6 @@
|
||||
<audio id="report-message">
|
||||
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
|
||||
</audio>
|
||||
<script type="text/javascript" src="config.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|