Merge branch 'develop' of github.com:thecodingmachine/workadventure into functional-tile-properties
This commit is contained in:
commit
b7934d9d03
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,4 +1,19 @@
|
|||||||
## Version 1.3.9 - in dev
|
## Version 1.4.x-dev
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
|
||||||
|
- Added the ability to have animated tiles in maps #1216 #1217
|
||||||
|
- Enabled outlines on actionable item again (they were disabled when migrating to Phaser 3.50) #1218
|
||||||
|
- Enabled outlines on player names (when the mouse hovers on a player you can interact with) #1219
|
||||||
|
- Migrated the admin console to Svelte, and redesigned the console #1211
|
||||||
|
|
||||||
|
## Version 1.4.1
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
|
||||||
|
- Loading errors after the preload stage should not crash the game anymore
|
||||||
|
|
||||||
|
## Version 1.4.0
|
||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
33
docs/maps/animations.md
Normal file
33
docs/maps/animations.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# Animating WorkAdventure maps
|
||||||
|
|
||||||
|
A tile can run an animation in loops, for example to render water or blinking lights. Each animation frame is a single
|
||||||
|
32x32 tile. To create an animation, edit the tileset in Tiled and click on the tile to animate (or pick a free tile to
|
||||||
|
not overwrite existing ones) and click on the animation editor:
|
||||||
|
|
||||||
|
|
||||||
|
<div class="px-5 card rounded d-inline-block">
|
||||||
|
<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="https://workadventu.re/img/docs/anims/animation_editor.png" alt="" />
|
||||||
|
<figcaption class="figure-caption">The tile animation editor</figcaption>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
You can preview animations directly in Tiled, using the "Show tile animations" option:
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<figure class="figure">
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{.alert.alert-info}
|
||||||
|
**Tip:** The engine does tile-updates every 100ms, animations with a shorter frame duration will most likely not look that good or may even do not work.
|
37
docs/maps/api-chat.md
Normal file
37
docs/maps/api-chat.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Chat functions reference
|
||||||
|
|
||||||
|
### Sending a message in the chat
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.chat.sendChatMessage(message: string, author: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Sends a message in the chat. The message is only visible in the browser of the current user.
|
||||||
|
|
||||||
|
* **message**: the message to be displayed in the chat
|
||||||
|
* **author**: the name displayed for the author of the message. It does not have to be a real user.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.chat.sendChatMessage('Hello world', 'Mr Robot');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listening to messages from the chat
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.chat.onChatMessage(callback: (message: string) => void): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Listens to messages typed by the current user and calls the callback. Messages from other users in the chat cannot be listened to.
|
||||||
|
|
||||||
|
* **callback**: the function that will be called when a message is received. It contains the message typed by the user.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.chat.onChatMessage((message => {
|
||||||
|
console.log('The user typed a message', message);
|
||||||
|
}));
|
||||||
|
```
|
29
docs/maps/api-controls.md
Normal file
29
docs/maps/api-controls.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Controls functions Reference
|
||||||
|
|
||||||
|
### Disabling / restoring controls
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.controls.disablePlayerControls(): void
|
||||||
|
WA.controls.restorePlayerControls(): void
|
||||||
|
```
|
||||||
|
|
||||||
|
These 2 methods can be used to completely disable player controls and to enable them again.
|
||||||
|
|
||||||
|
When controls are disabled, the user cannot move anymore using keyboard input. This can be useful in a "First Time User Experience" part, to display an important message to a user before letting him/her move again.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.room.onEnterZone('myZone', () => {
|
||||||
|
WA.controls.disablePlayerControls();
|
||||||
|
WA.ui.openPopup("popupRectangle", 'This is an imporant message!', [{
|
||||||
|
label: "Got it!",
|
||||||
|
className: "primary",
|
||||||
|
callback: (popup) => {
|
||||||
|
WA.controls.restorePlayerControls();
|
||||||
|
popup.close();
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
```
|
20
docs/maps/api-deprecated.md
Normal file
20
docs/maps/api-deprecated.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Reference - Deprecated functions
|
||||||
|
|
||||||
|
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`.
|
||||||
|
- 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`.
|
||||||
|
- 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`.
|
68
docs/maps/api-nav.md
Normal file
68
docs/maps/api-nav.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Navigation functions reference
|
||||||
|
|
||||||
|
### Opening a web page in a new tab
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.nav.openTab(url: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Opens the webpage at "url" in your browser, in a new tab.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.nav.openTab('https://www.wikipedia.org/');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opening a web page in the current tab
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.nav.goToPage(url: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Opens the webpage at "url" in your browser in place of WorkAdventure. WorkAdventure will be completely unloaded.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.nav.goToPage('https://www.wikipedia.org/');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Going to a different map from the script
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
WA.nav.goToRoom(url: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
Load the map at url without unloading workadventure
|
||||||
|
|
||||||
|
relative urls: "../subFolder/map.json[#start-layer-name]"
|
||||||
|
global urls: "/_/global/domain/path/map.json[#start-layer-name]"
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.nav.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls
|
||||||
|
WA.nav.goToRoom('../otherMap/map.json');
|
||||||
|
WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opening/closing a web page in an iFrame
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.nav.openCoWebSite(url: 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.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.nav.openCoWebSite('https://www.wikipedia.org/');
|
||||||
|
// ...
|
||||||
|
WA.nav.closeCoWebSite();
|
||||||
|
```
|
||||||
|
|
@ -1,257 +1,11 @@
|
|||||||
{.section-title.accent.text-primary}
|
{.section-title.accent.text-primary}
|
||||||
# API Reference
|
# API Reference
|
||||||
|
|
||||||
### Sending a message in the chat
|
- [Navigation functions](api-nav.md)
|
||||||
|
- [Chat functions](api-chat.md)
|
||||||
```
|
- [Room functions](api-room.md)
|
||||||
sendChatMessage(message: string, author: string): void
|
- [UI functions](api-ui.md)
|
||||||
```
|
- [Sound functions](api-sound.md)
|
||||||
|
- [Controls functions](api-controls.md)
|
||||||
Sends a message in the chat. The message is only visible in the browser of the current user.
|
|
||||||
|
- [List of deprecated functions](api-deprecated.md)
|
||||||
* **message**: the message to be displayed in the chat
|
|
||||||
* **author**: the name displayed for the author of the message. It does not have to be a real user.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.sendChatMessage('Hello world', 'Mr Robot');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Listening to messages from the chat
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
onChatMessage(callback: (message: string) => void): void
|
|
||||||
```
|
|
||||||
|
|
||||||
Listens to messages typed by the current user and calls the callback. Messages from other users in the chat cannot be listened to.
|
|
||||||
|
|
||||||
* **callback**: the function that will be called when a message is received. It contains the message typed by the user.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.onChatMessage((message => {
|
|
||||||
console.log('The user typed a message', message);
|
|
||||||
}));
|
|
||||||
```
|
|
||||||
|
|
||||||
### Detecting when the user enters/leaves a zone
|
|
||||||
|
|
||||||
```
|
|
||||||
onEnterZone(name: string, callback: () => void): void
|
|
||||||
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 zone. The name of the zone is stored in the map, on a dedicated layer with the `zone` property.
|
|
||||||
|
|
||||||
<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.onEnterZone('myZone', () => {
|
|
||||||
WA.sendChatMessage("Hello!", 'Mr Robot');
|
|
||||||
})
|
|
||||||
|
|
||||||
WA.onLeaveZone('myZone', () => {
|
|
||||||
WA.sendChatMessage("Goodbye!", 'Mr Robot');
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Opening a popup
|
|
||||||
|
|
||||||
In order to open a popup window, you must first define the position of the popup on your map.
|
|
||||||
|
|
||||||
You can position this popup by using a "rectangle" object in Tiled that you will place on an "object" layer.
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<img src="https://workadventu.re/img/docs/screen_popup_tiled.png" class="figure-img img-fluid rounded" alt="" />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<img src="https://workadventu.re/img/docs/screen_popup_in_game.png" class="figure-img img-fluid rounded" alt="" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```
|
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup
|
|
||||||
```
|
|
||||||
|
|
||||||
* **targetObject**: the name of the rectangle object defined in Tiled.
|
|
||||||
* **message**: the message to display in the popup.
|
|
||||||
* **buttons**: an array of action buttons defined underneath the popup.
|
|
||||||
|
|
||||||
Action buttons are `ButtonDescriptor` objects containing these properties.
|
|
||||||
|
|
||||||
* **label (_string_)**: The label of the button.
|
|
||||||
* **className (_string_)**: The visual type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled".
|
|
||||||
* **callback (_(popup: Popup)=>void_)**: Callback called when the button is pressed.
|
|
||||||
|
|
||||||
Please note that `openPopup` returns an object of the `Popup` class. Also, the callback called when a button is clicked is passed a `Popup` object.
|
|
||||||
|
|
||||||
The `Popup` class that represents an open popup contains a single method: `close()`. This will obviously close the popup when called.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
class Popup {
|
|
||||||
/**
|
|
||||||
* Closes the popup
|
|
||||||
*/
|
|
||||||
close() {};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
let helloWorldPopup;
|
|
||||||
|
|
||||||
// Open the popup when we enter a given zone
|
|
||||||
helloWorldPopup = WA.onEnterZone('myZone', () => {
|
|
||||||
WA.openPopup("popupRectangle", 'Hello world!', [{
|
|
||||||
label: "Close",
|
|
||||||
className: "primary",
|
|
||||||
callback: (popup) => {
|
|
||||||
// Close the popup when the "Close" button is pressed.
|
|
||||||
popup.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// Close the popup when we leave the zone.
|
|
||||||
WA.onLeaveZone('myZone', () => {
|
|
||||||
helloWorldPopup.close();
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Disabling / restoring controls
|
|
||||||
|
|
||||||
```
|
|
||||||
disablePlayerControls(): void
|
|
||||||
restorePlayerControls(): void
|
|
||||||
```
|
|
||||||
|
|
||||||
These 2 methods can be used to completely disable player controls and to enable them again.
|
|
||||||
|
|
||||||
When controls are disabled, the user cannot move anymore using keyboard input. This can be useful in a "First Time User Experience" part, to display an important message to a user before letting him/her move again.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.onEnterZone('myZone', () => {
|
|
||||||
WA.disablePlayerControls();
|
|
||||||
WA.openPopup("popupRectangle", 'This is an imporant message!', [{
|
|
||||||
label: "Got it!",
|
|
||||||
className: "primary",
|
|
||||||
callback: (popup) => {
|
|
||||||
WA.restorePlayerControls();
|
|
||||||
popup.close();
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Opening a web page in a new tab
|
|
||||||
|
|
||||||
```
|
|
||||||
openTab(url: string): void
|
|
||||||
```
|
|
||||||
|
|
||||||
Opens the webpage at "url" in your browser, in a new tab.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.openTab('https://www.wikipedia.org/');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Opening a web page in the current tab
|
|
||||||
|
|
||||||
```
|
|
||||||
goToPage(url: string): void
|
|
||||||
```
|
|
||||||
|
|
||||||
Opens the webpage at "url" in your browser in place of WorkAdventure. WorkAdventure will be completely unloaded.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.goToPage('https://www.wikipedia.org/');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Going to a different map from the script
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
goToRoom(url: string): void
|
|
||||||
```
|
|
||||||
|
|
||||||
Load the map at url without unloading workadventure
|
|
||||||
|
|
||||||
relative urls: "../subFolder/map.json[#start-layer-name]"
|
|
||||||
global urls: "/_/global/domain/path/map.json[#start-layer-name]"
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls
|
|
||||||
WA.goToRoom('../otherMap/map.json');
|
|
||||||
WA.goToRoom("/_/global/<path to global map>.json#start-layer-2")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Opening/closing a web page in an iFrame
|
|
||||||
|
|
||||||
```
|
|
||||||
openCoWebSite(url: string): void
|
|
||||||
closeCoWebSite(): void
|
|
||||||
```
|
|
||||||
|
|
||||||
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
WA.openCoWebSite('https://www.wikipedia.org/');
|
|
||||||
// ...
|
|
||||||
WA.closeCoWebSite();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Load a sound from an url
|
|
||||||
|
|
||||||
```
|
|
||||||
loadSound(url: string): Sound
|
|
||||||
```
|
|
||||||
|
|
||||||
Load a sound from an url
|
|
||||||
|
|
||||||
Please note that `loadSound` returns an object of the `Sound` class
|
|
||||||
|
|
||||||
The `Sound` class that represents a loaded sound contains two methods: `play(soundConfig : SoundConfig|undefined)` and `stop()`
|
|
||||||
|
|
||||||
The parameter soundConfig is optional, if you call play without a Sound config the sound will be played with the basic configuration.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var mySound = WA.loadSound("Sound.ogg");
|
|
||||||
var config = {
|
|
||||||
volume : 0.5,
|
|
||||||
loop : false,
|
|
||||||
rate : 1,
|
|
||||||
detune : 1,
|
|
||||||
delay : 0,
|
|
||||||
seek : 0,
|
|
||||||
mute : false
|
|
||||||
}
|
|
||||||
mySound.play(config);
|
|
||||||
// ...
|
|
||||||
mySound.stop();
|
|
||||||
```
|
|
||||||
|
33
docs/maps/api-room.md
Normal file
33
docs/maps/api-room.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Room functions Reference
|
||||||
|
|
||||||
|
### Detecting when the user enters/leaves a zone
|
||||||
|
|
||||||
|
```
|
||||||
|
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 zone. The name of the zone is stored in the map, on a dedicated layer with the `zone` property.
|
||||||
|
|
||||||
|
<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.onEnterZone('myZone', () => {
|
||||||
|
WA.chat.sendChatMessage("Hello!", 'Mr Robot');
|
||||||
|
})
|
||||||
|
|
||||||
|
WA.room.onLeaveZone('myZone', () => {
|
||||||
|
WA.chat.sendChatMessage("Goodbye!", 'Mr Robot');
|
||||||
|
})
|
||||||
|
```
|
34
docs/maps/api-sound.md
Normal file
34
docs/maps/api-sound.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API Sound functions Reference
|
||||||
|
|
||||||
|
### Load a sound from an url
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.sound.loadSound(url: string): Sound
|
||||||
|
```
|
||||||
|
|
||||||
|
Load a sound from an url
|
||||||
|
|
||||||
|
Please note that `loadSound` returns an object of the `Sound` class
|
||||||
|
|
||||||
|
The `Sound` class that represents a loaded sound contains two methods: `play(soundConfig : SoundConfig|undefined)` and `stop()`
|
||||||
|
|
||||||
|
The parameter soundConfig is optional, if you call play without a Sound config the sound will be played with the basic configuration.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var mySound = WA.sound.loadSound("Sound.ogg");
|
||||||
|
var config = {
|
||||||
|
volume : 0.5,
|
||||||
|
loop : false,
|
||||||
|
rate : 1,
|
||||||
|
detune : 1,
|
||||||
|
delay : 0,
|
||||||
|
seek : 0,
|
||||||
|
mute : false
|
||||||
|
}
|
||||||
|
mySound.play(config);
|
||||||
|
// ...
|
||||||
|
mySound.stop();
|
||||||
|
```
|
67
docs/maps/api-ui.md
Normal file
67
docs/maps/api-ui.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{.section-title.accent.text-primary}
|
||||||
|
# API UI functions Reference
|
||||||
|
|
||||||
|
### Opening a popup
|
||||||
|
|
||||||
|
In order to open a popup window, you must first define the position of the popup on your map.
|
||||||
|
|
||||||
|
You can position this popup by using a "rectangle" object in Tiled that you will place on an "object" layer.
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<img src="https://workadventu.re/img/docs/screen_popup_tiled.png" class="figure-img img-fluid rounded" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<img src="https://workadventu.re/img/docs/screen_popup_in_game.png" class="figure-img img-fluid rounded" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
```
|
||||||
|
WA.ui.openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup
|
||||||
|
```
|
||||||
|
|
||||||
|
* **targetObject**: the name of the rectangle object defined in Tiled.
|
||||||
|
* **message**: the message to display in the popup.
|
||||||
|
* **buttons**: an array of action buttons defined underneath the popup.
|
||||||
|
|
||||||
|
Action buttons are `ButtonDescriptor` objects containing these properties.
|
||||||
|
|
||||||
|
* **label (_string_)**: The label of the button.
|
||||||
|
* **className (_string_)**: The visual type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled".
|
||||||
|
* **callback (_(popup: Popup)=>void_)**: Callback called when the button is pressed.
|
||||||
|
|
||||||
|
Please note that `openPopup` returns an object of the `Popup` class. Also, the callback called when a button is clicked is passed a `Popup` object.
|
||||||
|
|
||||||
|
The `Popup` class that represents an open popup contains a single method: `close()`. This will obviously close the popup when called.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class Popup {
|
||||||
|
/**
|
||||||
|
* Closes the popup
|
||||||
|
*/
|
||||||
|
close() {};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let helloWorldPopup;
|
||||||
|
|
||||||
|
// Open the popup when we enter a given zone
|
||||||
|
helloWorldPopup = WA.room.onEnterZone('myZone', () => {
|
||||||
|
WA.ui.openPopup("popupRectangle", 'Hello world!', [{
|
||||||
|
label: "Close",
|
||||||
|
className: "primary",
|
||||||
|
callback: (popup) => {
|
||||||
|
// Close the popup when the "Close" button is pressed.
|
||||||
|
popup.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}]);
|
||||||
|
|
||||||
|
// Close the popup when we leave the zone.
|
||||||
|
WA.room.onLeaveZone('myZone', () => {
|
||||||
|
helloWorldPopup.close();
|
||||||
|
});
|
||||||
|
```
|
8204
front/package-lock.json
generated
8204
front/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@
|
|||||||
"generic-type-guard": "^3.2.0",
|
"generic-type-guard": "^3.2.0",
|
||||||
"google-protobuf": "^3.13.0",
|
"google-protobuf": "^3.13.0",
|
||||||
"phaser": "^3.54.0",
|
"phaser": "^3.54.0",
|
||||||
|
"phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254",
|
||||||
"phaser3-rex-plugins": "^1.1.42",
|
"phaser3-rex-plugins": "^1.1.42",
|
||||||
"queue-typescript": "^1.0.1",
|
"queue-typescript": "^1.0.1",
|
||||||
"quill": "1.3.6",
|
"quill": "1.3.6",
|
||||||
|
@ -1,397 +0,0 @@
|
|||||||
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
|
||||||
import type {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
|
||||||
import type {RoomConnection} from "../Connexion/RoomConnection";
|
|
||||||
import type {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
|
||||||
import {AdminMessageEventTypes} from "../Connexion/AdminMessagesService";
|
|
||||||
|
|
||||||
export const CLASS_CONSOLE_MESSAGE = 'main-console';
|
|
||||||
export const INPUT_CONSOLE_MESSAGE = 'input-send-text';
|
|
||||||
export const UPLOAD_CONSOLE_MESSAGE = 'input-upload-music';
|
|
||||||
export const INPUT_TYPE_CONSOLE = 'input-type';
|
|
||||||
export const VIDEO_QUALITY_SELECT = 'select-video-quality';
|
|
||||||
|
|
||||||
export const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
|
||||||
export const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
|
||||||
|
|
||||||
interface EventTargetFiles extends EventTarget {
|
|
||||||
files: Array<File>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
export class ConsoleGlobalMessageManager {
|
|
||||||
|
|
||||||
private readonly divMainConsole: HTMLDivElement;
|
|
||||||
private readonly divMessageConsole: HTMLDivElement;
|
|
||||||
//private readonly divSettingConsole: HTMLDivElement;
|
|
||||||
private readonly buttonMainConsole: HTMLDivElement;
|
|
||||||
private readonly buttonSendMainConsole: HTMLImageElement;
|
|
||||||
//private readonly buttonAdminMainConsole: HTMLImageElement;
|
|
||||||
//private readonly buttonSettingsMainConsole: HTMLImageElement;
|
|
||||||
private activeConsole: boolean = false;
|
|
||||||
private activeMessage: boolean = false;
|
|
||||||
private activeSetting: boolean = false;
|
|
||||||
private userInputManager!: UserInputManager;
|
|
||||||
private static cssLoaded: boolean = false;
|
|
||||||
|
|
||||||
constructor(private Connection: RoomConnection, userInputManager : UserInputManager, private isAdmin: Boolean) {
|
|
||||||
this.buttonMainConsole = document.createElement('div');
|
|
||||||
this.buttonMainConsole.classList.add('console');
|
|
||||||
this.buttonMainConsole.hidden = true;
|
|
||||||
this.divMainConsole = document.createElement('div');
|
|
||||||
this.divMainConsole.className = CLASS_CONSOLE_MESSAGE;
|
|
||||||
this.divMessageConsole = document.createElement('div');
|
|
||||||
this.divMessageConsole.className = 'message';
|
|
||||||
//this.divSettingConsole = document.createElement('div');
|
|
||||||
//this.divSettingConsole.className = 'setting';
|
|
||||||
this.buttonSendMainConsole = document.createElement('img');
|
|
||||||
this.buttonSendMainConsole.id = 'btn-send-message';
|
|
||||||
//this.buttonSettingsMainConsole = document.createElement('img');
|
|
||||||
//this.buttonAdminMainConsole = document.createElement('img');
|
|
||||||
this.userInputManager = userInputManager;
|
|
||||||
this.initialise();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
initialise() {
|
|
||||||
for (const elem of document.getElementsByClassName(CLASS_CONSOLE_MESSAGE)) {
|
|
||||||
elem.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
const typeConsole = document.createElement('input');
|
|
||||||
typeConsole.id = INPUT_TYPE_CONSOLE;
|
|
||||||
typeConsole.value = MESSAGE_TYPE;
|
|
||||||
typeConsole.type = 'hidden';
|
|
||||||
|
|
||||||
const menu = document.createElement('div');
|
|
||||||
menu.classList.add('menu')
|
|
||||||
const textMessage = document.createElement('span');
|
|
||||||
textMessage.innerText = "Message";
|
|
||||||
textMessage.classList.add('active');
|
|
||||||
textMessage.addEventListener('click', () => {
|
|
||||||
textMessage.classList.add('active');
|
|
||||||
const messageSection = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(this.getSectionId(INPUT_CONSOLE_MESSAGE));
|
|
||||||
messageSection.classList.add('active');
|
|
||||||
|
|
||||||
textAudio.classList.remove('active');
|
|
||||||
const audioSection = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(this.getSectionId(UPLOAD_CONSOLE_MESSAGE));
|
|
||||||
audioSection.classList.remove('active');
|
|
||||||
|
|
||||||
typeConsole.value = MESSAGE_TYPE;
|
|
||||||
});
|
|
||||||
menu.appendChild(textMessage);
|
|
||||||
const textAudio = document.createElement('span');
|
|
||||||
textAudio.innerText = "Audio";
|
|
||||||
textAudio.addEventListener('click', () => {
|
|
||||||
textAudio.classList.add('active');
|
|
||||||
const audioSection = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(this.getSectionId(UPLOAD_CONSOLE_MESSAGE));
|
|
||||||
audioSection.classList.add('active');
|
|
||||||
|
|
||||||
textMessage.classList.remove('active');
|
|
||||||
const messageSection = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(this.getSectionId(INPUT_CONSOLE_MESSAGE));
|
|
||||||
messageSection.classList.remove('active');
|
|
||||||
|
|
||||||
typeConsole.value = AUDIO_TYPE;
|
|
||||||
});
|
|
||||||
menu.appendChild(textMessage);
|
|
||||||
menu.appendChild(textAudio);
|
|
||||||
this.divMessageConsole.appendChild(menu);
|
|
||||||
|
|
||||||
this.buttonSendMainConsole.src = 'resources/logos/send-yellow.svg';
|
|
||||||
this.buttonSendMainConsole.addEventListener('click', () => {
|
|
||||||
if(this.activeMessage){
|
|
||||||
this.disabledMessageConsole();
|
|
||||||
}else{
|
|
||||||
this.activeMessageConsole();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*this.buttonAdminMainConsole.src = 'resources/logos/setting-yellow.svg';
|
|
||||||
this.buttonAdminMainConsole.addEventListener('click', () => {
|
|
||||||
window.open(ADMIN_URL, '_blank');
|
|
||||||
});*/
|
|
||||||
|
|
||||||
/*this.buttonSettingsMainConsole.src = 'resources/logos/monitor-yellow.svg';
|
|
||||||
this.buttonSettingsMainConsole.addEventListener('click', () => {
|
|
||||||
if(this.activeSetting){
|
|
||||||
this.disabledSettingConsole();
|
|
||||||
}else{
|
|
||||||
this.activeSettingConsole();
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
|
|
||||||
this.divMessageConsole.appendChild(typeConsole);
|
|
||||||
|
|
||||||
/*if(this.isAdmin) {
|
|
||||||
this.buttonMainConsole.appendChild(this.buttonSendMainConsole);
|
|
||||||
//this.buttonMainConsole.appendChild(this.buttonAdminMainConsole);
|
|
||||||
}*/
|
|
||||||
this.createTextMessagePart();
|
|
||||||
this.createUploadAudioPart();
|
|
||||||
//this.buttonMainConsole.appendChild(this.buttonSettingsMainConsole);
|
|
||||||
|
|
||||||
this.divMainConsole.appendChild(this.buttonMainConsole);
|
|
||||||
this.divMainConsole.appendChild(this.divMessageConsole);
|
|
||||||
//this.divMainConsole.appendChild(this.divSettingConsole);
|
|
||||||
|
|
||||||
const mainSectionDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
|
|
||||||
mainSectionDiv.appendChild(this.divMainConsole);
|
|
||||||
}
|
|
||||||
|
|
||||||
createTextMessagePart(){
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.id = INPUT_CONSOLE_MESSAGE
|
|
||||||
const buttonSend = document.createElement('button');
|
|
||||||
buttonSend.innerText = 'Send';
|
|
||||||
buttonSend.classList.add('btn');
|
|
||||||
buttonSend.addEventListener('click', (event: MouseEvent) => {
|
|
||||||
this.sendMessage();
|
|
||||||
this.disabledMessageConsole();
|
|
||||||
});
|
|
||||||
const buttonDiv = document.createElement('div');
|
|
||||||
buttonDiv.classList.add('btn-action');
|
|
||||||
buttonDiv.appendChild(buttonSend)
|
|
||||||
|
|
||||||
const section = document.createElement('section');
|
|
||||||
section.id = this.getSectionId(INPUT_CONSOLE_MESSAGE);
|
|
||||||
section.classList.add('active');
|
|
||||||
section.appendChild(div);
|
|
||||||
section.appendChild(buttonDiv);
|
|
||||||
this.divMessageConsole.appendChild(section);
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try{
|
|
||||||
// Start loading CSS
|
|
||||||
const cssPromise = ConsoleGlobalMessageManager.loadCss();
|
|
||||||
// Import quill
|
|
||||||
const {default: Quill}:any = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
||||||
// Wait for CSS to be loaded
|
|
||||||
await cssPromise;
|
|
||||||
|
|
||||||
const toolbarOptions = [
|
|
||||||
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
|
||||||
['blockquote', 'code-block'],
|
|
||||||
|
|
||||||
[{'header': 1}, {'header': 2}], // custom button values
|
|
||||||
[{'list': 'ordered'}, {'list': 'bullet'}],
|
|
||||||
[{'script': 'sub'}, {'script': 'super'}], // superscript/subscript
|
|
||||||
[{'indent': '-1'}, {'indent': '+1'}], // outdent/indent
|
|
||||||
[{'direction': 'rtl'}], // text direction
|
|
||||||
|
|
||||||
[{'size': ['small', false, 'large', 'huge']}], // custom dropdown
|
|
||||||
[{'header': [1, 2, 3, 4, 5, 6, false]}],
|
|
||||||
|
|
||||||
[{'color': []}, {'background': []}], // dropdown with defaults from theme
|
|
||||||
[{'font': []}],
|
|
||||||
[{'align': []}],
|
|
||||||
|
|
||||||
['clean'],
|
|
||||||
|
|
||||||
['link', 'image', 'video']
|
|
||||||
// remove formatting button
|
|
||||||
];
|
|
||||||
|
|
||||||
new Quill(`#${INPUT_CONSOLE_MESSAGE}`, {
|
|
||||||
theme: 'snow',
|
|
||||||
modules: {
|
|
||||||
toolbar: toolbarOptions
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}catch(err){
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
createUploadAudioPart(){
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.classList.add('upload');
|
|
||||||
|
|
||||||
const label = document.createElement('label');
|
|
||||||
label.setAttribute('for', UPLOAD_CONSOLE_MESSAGE);
|
|
||||||
|
|
||||||
const img = document.createElement('img');
|
|
||||||
img.setAttribute('for', UPLOAD_CONSOLE_MESSAGE);
|
|
||||||
img.src = 'resources/logos/music-file.svg';
|
|
||||||
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'file';
|
|
||||||
input.id = UPLOAD_CONSOLE_MESSAGE
|
|
||||||
input.addEventListener('input', (e: Event) => {
|
|
||||||
if(!e.target){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const eventTarget : EventTargetFiles = (e.target as EventTargetFiles);
|
|
||||||
if(!eventTarget || !eventTarget.files || eventTarget.files.length === 0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const file : File = eventTarget.files[0];
|
|
||||||
|
|
||||||
if(!file){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HtmlUtils.removeElementByIdOrFail('audi-message-filename');
|
|
||||||
}catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const p = document.createElement('p');
|
|
||||||
p.id = 'audi-message-filename';
|
|
||||||
p.innerText = `${file.name} : ${this.getFileSize(file.size)}`;
|
|
||||||
label.appendChild(p);
|
|
||||||
});
|
|
||||||
|
|
||||||
label.appendChild(img);
|
|
||||||
div.appendChild(label);
|
|
||||||
div.appendChild(input);
|
|
||||||
|
|
||||||
const buttonSend = document.createElement('button');
|
|
||||||
buttonSend.innerText = 'Send';
|
|
||||||
buttonSend.classList.add('btn');
|
|
||||||
buttonSend.addEventListener('click', (event: MouseEvent) => {
|
|
||||||
this.sendMessage();
|
|
||||||
this.disabledMessageConsole();
|
|
||||||
});
|
|
||||||
const buttonDiv = document.createElement('div');
|
|
||||||
buttonDiv.classList.add('btn-action');
|
|
||||||
buttonDiv.appendChild(buttonSend)
|
|
||||||
|
|
||||||
const section = document.createElement('section');
|
|
||||||
section.id = this.getSectionId(UPLOAD_CONSOLE_MESSAGE);
|
|
||||||
section.appendChild(div);
|
|
||||||
section.appendChild(buttonDiv);
|
|
||||||
this.divMessageConsole.appendChild(section);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static loadCss(): Promise<void> {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
if (ConsoleGlobalMessageManager.cssLoaded) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const fileref = document.createElement("link")
|
|
||||||
fileref.setAttribute("rel", "stylesheet")
|
|
||||||
fileref.setAttribute("type", "text/css")
|
|
||||||
fileref.setAttribute("href", "https://cdn.quilljs.com/1.3.7/quill.snow.css");
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(fileref);
|
|
||||||
ConsoleGlobalMessageManager.cssLoaded = true;
|
|
||||||
fileref.onload = () => {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
fileref.onerror = () => {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(){
|
|
||||||
const inputType = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(INPUT_TYPE_CONSOLE);
|
|
||||||
if(AUDIO_TYPE !== inputType.value && MESSAGE_TYPE !== inputType.value){
|
|
||||||
throw "Error event type";
|
|
||||||
}
|
|
||||||
if(AUDIO_TYPE === inputType.value){
|
|
||||||
return this.sendAudioMessage();
|
|
||||||
}
|
|
||||||
return this.sendTextMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sendTextMessage(){
|
|
||||||
const elements = document.getElementsByClassName('ql-editor');
|
|
||||||
const quillEditor = elements.item(0);
|
|
||||||
if(!quillEditor){
|
|
||||||
throw "Error get quill node";
|
|
||||||
}
|
|
||||||
const GlobalMessage : PlayGlobalMessageInterface = {
|
|
||||||
id: "1", // FIXME: use another ID?
|
|
||||||
message: quillEditor.innerHTML,
|
|
||||||
type: MESSAGE_TYPE
|
|
||||||
};
|
|
||||||
quillEditor.innerHTML = '';
|
|
||||||
this.Connection.emitGlobalMessage(GlobalMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async sendAudioMessage(){
|
|
||||||
const inputAudio = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(UPLOAD_CONSOLE_MESSAGE);
|
|
||||||
const selectedFile = inputAudio.files ? inputAudio.files[0] : null;
|
|
||||||
if(!selectedFile){
|
|
||||||
throw 'no file selected';
|
|
||||||
}
|
|
||||||
|
|
||||||
const fd = new FormData();
|
|
||||||
fd.append('file', selectedFile);
|
|
||||||
const res = await this.Connection.uploadAudio(fd);
|
|
||||||
|
|
||||||
const GlobalMessage : PlayGlobalMessageInterface = {
|
|
||||||
id: (res as {id: string}).id,
|
|
||||||
message: (res as {path: string}).path,
|
|
||||||
type: AUDIO_TYPE
|
|
||||||
};
|
|
||||||
inputAudio.value = '';
|
|
||||||
try {
|
|
||||||
HtmlUtils.removeElementByIdOrFail('audi-message-filename');
|
|
||||||
}catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
this.Connection.emitGlobalMessage(GlobalMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
active(){
|
|
||||||
this.userInputManager.disableControls();
|
|
||||||
this.divMainConsole.style.top = '0';
|
|
||||||
this.activeConsole = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
disabled(){
|
|
||||||
this.userInputManager.initKeyBoardEvent();
|
|
||||||
this.activeConsole = false;
|
|
||||||
this.divMainConsole.style.top = '-80%';
|
|
||||||
}
|
|
||||||
|
|
||||||
activeMessageConsole(){
|
|
||||||
if(!this.isAdmin){
|
|
||||||
throw "User is not admin";
|
|
||||||
}
|
|
||||||
if(this.activeMessage){
|
|
||||||
this.disabledMessageConsole();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.activeMessage = true;
|
|
||||||
this.active();
|
|
||||||
this.divMessageConsole.classList.add('active');
|
|
||||||
this.buttonMainConsole.hidden = false;
|
|
||||||
this.buttonSendMainConsole.classList.add('active');
|
|
||||||
//if button not
|
|
||||||
try{
|
|
||||||
HtmlUtils.getElementByIdOrFail('btn-send-message');
|
|
||||||
}catch (e) {
|
|
||||||
this.buttonMainConsole.appendChild(this.buttonSendMainConsole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disabledMessageConsole(){
|
|
||||||
this.activeMessage = false;
|
|
||||||
this.disabled();
|
|
||||||
this.buttonMainConsole.hidden = true;
|
|
||||||
this.divMessageConsole.classList.remove('active');
|
|
||||||
this.buttonSendMainConsole.classList.remove('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSectionId(id: string) : string {
|
|
||||||
return `section-${id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getFileSize(number: number) :string {
|
|
||||||
if (number < 1024) {
|
|
||||||
return number + 'bytes';
|
|
||||||
} else if (number >= 1024 && number < 1048576) {
|
|
||||||
return (number / 1024).toFixed(1) + 'KB';
|
|
||||||
} else if (number >= 1048576) {
|
|
||||||
return (number / 1048576).toFixed(1) + 'MB';
|
|
||||||
}else{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,10 @@
|
|||||||
import {HtmlUtils} from "./../WebRtc/HtmlUtils";
|
import {HtmlUtils} from "./../WebRtc/HtmlUtils";
|
||||||
import {AUDIO_TYPE, MESSAGE_TYPE} from "./ConsoleGlobalMessageManager";
|
|
||||||
import {PUSHER_URL, UPLOADER_URL} from "../Enum/EnvironmentVariable";
|
import {PUSHER_URL, UPLOADER_URL} from "../Enum/EnvironmentVariable";
|
||||||
import type {RoomConnection} from "../Connexion/RoomConnection";
|
import type {RoomConnection} from "../Connexion/RoomConnection";
|
||||||
import type {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
import type {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
||||||
import {soundManager} from "../Phaser/Game/SoundManager";
|
import {soundManager} from "../Phaser/Game/SoundManager";
|
||||||
|
import {AdminMessageEventTypes} from "../Connexion/AdminMessagesService";
|
||||||
|
|
||||||
export class GlobalMessageManager {
|
export class GlobalMessageManager {
|
||||||
|
|
||||||
@ -36,11 +36,11 @@ export class GlobalMessageManager {
|
|||||||
previousMessage.remove();
|
previousMessage.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(AUDIO_TYPE === message.type){
|
if(AdminMessageEventTypes.audio === message.type){
|
||||||
this.playAudioMessage(message.id, message.message);
|
this.playAudioMessage(message.id, message.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MESSAGE_TYPE === message.type){
|
if(AdminMessageEventTypes.admin === message.type){
|
||||||
this.playTextMessage(message.id, message.message);
|
this.playTextMessage(message.id, message.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export type IframeEventMap = {
|
|||||||
removeBubble: null
|
removeBubble: null
|
||||||
loadSound: LoadSoundEvent
|
loadSound: LoadSoundEvent
|
||||||
playSound: PlaySoundEvent
|
playSound: PlaySoundEvent
|
||||||
stopSound: null
|
stopSound: null,
|
||||||
}
|
}
|
||||||
export interface IframeEvent<T extends keyof IframeEventMap> {
|
export interface IframeEvent<T extends keyof IframeEventMap> {
|
||||||
type: T;
|
type: T;
|
||||||
|
31
front/src/Api/iframe/IframeApiContribution.ts
Normal file
31
front/src/Api/iframe/IframeApiContribution.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type * as tg from "generic-type-guard";
|
||||||
|
import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent';
|
||||||
|
|
||||||
|
export function sendToWorkadventure(content: IframeEvent<keyof IframeEventMap>) {
|
||||||
|
window.parent.postMessage(content, "*")
|
||||||
|
}
|
||||||
|
type GuardedType<Guard extends tg.TypeGuard<unknown>> = Guard extends tg.TypeGuard<infer T> ? T : never
|
||||||
|
|
||||||
|
export interface IframeCallback<Key extends keyof IframeResponseEventMap, T = IframeResponseEventMap[Key], Guard = tg.TypeGuard<T>> {
|
||||||
|
|
||||||
|
typeChecker: Guard,
|
||||||
|
callback: (payloadData: T) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IframeCallbackContribution<Key extends keyof IframeResponseEventMap> extends IframeCallback<Key> {
|
||||||
|
|
||||||
|
type: Key
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export abstract class IframeApiContribution<T extends {
|
||||||
|
callbacks: Array<IframeCallbackContribution<keyof IframeResponseEventMap>>,
|
||||||
|
}> {
|
||||||
|
|
||||||
|
abstract callbacks: T["callbacks"]
|
||||||
|
}
|
39
front/src/Api/iframe/Sound/Sound.ts
Normal file
39
front/src/Api/iframe/Sound/Sound.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import {sendToWorkadventure} from "../IframeApiContribution";
|
||||||
|
import type {LoadSoundEvent} from "../../Events/LoadSoundEvent";
|
||||||
|
import type {PlaySoundEvent} from "../../Events/PlaySoundEvent";
|
||||||
|
import type {StopSoundEvent} from "../../Events/StopSoundEvent";
|
||||||
|
import SoundConfig = Phaser.Types.Sound.SoundConfig;
|
||||||
|
|
||||||
|
export class Sound {
|
||||||
|
constructor(private url: string) {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'loadSound',
|
||||||
|
"data": {
|
||||||
|
url: this.url,
|
||||||
|
} as LoadSoundEvent
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public play(config: SoundConfig) {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'playSound',
|
||||||
|
"data": {
|
||||||
|
url: this.url,
|
||||||
|
config
|
||||||
|
} as PlaySoundEvent
|
||||||
|
|
||||||
|
});
|
||||||
|
return this.url;
|
||||||
|
}
|
||||||
|
public stop() {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'stopSound',
|
||||||
|
"data": {
|
||||||
|
url: this.url,
|
||||||
|
} as StopSoundEvent
|
||||||
|
|
||||||
|
});
|
||||||
|
return this.url;
|
||||||
|
}
|
||||||
|
}
|
18
front/src/Api/iframe/Ui/ButtonDescriptor.ts
Normal file
18
front/src/Api/iframe/Ui/ButtonDescriptor.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type {Popup} from "./Popup";
|
||||||
|
|
||||||
|
export type ButtonClickedCallback = (popup: Popup) => void;
|
||||||
|
|
||||||
|
export interface ButtonDescriptor {
|
||||||
|
/**
|
||||||
|
* The label of the button
|
||||||
|
*/
|
||||||
|
label: string,
|
||||||
|
/**
|
||||||
|
* The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled"
|
||||||
|
*/
|
||||||
|
className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled",
|
||||||
|
/**
|
||||||
|
* Callback called if the button is pressed
|
||||||
|
*/
|
||||||
|
callback: ButtonClickedCallback,
|
||||||
|
}
|
19
front/src/Api/iframe/Ui/Popup.ts
Normal file
19
front/src/Api/iframe/Ui/Popup.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import {sendToWorkadventure} from "../IframeApiContribution";
|
||||||
|
import type {ClosePopupEvent} from "../../Events/ClosePopupEvent";
|
||||||
|
|
||||||
|
export class Popup {
|
||||||
|
constructor(private id: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the popup
|
||||||
|
*/
|
||||||
|
public close(): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
'type': 'closePopup',
|
||||||
|
'data': {
|
||||||
|
'popupId': this.id,
|
||||||
|
} as ClosePopupEvent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
38
front/src/Api/iframe/chat.ts
Normal file
38
front/src/Api/iframe/chat.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import type { ChatEvent } from '../Events/ChatEvent'
|
||||||
|
import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent'
|
||||||
|
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'
|
||||||
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
|
import {Subject} from "rxjs";
|
||||||
|
|
||||||
|
const chatStream = new Subject<string>();
|
||||||
|
|
||||||
|
class WorkadventureChatCommands extends IframeApiContribution<WorkadventureChatCommands> {
|
||||||
|
|
||||||
|
callbacks = [apiCallback({
|
||||||
|
callback: (event: UserInputChatEvent) => {
|
||||||
|
chatStream.next(event.message);
|
||||||
|
},
|
||||||
|
type: "userInputChat",
|
||||||
|
typeChecker: isUserInputChatEvent
|
||||||
|
})]
|
||||||
|
|
||||||
|
|
||||||
|
sendChatMessage(message: string, author: string) {
|
||||||
|
sendToWorkadventure({
|
||||||
|
type: 'chat',
|
||||||
|
data: {
|
||||||
|
'message': message,
|
||||||
|
'author': author
|
||||||
|
} as ChatEvent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to messages sent by the local user, in the chat.
|
||||||
|
*/
|
||||||
|
onChatMessage(callback: (message: string) => void) {
|
||||||
|
chatStream.subscribe(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new WorkadventureChatCommands()
|
16
front/src/Api/iframe/controls.ts
Normal file
16
front/src/Api/iframe/controls.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||||
|
|
||||||
|
class WorkadventureControlsCommands extends IframeApiContribution<WorkadventureControlsCommands> {
|
||||||
|
callbacks = []
|
||||||
|
|
||||||
|
disablePlayerControls(): void {
|
||||||
|
sendToWorkadventure({ 'type': 'disablePlayerControls', data: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
restorePlayerControls(): void {
|
||||||
|
sendToWorkadventure({ 'type': 'restorePlayerControls', data: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default new WorkadventureControlsCommands();
|
56
front/src/Api/iframe/nav.ts
Normal file
56
front/src/Api/iframe/nav.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import type { GoToPageEvent } from '../Events/GoToPageEvent';
|
||||||
|
import type { OpenTabEvent } from '../Events/OpenTabEvent';
|
||||||
|
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||||
|
import type {OpenCoWebSiteEvent} from "../Events/OpenCoWebSiteEvent";
|
||||||
|
|
||||||
|
|
||||||
|
class WorkadventureNavigationCommands extends IframeApiContribution<WorkadventureNavigationCommands> {
|
||||||
|
callbacks = []
|
||||||
|
|
||||||
|
|
||||||
|
openTab(url: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'openTab',
|
||||||
|
"data": {
|
||||||
|
url
|
||||||
|
} as OpenTabEvent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goToPage(url: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'goToPage',
|
||||||
|
"data": {
|
||||||
|
url
|
||||||
|
} as GoToPageEvent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goToRoom(url: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'loadPage',
|
||||||
|
"data": {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openCoWebSite(url: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'openCoWebSite',
|
||||||
|
"data": {
|
||||||
|
url
|
||||||
|
} as OpenCoWebSiteEvent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeCoWebSite(): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
"type": 'closeCoWebSite',
|
||||||
|
data: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default new WorkadventureNavigationCommands();
|
16
front/src/Api/iframe/registeredCallbacks.ts
Normal file
16
front/src/Api/iframe/registeredCallbacks.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type {IframeResponseEventMap} from "../../Api/Events/IframeEvent";
|
||||||
|
import type {IframeCallback} from "../../Api/iframe/IframeApiContribution";
|
||||||
|
import type {IframeCallbackContribution} from "../../Api/iframe/IframeApiContribution";
|
||||||
|
|
||||||
|
export const registeredCallbacks: { [K in keyof IframeResponseEventMap]?: IframeCallback<K> } = {}
|
||||||
|
|
||||||
|
export function apiCallback<T extends keyof IframeResponseEventMap>(callbackData: IframeCallbackContribution<T>): IframeCallbackContribution<keyof IframeResponseEventMap> {
|
||||||
|
const iframeCallback = {
|
||||||
|
typeChecker: callbackData.typeChecker,
|
||||||
|
callback: callbackData.callback
|
||||||
|
} as IframeCallback<T>;
|
||||||
|
|
||||||
|
const newCallback = { [callbackData.type]: iframeCallback };
|
||||||
|
Object.assign(registeredCallbacks, newCallback)
|
||||||
|
return callbackData as unknown as IframeCallbackContribution<keyof IframeResponseEventMap>;
|
||||||
|
}
|
50
front/src/Api/iframe/room.ts
Normal file
50
front/src/Api/iframe/room.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Subject } from "rxjs";
|
||||||
|
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent';
|
||||||
|
import { IframeApiContribution } from './IframeApiContribution';
|
||||||
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
|
|
||||||
|
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
|
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
|
|
||||||
|
class WorkadventureRoomCommands extends IframeApiContribution<WorkadventureRoomCommands> {
|
||||||
|
callbacks = [
|
||||||
|
apiCallback({
|
||||||
|
callback: (payloadData: EnterLeaveEvent) => {
|
||||||
|
enterStreams.get(payloadData.name)?.next();
|
||||||
|
},
|
||||||
|
type: "enterEvent",
|
||||||
|
typeChecker: isEnterLeaveEvent
|
||||||
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "leaveEvent",
|
||||||
|
typeChecker: isEnterLeaveEvent,
|
||||||
|
callback: (payloadData) => {
|
||||||
|
leaveStreams.get(payloadData.name)?.next();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
onEnterZone(name: string, callback: () => void): void {
|
||||||
|
let subject = enterStreams.get(name);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<EnterLeaveEvent>();
|
||||||
|
enterStreams.set(name, subject);
|
||||||
|
}
|
||||||
|
subject.subscribe(callback);
|
||||||
|
|
||||||
|
}
|
||||||
|
onLeaveZone(name: string, callback: () => void): void {
|
||||||
|
let subject = leaveStreams.get(name);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<EnterLeaveEvent>();
|
||||||
|
leaveStreams.set(name, subject);
|
||||||
|
}
|
||||||
|
subject.subscribe(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default new WorkadventureRoomCommands();
|
17
front/src/Api/iframe/sound.ts
Normal file
17
front/src/Api/iframe/sound.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { LoadSoundEvent } from '../Events/LoadSoundEvent';
|
||||||
|
import type { PlaySoundEvent } from '../Events/PlaySoundEvent';
|
||||||
|
import type { StopSoundEvent } from '../Events/StopSoundEvent';
|
||||||
|
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||||
|
import {Sound} from "./Sound/Sound";
|
||||||
|
|
||||||
|
class WorkadventureSoundCommands extends IframeApiContribution<WorkadventureSoundCommands> {
|
||||||
|
callbacks = []
|
||||||
|
|
||||||
|
loadSound(url: string): Sound {
|
||||||
|
return new Sound(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default new WorkadventureSoundCommands();
|
83
front/src/Api/iframe/ui.ts
Normal file
83
front/src/Api/iframe/ui.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { isButtonClickedEvent } from '../Events/ButtonClickedEvent';
|
||||||
|
import type { ClosePopupEvent } from '../Events/ClosePopupEvent';
|
||||||
|
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||||
|
import { apiCallback } from "./registeredCallbacks";
|
||||||
|
import {Popup} from "./Ui/Popup";
|
||||||
|
import type {ButtonClickedCallback, ButtonDescriptor} from "./Ui/ButtonDescriptor";
|
||||||
|
|
||||||
|
let popupId = 0;
|
||||||
|
const popups: Map<number, Popup> = new Map<number, Popup>();
|
||||||
|
const popupCallbacks: Map<number, Map<number, ButtonClickedCallback>> = new Map<number, Map<number, ButtonClickedCallback>>();
|
||||||
|
|
||||||
|
interface ZonedPopupOptions {
|
||||||
|
zone: string
|
||||||
|
objectLayerName?: string,
|
||||||
|
popupText: string,
|
||||||
|
delay?: number
|
||||||
|
popupOptions: Array<ButtonDescriptor>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiCommands> {
|
||||||
|
|
||||||
|
callbacks = [apiCallback({
|
||||||
|
type: "buttonClickedEvent",
|
||||||
|
typeChecker: isButtonClickedEvent,
|
||||||
|
callback: (payloadData) => {
|
||||||
|
const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId);
|
||||||
|
const popup = popups.get(payloadData.popupId);
|
||||||
|
if (popup === undefined) {
|
||||||
|
throw new Error('Could not find popup with ID "' + payloadData.popupId + '"');
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
callback(popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})];
|
||||||
|
|
||||||
|
|
||||||
|
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||||
|
popupId++;
|
||||||
|
const popup = new Popup(popupId);
|
||||||
|
const btnMap = new Map<number, () => void>();
|
||||||
|
popupCallbacks.set(popupId, btnMap);
|
||||||
|
let id = 0;
|
||||||
|
for (const button of buttons) {
|
||||||
|
const callback = button.callback;
|
||||||
|
if (callback) {
|
||||||
|
btnMap.set(id, () => {
|
||||||
|
callback(popup);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToWorkadventure({
|
||||||
|
'type': 'openPopup',
|
||||||
|
'data': {
|
||||||
|
popupId,
|
||||||
|
targetObject,
|
||||||
|
message,
|
||||||
|
buttons: buttons.map((button) => {
|
||||||
|
return {
|
||||||
|
label: button.label,
|
||||||
|
className: button.className
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
popups.set(popupId, popup)
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayBubble(): void {
|
||||||
|
sendToWorkadventure({ 'type': 'displayBubble', data: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBubble(): void {
|
||||||
|
sendToWorkadventure({ 'type': 'removeBubble', data: null });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new WorkAdventureUiCommands();
|
@ -21,6 +21,8 @@
|
|||||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
||||||
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||||
|
import {consoleGlobalMessageManagerVisibleStore} from "../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
|
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
</script>
|
</script>
|
||||||
@ -70,6 +72,11 @@
|
|||||||
<CameraControls></CameraControls>
|
<CameraControls></CameraControls>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $consoleGlobalMessageManagerVisibleStore}
|
||||||
|
<div>
|
||||||
|
<ConsoleGlobalMessageManager game={game}></ConsoleGlobalMessageManager>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $helpCameraSettingsVisibleStore}
|
{#if $helpCameraSettingsVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>
|
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import InputTextGlobalMessage from "./InputTextGlobalMessage.svelte";
|
||||||
|
import UploadAudioGlobalMessage from "./UploadAudioGlobalMessage.svelte";
|
||||||
|
import {gameManager} from "../../Phaser/Game/GameManager";
|
||||||
|
import type {Game} from "../../Phaser/Game/Game";
|
||||||
|
|
||||||
|
export let game: Game;
|
||||||
|
let inputSendTextActive = true;
|
||||||
|
let uploadMusicActive = false;
|
||||||
|
|
||||||
|
function inputSendTextActivate() {
|
||||||
|
inputSendTextActive = true;
|
||||||
|
uploadMusicActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputUploadMusicActivate() {
|
||||||
|
uploadMusicActive = true;
|
||||||
|
inputSendTextActive = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="main-console nes-container is-rounded">
|
||||||
|
<!-- <div class="console nes-container is-rounded">
|
||||||
|
<img class="btn-close" src="resources/logos/send-yellow.svg" alt="Close">
|
||||||
|
</div>-->
|
||||||
|
<div class="main-global-message">
|
||||||
|
<h2> Global Message </h2>
|
||||||
|
<div class="global-message">
|
||||||
|
<div class="menu">
|
||||||
|
<button class="nes-btn {inputSendTextActive ? 'is-disabled' : ''}" on:click|preventDefault={inputSendTextActivate}>Message</button>
|
||||||
|
<button class="nes-btn {uploadMusicActive ? 'is-disabled' : ''}" on:click|preventDefault={inputUploadMusicActivate}>Audio</button>
|
||||||
|
</div>
|
||||||
|
<div class="main-input">
|
||||||
|
{#if inputSendTextActive}
|
||||||
|
<InputTextGlobalMessage game={game} gameManager={gameManager}></InputTextGlobalMessage>
|
||||||
|
{/if}
|
||||||
|
{#if uploadMusicActive}
|
||||||
|
<UploadAudioGlobalMessage game={game} gameManager={gameManager}></UploadAudioGlobalMessage>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,99 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import type {Game} from "../../Phaser/Game/Game";
|
||||||
|
import type {GameManager} from "../../Phaser/Game/GameManager";
|
||||||
|
import type {PlayGlobalMessageInterface} from "../../Connexion/ConnexionModels";
|
||||||
|
import {AdminMessageEventTypes} from "../../Connexion/AdminMessagesService";
|
||||||
|
import type {Quill} from "quill";
|
||||||
|
import {LoginSceneName} from "../../Phaser/Login/LoginScene";
|
||||||
|
|
||||||
|
//toolbar
|
||||||
|
export const toolbarOptions = [
|
||||||
|
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
||||||
|
['blockquote', 'code-block'],
|
||||||
|
|
||||||
|
[{'header': 1}, {'header': 2}], // custom button values
|
||||||
|
[{'list': 'ordered'}, {'list': 'bullet'}],
|
||||||
|
[{'script': 'sub'}, {'script': 'super'}], // superscript/subscript
|
||||||
|
[{'indent': '-1'}, {'indent': '+1'}], // outdent/indent
|
||||||
|
[{'direction': 'rtl'}], // text direction
|
||||||
|
|
||||||
|
[{'size': ['small', false, 'large', 'huge']}], // custom dropdown
|
||||||
|
[{'header': [1, 2, 3, 4, 5, 6, false]}],
|
||||||
|
|
||||||
|
[{'color': []}, {'background': []}], // dropdown with defaults from theme
|
||||||
|
[{'font': []}],
|
||||||
|
[{'align': []}],
|
||||||
|
|
||||||
|
['clean'],
|
||||||
|
|
||||||
|
['link', 'image', 'video']
|
||||||
|
// remove formatting button
|
||||||
|
];
|
||||||
|
|
||||||
|
export let game: Game;
|
||||||
|
export let gameManager: GameManager;
|
||||||
|
|
||||||
|
let gameScene = gameManager.getCurrentGameScene(game.scene.getScene(LoginSceneName));
|
||||||
|
let quill: Quill;
|
||||||
|
let INPUT_CONSOLE_MESSAGE: HTMLDivElement;
|
||||||
|
|
||||||
|
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
||||||
|
|
||||||
|
//Quill
|
||||||
|
onMount(async () => {
|
||||||
|
|
||||||
|
// Import quill
|
||||||
|
const {default: Quill} = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
|
quill = new Quill(INPUT_CONSOLE_MESSAGE, {
|
||||||
|
theme: 'snow',
|
||||||
|
modules: {
|
||||||
|
toolbar: toolbarOptions
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
quill.on('selection-change', function (range, oldRange) {
|
||||||
|
if (range === null && oldRange !== null) {
|
||||||
|
consoleGlobalMessageManagerFocusStore.set(false);
|
||||||
|
} else if (range !== null && oldRange === null)
|
||||||
|
consoleGlobalMessageManagerFocusStore.set(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function disableConsole() {
|
||||||
|
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||||
|
consoleGlobalMessageManagerFocusStore.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SendTextMessage() {
|
||||||
|
if (gameScene == undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const text = quill.getText(0, quill.getLength());
|
||||||
|
|
||||||
|
const GlobalMessage: PlayGlobalMessageInterface = {
|
||||||
|
id: "1", // FIXME: use another ID?
|
||||||
|
message: text,
|
||||||
|
type: MESSAGE_TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
quill.deleteText(0, quill.getLength());
|
||||||
|
gameScene.connection?.emitGlobalMessage(GlobalMessage);
|
||||||
|
disableConsole();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="section-input-send-text">
|
||||||
|
<div class="input-send-text" bind:this={INPUT_CONSOLE_MESSAGE}></div>
|
||||||
|
<div class="btn-action">
|
||||||
|
<button class="nes-btn is-primary" on:click|preventDefault={SendTextMessage}>Send</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import 'https://cdn.quilljs.com/1.3.7/quill.snow.css';
|
||||||
|
</style>
|
@ -0,0 +1,130 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||||
|
import type {Game} from "../../Phaser/Game/Game";
|
||||||
|
import type {GameManager} from "../../Phaser/Game/GameManager";
|
||||||
|
import {consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore} from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
|
import {AdminMessageEventTypes} from "../../Connexion/AdminMessagesService";
|
||||||
|
import type {PlayGlobalMessageInterface} from "../../Connexion/ConnexionModels";
|
||||||
|
import uploadFile from "../images/music-file.svg";
|
||||||
|
import {LoginSceneName} from "../../Phaser/Login/LoginScene";
|
||||||
|
|
||||||
|
interface EventTargetFiles extends EventTarget {
|
||||||
|
files: Array<File>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let game: Game;
|
||||||
|
export let gameManager: GameManager;
|
||||||
|
|
||||||
|
let gameScene = gameManager.getCurrentGameScene(game.scene.getScene(LoginSceneName));
|
||||||
|
let fileinput: HTMLInputElement;
|
||||||
|
let filename: string;
|
||||||
|
let filesize: string;
|
||||||
|
let errorfile: boolean;
|
||||||
|
|
||||||
|
const AUDIO_TYPE = AdminMessageEventTypes.audio;
|
||||||
|
|
||||||
|
|
||||||
|
async function SendAudioMessage() {
|
||||||
|
if (gameScene == undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const inputAudio = HtmlUtils.getElementByIdOrFail<HTMLInputElement>("input-send-audio");
|
||||||
|
const selectedFile = inputAudio.files ? inputAudio.files[0] : null;
|
||||||
|
if (!selectedFile) {
|
||||||
|
errorfile = true;
|
||||||
|
throw 'no file selected';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('file', selectedFile);
|
||||||
|
const res = await gameScene.connection?.uploadAudio(fd);
|
||||||
|
|
||||||
|
const GlobalMessage: PlayGlobalMessageInterface = {
|
||||||
|
id: (res as { id: string }).id,
|
||||||
|
message: (res as { path: string }).path,
|
||||||
|
type: AUDIO_TYPE
|
||||||
|
}
|
||||||
|
inputAudio.value = '';
|
||||||
|
gameScene.connection?.emitGlobalMessage(GlobalMessage);
|
||||||
|
disableConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputAudioFile(event: Event) {
|
||||||
|
const eventTarget : EventTargetFiles = (event.target as EventTargetFiles);
|
||||||
|
if(!eventTarget || !eventTarget.files || eventTarget.files.length === 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = eventTarget.files[0];
|
||||||
|
if(!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = file.name;
|
||||||
|
filesize = getFileSize(file.size);
|
||||||
|
errorfile = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileSize(number: number) {
|
||||||
|
if (number < 1024) {
|
||||||
|
return number + 'bytes';
|
||||||
|
} else if (number >= 1024 && number < 1048576) {
|
||||||
|
return (number / 1024).toFixed(1) + 'KB';
|
||||||
|
} else if (number >= 1048576) {
|
||||||
|
return (number / 1048576).toFixed(1) + 'MB';
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableConsole() {
|
||||||
|
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||||
|
consoleGlobalMessageManagerFocusStore.set(false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="section-input-send-audio">
|
||||||
|
<div class="input-send-audio">
|
||||||
|
<img src="{uploadFile}" alt="Upload a file" on:click|preventDefault={ () => {fileinput.click();}}>
|
||||||
|
{#if filename != undefined}
|
||||||
|
<label for="input-send-audio">{filename} : {filesize}</label>
|
||||||
|
{/if}
|
||||||
|
{#if errorfile}
|
||||||
|
<p class="err">No file selected. You need to upload a file before sending it.</p>
|
||||||
|
{/if}
|
||||||
|
<input type="file" id="input-send-audio" bind:this={fileinput} on:change={(e) => {inputAudioFile(e)}}>
|
||||||
|
</div>
|
||||||
|
<div class="btn-action">
|
||||||
|
<button class="nes-btn is-primary" on:click|preventDefault={SendAudioMessage}>Send</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
//UploadAudioGlobalMessage
|
||||||
|
.section-input-send-audio {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-audio .input-send-audio {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-audio #input-send-audio{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-audio div.input-send-audio label{
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-audio div.input-send-audio p.err {
|
||||||
|
color: #ce372b;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-audio div.input-send-audio img{
|
||||||
|
height: 150px;
|
||||||
|
cursor: url('../../../style/images/cursor_pointer.png'), pointer;
|
||||||
|
}
|
||||||
|
</style>
|
27
front/src/Components/images/music-file.svg
Normal file
27
front/src/Components/images/music-file.svg
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 448 448" style="enable-background:new 0 0 448 448;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFDA01;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M348,288c-44.2,0-80,35.8-80,80s35.8,80,80,80s80-35.8,80-80C428,323.8,392.2,288,348,288z M387.6,359.6
|
||||||
|
c-3.1,3.1-8.2,3.1-11.3,0L356,339.3V416c0,4.4-3.6,8-8,8s-8-3.6-8-8v-76.7l-20.3,20.3c-3.1,3-8.1,3-11.2-0.1s-3.1-8.1-0.1-11.2
|
||||||
|
l33.9-33.9c0.7-0.7,1.6-1.3,2.6-1.7c2-0.8,4.2-0.8,6.1,0c1,0.4,1.9,1,2.6,1.7l33.9,33.9C390.7,351.4,390.7,356.5,387.6,359.6z"/>
|
||||||
|
<path class="st0" d="M244,154.6L148,182v15.4l96-27.4V154.6z"/>
|
||||||
|
<path class="st0" d="M244,280c0,8.8-7.2,16-16,16s-16-7.2-16-16s7.2-16,16-16S244,271.2,244,280z"/>
|
||||||
|
<path class="st0" d="M132,312c0,8.8-7.2,16-16,16s-16-7.2-16-16s7.2-16,16-16S132,303.2,132,312z"/>
|
||||||
|
<path class="st0" d="M31.3,80H100V11.3L31.3,80z"/>
|
||||||
|
<path class="st0" d="M20,448h275c-0.1-0.1-0.2-0.1-0.3-0.2c-2.9-2-5.8-4.1-8.5-6.4c-0.7-0.6-1.4-1.3-2.1-1.9
|
||||||
|
c-1.9-1.7-3.8-3.5-5.6-5.4c-0.8-0.9-1.6-1.8-2.4-2.7c-1.6-1.8-3.2-3.8-4.7-5.7c-0.7-0.9-1.4-1.8-2-2.7c-1.8-2.6-3.5-5.2-5-8
|
||||||
|
c-0.2-0.4-0.4-0.7-0.6-1c-1.7-3.1-3.2-6.4-4.6-9.7c-0.4-1-0.7-2-1.1-3c-0.9-2.4-1.7-4.9-2.4-7.4c-0.3-1.2-0.6-2.4-0.9-3.6
|
||||||
|
c-0.6-2.5-1.1-5-1.5-7.6c-0.2-1.1-0.4-2.3-0.5-3.4c-0.9-6.9-1-13.9-0.2-20.8c0.1-1.1,0.3-2.1,0.5-3.1c0.3-2.1,0.5-4.1,0.9-6.2
|
||||||
|
c0.2-1.2,0.6-2.4,0.9-3.7c0.4-1.8,0.8-3.6,1.4-5.3c0.4-1.3,0.9-2.5,1.3-3.8c0.6-1.6,1.1-3.3,1.8-4.9c0.5-1.3,1.1-2.5,1.7-3.7
|
||||||
|
c0.7-1.5,1.4-3,2.2-4.5c0.6-1.2,1.4-2.4,2-3.6c0.8-1.4,1.7-2.8,2.6-4.2c0.8-1.2,1.6-2.3,2.4-3.4c0.9-1.3,1.9-2.6,2.9-3.9
|
||||||
|
c0.9-1.1,1.8-2.1,2.7-3.2c1.1-1.2,2.1-2.4,3.2-3.6c1-1,2-2,3-2.9c1.2-1.1,2.3-2.2,3.6-3.2c1.1-0.9,2.1-1.8,3.2-2.7
|
||||||
|
c1.3-1,2.6-2,3.9-2.9c1.1-0.8,2.3-1.6,3.5-2.4c1.4-0.9,2.8-1.7,4.2-2.5c1.2-0.7,2.4-1.4,3.6-2c1.5-0.8,2.9-1.5,4.4-2.1
|
||||||
|
c1.3-0.6,2.5-1.2,3.8-1.7c1.6-0.6,3.1-1.2,4.7-1.7c1.3-0.4,2.6-0.9,3.9-1.3c1.6-0.5,3.3-0.9,5-1.3c1.3-0.3,2.6-0.7,4-0.9
|
||||||
|
c1.8-0.3,3.5-0.6,5.3-0.8c1.3-0.2,2.6-0.4,4-0.5c0.3,0,0.6-0.1,1-0.1V0H116v88c0,4.4-3.6,8-8,8H20V448z M116,280
|
||||||
|
c5.6,0,11.2,1.6,16,4.4V176c0-3.6,2.4-6.7,5.8-7.7l112-32c2.4-0.7,5-0.2,7,1.3s3.2,3.9,3.2,6.4v136c0,17.7-14.3,32-32,32
|
||||||
|
s-32-14.3-32-32s14.3-32,32-32c5.6,0,11.2,1.6,16,4.4v-65.8L148,214v98c0,17.7-14.3,32-32,32s-32-14.3-32-32S98.3,280,116,280z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
@ -10,7 +10,7 @@ export interface CharacterTexture {
|
|||||||
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
|
export const maxUserNameLength: number = MAX_USERNAME_LENGTH;
|
||||||
|
|
||||||
export function isUserNameValid(value: unknown): boolean {
|
export function isUserNameValid(value: unknown): boolean {
|
||||||
return typeof value === "string" && value.length > 0 && value.length <= maxUserNameLength && value.indexOf(' ') === -1;
|
return typeof value === "string" && value.length > 0 && value.length <= maxUserNameLength && /\S/.test(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function areCharacterLayersValid(value: string[] | null): boolean {
|
export function areCharacterLayersValid(value: string[] | null): boolean {
|
||||||
|
@ -8,6 +8,7 @@ import {Companion} from "../Companion/Companion";
|
|||||||
import type {GameScene} from "../Game/GameScene";
|
import type {GameScene} from "../Game/GameScene";
|
||||||
import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes";
|
import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes";
|
||||||
import {waScaleManager} from "../Services/WaScaleManager";
|
import {waScaleManager} from "../Services/WaScaleManager";
|
||||||
|
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||||
|
|
||||||
const playerNameY = - 25;
|
const playerNameY = - 25;
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ export abstract class Character extends Container {
|
|||||||
public companion?: Companion;
|
public companion?: Companion;
|
||||||
private emote: Phaser.GameObjects.Sprite | null = null;
|
private emote: Phaser.GameObjects.Sprite | null = null;
|
||||||
private emoteTween: Phaser.Tweens.Tween|null = null;
|
private emoteTween: Phaser.Tweens.Tween|null = null;
|
||||||
|
scene: GameScene;
|
||||||
|
|
||||||
constructor(scene: GameScene,
|
constructor(scene: GameScene,
|
||||||
x: number,
|
x: number,
|
||||||
@ -46,6 +48,7 @@ export abstract class Character extends Container {
|
|||||||
companionTexturePromise?: Promise<string>
|
companionTexturePromise?: Promise<string>
|
||||||
) {
|
) {
|
||||||
super(scene, x, y/*, texture, frame*/);
|
super(scene, x, y/*, texture, frame*/);
|
||||||
|
this.scene = scene;
|
||||||
this.PlayerValue = name;
|
this.PlayerValue = name;
|
||||||
this.invisible = true
|
this.invisible = true
|
||||||
|
|
||||||
@ -67,6 +70,19 @@ export abstract class Character extends Container {
|
|||||||
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
||||||
useHandCursor: true,
|
useHandCursor: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.on('pointerover',() => {
|
||||||
|
this.getOutlinePlugin()?.add(this.playerName, {
|
||||||
|
thickness: 2,
|
||||||
|
outlineColor: 0xffff00
|
||||||
|
});
|
||||||
|
this.scene.markDirty();
|
||||||
|
});
|
||||||
|
this.on('pointerout',() => {
|
||||||
|
this.getOutlinePlugin()?.remove(this.playerName);
|
||||||
|
this.scene.markDirty();
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.add.existing(this);
|
scene.add.existing(this);
|
||||||
@ -86,6 +102,10 @@ export abstract class Character extends Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getOutlinePlugin(): OutlinePipelinePlugin|undefined {
|
||||||
|
return this.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
||||||
if (typeof texturePromise !== 'undefined') {
|
if (typeof texturePromise !== 'undefined') {
|
||||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||||
|
@ -69,6 +69,10 @@ export abstract class DirtyScene extends ResizableScene {
|
|||||||
return this.dirty || this.objectListChanged;
|
return this.dirty || this.objectListChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public markDirty(): void {
|
||||||
|
this.events.once(Phaser.Scenes.Events.POST_UPDATE, () => this.dirty = true);
|
||||||
|
}
|
||||||
|
|
||||||
public onResize(): void {
|
public onResize(): void {
|
||||||
this.objectListChanged = true;
|
this.objectListChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,6 @@ import {connectionManager} from "../../Connexion/ConnectionManager";
|
|||||||
import type {RoomConnection} from "../../Connexion/RoomConnection";
|
import type {RoomConnection} from "../../Connexion/RoomConnection";
|
||||||
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
import {GlobalMessageManager} from "../../Administration/GlobalMessageManager";
|
||||||
import {userMessageManager} from "../../Administration/UserMessageManager";
|
import {userMessageManager} from "../../Administration/UserMessageManager";
|
||||||
import {ConsoleGlobalMessageManager} from "../../Administration/ConsoleGlobalMessageManager";
|
|
||||||
import {ResizableScene} from "../Login/ResizableScene";
|
import {ResizableScene} from "../Login/ResizableScene";
|
||||||
import {Room} from "../../Connexion/Room";
|
import {Room} from "../../Connexion/Room";
|
||||||
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
|
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
|
||||||
@ -96,6 +95,8 @@ import {waScaleManager} from "../Services/WaScaleManager";
|
|||||||
import {peerStore} from "../../Stores/PeerStore";
|
import {peerStore} from "../../Stores/PeerStore";
|
||||||
import {EmoteManager} from "./EmoteManager";
|
import {EmoteManager} from "./EmoteManager";
|
||||||
|
|
||||||
|
import AnimatedTiles from "phaser-animated-tiles";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface|null,
|
initPosition: PointInterface|null,
|
||||||
reconnecting: boolean
|
reconnecting: boolean
|
||||||
@ -142,6 +143,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
Layers!: Array<Phaser.Tilemaps.TilemapLayer>;
|
Layers!: Array<Phaser.Tilemaps.TilemapLayer>;
|
||||||
Objects!: Array<Phaser.Physics.Arcade.Sprite>;
|
Objects!: Array<Phaser.Physics.Arcade.Sprite>;
|
||||||
mapFile!: ITiledMap;
|
mapFile!: ITiledMap;
|
||||||
|
animatedTiles!: AnimatedTiles;
|
||||||
groups: Map<number, Sprite>;
|
groups: Map<number, Sprite>;
|
||||||
startX!: number;
|
startX!: number;
|
||||||
startY!: number;
|
startY!: number;
|
||||||
@ -153,7 +155,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
public connection: RoomConnection|undefined;
|
public connection: RoomConnection|undefined;
|
||||||
private simplePeer!: SimplePeer;
|
private simplePeer!: SimplePeer;
|
||||||
private GlobalMessageManager!: GlobalMessageManager;
|
private GlobalMessageManager!: GlobalMessageManager;
|
||||||
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
|
|
||||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||||
private connectionAnswerPromiseResolve!: (value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
private connectionAnswerPromiseResolve!: (value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
||||||
// A promise that will resolve when the "create" method is called (signaling loading is ended)
|
// A promise that will resolve when the "create" method is called (signaling loading is ended)
|
||||||
@ -266,6 +267,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
message: this.originalMapUrl ?? file.src
|
message: this.originalMapUrl ?? file.src
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
this.load.scenePlugin('AnimatedTiles', AnimatedTiles, 'animatedTiles', 'animatedTiles');
|
||||||
this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => {
|
this.load.on('filecomplete-tilemapJSON-'+this.MapUrlFile, (key: string, type: string, data: unknown) => {
|
||||||
this.onMapLoad(data);
|
this.onMapLoad(data);
|
||||||
});
|
});
|
||||||
@ -479,6 +481,9 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
|
|
||||||
this.initCamera();
|
this.initCamera();
|
||||||
|
|
||||||
|
this.animatedTiles.init(this.Map);
|
||||||
|
this.events.on('tileanimationupdate', () => this.dirty = true);
|
||||||
|
|
||||||
this.initCirclesCanvas();
|
this.initCirclesCanvas();
|
||||||
|
|
||||||
// Let's pause the scene if the connection is not established yet
|
// Let's pause the scene if the connection is not established yet
|
||||||
@ -682,7 +687,6 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||||||
//this.initUsersPosition(roomJoinedMessage.users);
|
//this.initUsersPosition(roomJoinedMessage.users);
|
||||||
this.connectionAnswerPromiseResolve(onConnect.room);
|
this.connectionAnswerPromiseResolve(onConnect.room);
|
||||||
// Analyze tags to find if we are admin. If yes, show console.
|
// Analyze tags to find if we are admin. If yes, show console.
|
||||||
this.ConsoleGlobalMessageManager = new ConsoleGlobalMessageManager(this.connection, this.userInputManager, this.connection.isAdmin());
|
|
||||||
|
|
||||||
|
|
||||||
this.scene.wake();
|
this.scene.wake();
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
* It has coordinates and an "activation radius"
|
* It has coordinates and an "activation radius"
|
||||||
*/
|
*/
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
import {OutlinePipeline} from "../Shaders/OutlinePipeline";
|
|
||||||
import type {GameScene} from "../Game/GameScene";
|
import type {GameScene} from "../Game/GameScene";
|
||||||
|
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||||
|
|
||||||
type EventCallback = (state: unknown, parameters: unknown) => void;
|
type EventCallback = (state: unknown, parameters: unknown) => void;
|
||||||
|
|
||||||
@ -42,11 +42,11 @@ export class ActionableItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.isSelectable = true;
|
this.isSelectable = true;
|
||||||
if (this.sprite.pipeline) {
|
|
||||||
// Commented out to try to fix MacOS issue
|
this.getOutlinePlugin()?.add(this.sprite, {
|
||||||
/*this.sprite.setPipeline(OutlinePipeline.KEY);
|
thickness: 2,
|
||||||
this.sprite.pipeline.set2f('uTextureSize', this.sprite.texture.getSourceImage().width, this.sprite.texture.getSourceImage().height);*/
|
outlineColor: 0xffff00
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,8 +57,11 @@ export class ActionableItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.isSelectable = false;
|
this.isSelectable = false;
|
||||||
// Commented out to try to fix MacOS issue
|
this.getOutlinePlugin()?.remove(this.sprite);
|
||||||
//this.sprite.resetPipeline();
|
}
|
||||||
|
|
||||||
|
private getOutlinePlugin(): OutlinePipelinePlugin|undefined {
|
||||||
|
return this.sprite.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,6 +11,8 @@ import {WarningContainer, warningContainerHtml, warningContainerKey} from "../Co
|
|||||||
import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream";
|
import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream";
|
||||||
import {menuIconVisible} from "../../Stores/MenuStore";
|
import {menuIconVisible} from "../../Stores/MenuStore";
|
||||||
import {videoConstraintStore} from "../../Stores/MediaStore";
|
import {videoConstraintStore} from "../../Stores/MediaStore";
|
||||||
|
import {consoleGlobalMessageManagerVisibleStore} from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||||
|
import {get} from "svelte/store";
|
||||||
|
|
||||||
export const MenuSceneName = 'MenuScene';
|
export const MenuSceneName = 'MenuScene';
|
||||||
const gameMenuKey = 'gameMenu';
|
const gameMenuKey = 'gameMenu';
|
||||||
@ -159,7 +161,7 @@ export class MenuScene extends Phaser.Scene {
|
|||||||
this.sideMenuOpened = false;
|
this.sideMenuOpened = false;
|
||||||
this.closeAll();
|
this.closeAll();
|
||||||
this.menuButton.getChildByID('openMenuButton').innerHTML = `<img src="/static/images/menu.svg">`;
|
this.menuButton.getChildByID('openMenuButton').innerHTML = `<img src="/static/images/menu.svg">`;
|
||||||
gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.disabledMessageConsole();
|
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||||
this.tweens.add({
|
this.tweens.add({
|
||||||
targets: this.menuElement,
|
targets: this.menuElement,
|
||||||
x: closedSideMenuX,
|
x: closedSideMenuX,
|
||||||
@ -304,7 +306,11 @@ export class MenuScene extends Phaser.Scene {
|
|||||||
this.toggleFullscreen();
|
this.toggleFullscreen();
|
||||||
break;
|
break;
|
||||||
case 'adminConsoleButton':
|
case 'adminConsoleButton':
|
||||||
gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.activeMessageConsole();
|
if (get(consoleGlobalMessageManagerVisibleStore)) {
|
||||||
|
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||||
|
} else {
|
||||||
|
consoleGlobalMessageManagerVisibleStore.set(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
export class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline {
|
|
||||||
|
|
||||||
// the unique id of this pipeline
|
|
||||||
public static readonly KEY = 'Outline';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Phaser.Game} game - the controller of the game instance
|
|
||||||
*/
|
|
||||||
constructor(game: Phaser.Game)
|
|
||||||
{
|
|
||||||
super({
|
|
||||||
game: game,
|
|
||||||
fragShader: `
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
uniform sampler2D uMainSampler;
|
|
||||||
uniform vec2 uTextureSize;
|
|
||||||
|
|
||||||
varying vec2 outTexCoord;
|
|
||||||
varying float outTintEffect;
|
|
||||||
varying vec4 outTint;
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
vec4 texture = texture2D(uMainSampler, outTexCoord);
|
|
||||||
vec4 texel = vec4(outTint.rgb * outTint.a, outTint.a);
|
|
||||||
vec4 color = texture;
|
|
||||||
|
|
||||||
if (outTintEffect == 0.0)
|
|
||||||
{
|
|
||||||
color = texture * texel;
|
|
||||||
}
|
|
||||||
else if (outTintEffect == 1.0)
|
|
||||||
{
|
|
||||||
color.rgb = mix(texture.rgb, outTint.rgb * outTint.a, texture.a);
|
|
||||||
color.a = texture.a * texel.a;
|
|
||||||
}
|
|
||||||
else if (outTintEffect == 2.0)
|
|
||||||
{
|
|
||||||
color = texel;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 onePixel = vec2(1.0, 1.0) / uTextureSize;
|
|
||||||
float upAlpha = texture2D(uMainSampler, outTexCoord + vec2(0.0, onePixel.y)).a;
|
|
||||||
float leftAlpha = texture2D(uMainSampler, outTexCoord + vec2(-onePixel.x, 0.0)).a;
|
|
||||||
float downAlpha = texture2D(uMainSampler, outTexCoord + vec2(0.0, -onePixel.y)).a;
|
|
||||||
float rightAlpha = texture2D(uMainSampler, outTexCoord + vec2(onePixel.x, 0.0)).a;
|
|
||||||
|
|
||||||
if (texture.a == 0.0 && max(max(upAlpha, downAlpha), max(leftAlpha, rightAlpha)) == 1.0)
|
|
||||||
{
|
|
||||||
color = vec4(1.0, 1.0, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_FragColor = color;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ import type { Direction } from "../../types";
|
|||||||
import type {GameScene} from "../Game/GameScene";
|
import type {GameScene} from "../Game/GameScene";
|
||||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||||
import {MobileJoystick} from "../Components/MobileJoystick";
|
import {MobileJoystick} from "../Components/MobileJoystick";
|
||||||
|
import {enableUserInputsStore} from "../../Stores/UserInputStore";
|
||||||
|
|
||||||
interface UserInputManagerDatum {
|
interface UserInputManagerDatum {
|
||||||
keyInstance: Phaser.Input.Keyboard.Key;
|
keyInstance: Phaser.Input.Keyboard.Key;
|
||||||
@ -58,6 +59,10 @@ export class UserInputManager {
|
|||||||
if (touchScreenManager.supportTouchScreen) {
|
if (touchScreenManager.supportTouchScreen) {
|
||||||
this.initVirtualJoystick();
|
this.initVirtualJoystick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableUserInputsStore.subscribe((enable) => {
|
||||||
|
enable ? this.restoreControls() : this.disableControls()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
initVirtualJoystick() {
|
initVirtualJoystick() {
|
||||||
|
5
front/src/Stores/ConsoleGlobalMessageManagerStore.ts
Normal file
5
front/src/Stores/ConsoleGlobalMessageManagerStore.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const consoleGlobalMessageManagerVisibleStore = writable(false);
|
||||||
|
|
||||||
|
export const consoleGlobalMessageManagerFocusStore = writable(false);
|
10
front/src/Stores/UserInputStore.ts
Normal file
10
front/src/Stores/UserInputStore.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import {derived} from "svelte/store";
|
||||||
|
import {consoleGlobalMessageManagerFocusStore} from "./ConsoleGlobalMessageManagerStore";
|
||||||
|
|
||||||
|
//derived from the focus on Menu, ConsoleGlobal, Chat and ...
|
||||||
|
export const enableUserInputsStore = derived(
|
||||||
|
consoleGlobalMessageManagerFocusStore,
|
||||||
|
($consoleGlobalMessageManagerFocusStore) => {
|
||||||
|
return !$consoleGlobalMessageManagerFocusStore;
|
||||||
|
}
|
||||||
|
);
|
@ -1,286 +1,175 @@
|
|||||||
import type { ChatEvent } from "./Api/Events/ChatEvent";
|
import {registeredCallbacks} from "./Api/iframe/registeredCallbacks";
|
||||||
import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent";
|
import {
|
||||||
import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent";
|
IframeResponseEvent,
|
||||||
import { Subject } from "rxjs";
|
IframeResponseEventMap,
|
||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent";
|
isIframeResponseEventWrapper,
|
||||||
import type { OpenPopupEvent } from "./Api/Events/OpenPopupEvent";
|
TypedMessageEvent
|
||||||
import { isButtonClickedEvent } from "./Api/Events/ButtonClickedEvent";
|
} from "./Api/Events/IframeEvent";
|
||||||
import type { ClosePopupEvent } from "./Api/Events/ClosePopupEvent";
|
import chat from "./Api/iframe/chat";
|
||||||
import type { OpenTabEvent } from "./Api/Events/OpenTabEvent";
|
import type {IframeCallback} from './Api/iframe/IframeApiContribution';
|
||||||
import type { GoToPageEvent } from "./Api/Events/GoToPageEvent";
|
import nav from "./Api/iframe/nav";
|
||||||
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
import controls from "./Api/iframe/controls";
|
||||||
import type { PlaySoundEvent } from "./Api/Events/PlaySoundEvent";
|
import ui from "./Api/iframe/ui";
|
||||||
import type { StopSoundEvent } from "./Api/Events/StopSoundEvent";
|
import sound from "./Api/iframe/sound";
|
||||||
import type { LoadSoundEvent } from "./Api/Events/LoadSoundEvent";
|
import room from "./Api/iframe/room";
|
||||||
import SoundConfig = Phaser.Types.Sound.SoundConfig;
|
import type {ButtonDescriptor} from "./Api/iframe/Ui/ButtonDescriptor";
|
||||||
import type { LoadPageEvent } from './Api/Events/LoadPageEvent';
|
import type {Popup} from "./Api/iframe/Ui/Popup";
|
||||||
|
import type {Sound} from "./Api/iframe/Sound/Sound";
|
||||||
|
|
||||||
interface WorkAdventureApi {
|
const wa = {
|
||||||
sendChatMessage(message: string, author: string): void;
|
ui,
|
||||||
onChatMessage(callback: (message: string) => void): void;
|
nav,
|
||||||
onEnterZone(name: string, callback: () => void): void;
|
controls,
|
||||||
onLeaveZone(name: string, callback: () => void): void;
|
chat,
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup;
|
sound,
|
||||||
openTab(url: string): void;
|
room,
|
||||||
goToPage(url: string): void;
|
|
||||||
goToRoom(url: string): void;
|
// All methods below are deprecated and should not be used anymore.
|
||||||
openCoWebSite(url: string): void;
|
// They are kept here for backward compatibility.
|
||||||
closeCoWebSite(): void;
|
|
||||||
disablePlayerControls(): void;
|
/**
|
||||||
restorePlayerControls(): void;
|
* @deprecated Use WA.chat.sendChatMessage instead
|
||||||
displayBubble(): void;
|
*/
|
||||||
removeBubble(): void;
|
sendChatMessage(message: string, author: string): void {
|
||||||
loadSound(url : string): Sound;
|
console.warn('Method WA.sendChatMessage is deprecated. Please use WA.chat.sendChatMessage instead');
|
||||||
}
|
chat.sendChatMessage(message, author);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.chat.disablePlayerControls instead
|
||||||
|
*/
|
||||||
|
disablePlayerControls(): void {
|
||||||
|
console.warn('Method WA.disablePlayerControls is deprecated. Please use WA.controls.disablePlayerControls instead');
|
||||||
|
controls.disablePlayerControls();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.controls.restorePlayerControls instead
|
||||||
|
*/
|
||||||
|
restorePlayerControls(): void {
|
||||||
|
console.warn('Method WA.restorePlayerControls is deprecated. Please use WA.controls.restorePlayerControls instead');
|
||||||
|
controls.restorePlayerControls();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.ui.displayBubble instead
|
||||||
|
*/
|
||||||
|
displayBubble(): void {
|
||||||
|
console.warn('Method WA.displayBubble is deprecated. Please use WA.ui.displayBubble instead');
|
||||||
|
ui.displayBubble();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.ui.removeBubble instead
|
||||||
|
*/
|
||||||
|
removeBubble(): void {
|
||||||
|
console.warn('Method WA.removeBubble is deprecated. Please use WA.ui.removeBubble instead');
|
||||||
|
ui.removeBubble();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.nav.openTab instead
|
||||||
|
*/
|
||||||
|
openTab(url: string): void {
|
||||||
|
console.warn('Method WA.openTab is deprecated. Please use WA.nav.openTab instead');
|
||||||
|
nav.openTab(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.sound.loadSound instead
|
||||||
|
*/
|
||||||
|
loadSound(url: string) : Sound {
|
||||||
|
console.warn('Method WA.loadSound is deprecated. Please use WA.sound.loadSound instead');
|
||||||
|
return sound.loadSound(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.nav.goToPage instead
|
||||||
|
*/
|
||||||
|
goToPage(url : string) : void {
|
||||||
|
console.warn('Method WA.goToPage is deprecated. Please use WA.nav.goToPage instead');
|
||||||
|
nav.goToPage(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.nav.goToRoom instead
|
||||||
|
*/
|
||||||
|
goToRoom(url: string): void {
|
||||||
|
console.warn('Method WA.goToRoom is deprecated. Please use WA.nav.goToRoom instead');
|
||||||
|
nav.goToRoom(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.nav.openCoWebSite instead
|
||||||
|
*/
|
||||||
|
openCoWebSite(url : string) : void{
|
||||||
|
console.warn('Method WA.openCoWebSite is deprecated. Please use WA.nav.openCoWebSite instead');
|
||||||
|
nav.openCoWebSite(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.nav.closeCoWebSite instead
|
||||||
|
*/
|
||||||
|
closeCoWebSite(): void {
|
||||||
|
console.warn('Method WA.closeCoWebSite is deprecated. Please use WA.nav.closeCoWebSite instead');
|
||||||
|
nav.closeCoWebSite();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.controls.restorePlayerControls instead
|
||||||
|
*/
|
||||||
|
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||||
|
console.warn('Method WA.openPopup is deprecated. Please use WA.ui.openPopup instead');
|
||||||
|
return ui.openPopup(targetObject, message, buttons);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.chat.onChatMessage instead
|
||||||
|
*/
|
||||||
|
onChatMessage(callback: (message: string) => void): void {
|
||||||
|
console.warn('Method WA.onChatMessage is deprecated. Please use WA.chat.onChatMessage instead');
|
||||||
|
chat.onChatMessage(callback);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.room.onEnterZone instead
|
||||||
|
*/
|
||||||
|
onEnterZone(name: string, callback: () => void): void {
|
||||||
|
console.warn('Method WA.onEnterZone is deprecated. Please use WA.room.onEnterZone instead');
|
||||||
|
room.onEnterZone(name, callback);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @deprecated Use WA.room.onLeaveZone instead
|
||||||
|
*/
|
||||||
|
onLeaveZone(name: string, callback: () => void): void {
|
||||||
|
console.warn('Method WA.onLeaveZone is deprecated. Please use WA.room.onLeaveZone instead');
|
||||||
|
room.onLeaveZone(name, callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkAdventureApi = typeof wa;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line no-var
|
|
||||||
var WA: WorkAdventureApi
|
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
WA: WorkAdventureApi
|
||||||
|
}
|
||||||
|
let WA: WorkAdventureApi
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatMessageCallback = (message: string) => void;
|
window.WA = wa;
|
||||||
type ButtonClickedCallback = (popup: Popup) => void;
|
|
||||||
|
|
||||||
const userInputChatStream: Subject<UserInputChatEvent> = new Subject();
|
window.addEventListener('message', <T extends keyof IframeResponseEventMap>(message: TypedMessageEvent<IframeResponseEvent<T>>) => {
|
||||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
|
||||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
|
||||||
const popups: Map<number, Popup> = new Map<number, Popup>();
|
|
||||||
const popupCallbacks: Map<number, Map<number, ButtonClickedCallback>> = new Map<number, Map<number, ButtonClickedCallback>>();
|
|
||||||
|
|
||||||
let popupId = 0;
|
|
||||||
interface ButtonDescriptor {
|
|
||||||
/**
|
|
||||||
* The label of the button
|
|
||||||
*/
|
|
||||||
label: string,
|
|
||||||
/**
|
|
||||||
* The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled"
|
|
||||||
*/
|
|
||||||
className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled",
|
|
||||||
/**
|
|
||||||
* Callback called if the button is pressed
|
|
||||||
*/
|
|
||||||
callback: ButtonClickedCallback,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Popup {
|
|
||||||
constructor(private id: number) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the popup
|
|
||||||
*/
|
|
||||||
public close(): void {
|
|
||||||
window.parent.postMessage({
|
|
||||||
'type': 'closePopup',
|
|
||||||
'data': {
|
|
||||||
'popupId': this.id,
|
|
||||||
} as ClosePopupEvent
|
|
||||||
}, '*');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Sound {
|
|
||||||
constructor(private url: string) {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type" : 'loadSound',
|
|
||||||
"data": {
|
|
||||||
url: this.url,
|
|
||||||
} as LoadSoundEvent
|
|
||||||
|
|
||||||
},'*');
|
|
||||||
}
|
|
||||||
|
|
||||||
public play(config : SoundConfig) {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type" : 'playSound',
|
|
||||||
"data": {
|
|
||||||
url: this.url,
|
|
||||||
config
|
|
||||||
} as PlaySoundEvent
|
|
||||||
|
|
||||||
},'*');
|
|
||||||
return this.url;
|
|
||||||
}
|
|
||||||
public stop() {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type" : 'stopSound',
|
|
||||||
"data": {
|
|
||||||
url: this.url,
|
|
||||||
} as StopSoundEvent
|
|
||||||
|
|
||||||
},'*');
|
|
||||||
return this.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
window.WA = {
|
|
||||||
/**
|
|
||||||
* Send a message in the chat.
|
|
||||||
* Only the local user will receive this message.
|
|
||||||
*/
|
|
||||||
sendChatMessage(message: string, author: string) {
|
|
||||||
window.parent.postMessage({
|
|
||||||
'type': 'chat',
|
|
||||||
'data': {
|
|
||||||
'message': message,
|
|
||||||
'author': author
|
|
||||||
} as ChatEvent
|
|
||||||
}, '*');
|
|
||||||
},
|
|
||||||
disablePlayerControls(): void {
|
|
||||||
window.parent.postMessage({ 'type': 'disablePlayerControls' }, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
restorePlayerControls(): void {
|
|
||||||
window.parent.postMessage({ 'type': 'restorePlayerControls' }, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
displayBubble(): void {
|
|
||||||
window.parent.postMessage({ 'type': 'displayBubble' }, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
removeBubble(): void {
|
|
||||||
window.parent.postMessage({ 'type': 'removeBubble' }, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
openTab(url: string): void {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type": 'openTab',
|
|
||||||
"data": {
|
|
||||||
url
|
|
||||||
} as OpenTabEvent
|
|
||||||
}, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
loadSound(url: string) : Sound {
|
|
||||||
return new Sound(url);
|
|
||||||
},
|
|
||||||
|
|
||||||
goToPage(url : string) : void{
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type": 'goToPage',
|
|
||||||
"data": {
|
|
||||||
url
|
|
||||||
} as GoToPageEvent
|
|
||||||
}, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
goToRoom(url: string): void {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type" : 'loadPage',
|
|
||||||
"data" : {
|
|
||||||
url
|
|
||||||
} as LoadPageEvent
|
|
||||||
},'*');
|
|
||||||
},
|
|
||||||
|
|
||||||
openCoWebSite(url : string) : void{
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type" : 'openCoWebSite',
|
|
||||||
"data" : {
|
|
||||||
url
|
|
||||||
} as OpenCoWebSiteEvent
|
|
||||||
}, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
closeCoWebSite(): void {
|
|
||||||
window.parent.postMessage({
|
|
||||||
"type": 'closeCoWebSite'
|
|
||||||
}, '*');
|
|
||||||
},
|
|
||||||
|
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
|
||||||
popupId++;
|
|
||||||
const popup = new Popup(popupId);
|
|
||||||
const btnMap = new Map<number, () => void>();
|
|
||||||
popupCallbacks.set(popupId, btnMap);
|
|
||||||
let id = 0;
|
|
||||||
for (const button of buttons) {
|
|
||||||
const callback = button.callback;
|
|
||||||
if (callback) {
|
|
||||||
btnMap.set(id, () => {
|
|
||||||
callback(popup);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
window.parent.postMessage({
|
|
||||||
'type': 'openPopup',
|
|
||||||
'data': {
|
|
||||||
popupId,
|
|
||||||
targetObject,
|
|
||||||
message,
|
|
||||||
buttons: buttons.map((button) => {
|
|
||||||
return {
|
|
||||||
label: button.label,
|
|
||||||
className: button.className
|
|
||||||
};
|
|
||||||
})
|
|
||||||
} as OpenPopupEvent
|
|
||||||
}, '*');
|
|
||||||
|
|
||||||
popups.set(popupId, popup)
|
|
||||||
return popup;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Listen to messages sent by the local user, in the chat.
|
|
||||||
*/
|
|
||||||
onChatMessage(callback: ChatMessageCallback): void {
|
|
||||||
userInputChatStream.subscribe((userInputChatEvent) => {
|
|
||||||
callback(userInputChatEvent.message);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onEnterZone(name: string, callback: () => void): void {
|
|
||||||
let subject = enterStreams.get(name);
|
|
||||||
if (subject === undefined) {
|
|
||||||
subject = new Subject<EnterLeaveEvent>();
|
|
||||||
enterStreams.set(name, subject);
|
|
||||||
}
|
|
||||||
subject.subscribe(callback);
|
|
||||||
},
|
|
||||||
onLeaveZone(name: string, callback: () => void): void {
|
|
||||||
let subject = leaveStreams.get(name);
|
|
||||||
if (subject === undefined) {
|
|
||||||
subject = new Subject<EnterLeaveEvent>();
|
|
||||||
leaveStreams.set(name, subject);
|
|
||||||
}
|
|
||||||
subject.subscribe(callback);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('message', message => {
|
|
||||||
if (message.source !== window.parent) {
|
if (message.source !== window.parent) {
|
||||||
return; // Skip message in this event listener
|
return; // Skip message in this event listener
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = message.data;
|
const payload = message.data;
|
||||||
|
|
||||||
console.debug(payload);
|
console.debug(payload);
|
||||||
|
|
||||||
if (isIframeResponseEventWrapper(payload)) {
|
if (isIframeResponseEventWrapper(payload)) {
|
||||||
const payloadData = payload.data;
|
const payloadData = payload.data;
|
||||||
if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) {
|
|
||||||
userInputChatStream.next(payloadData);
|
|
||||||
} else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) {
|
|
||||||
enterStreams.get(payloadData.name)?.next();
|
|
||||||
} else if (payload.type === 'leaveEvent' && isEnterLeaveEvent(payloadData)) {
|
|
||||||
leaveStreams.get(payloadData.name)?.next();
|
|
||||||
} else if (payload.type === 'buttonClickedEvent' && isButtonClickedEvent(payloadData)) {
|
|
||||||
const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId);
|
|
||||||
const popup = popups.get(payloadData.popupId);
|
|
||||||
if (popup === undefined) {
|
|
||||||
throw new Error('Could not find popup with ID "' + payloadData.popupId + '"');
|
|
||||||
}
|
|
||||||
if (callback) {
|
|
||||||
callback(popup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const callback = registeredCallbacks[payload.type] as IframeCallback<T> | undefined
|
||||||
|
if (callback?.typeChecker(payloadData)) {
|
||||||
|
callback?.callback(payloadData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
@ -10,6 +10,7 @@ import {SelectCompanionScene} from "./Phaser/Login/SelectCompanionScene";
|
|||||||
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
|
import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene";
|
||||||
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
|
||||||
import WebFontLoaderPlugin from 'phaser3-rex-plugins/plugins/webfontloader-plugin.js';
|
import WebFontLoaderPlugin from 'phaser3-rex-plugins/plugins/webfontloader-plugin.js';
|
||||||
|
import OutlinePipelinePlugin from 'phaser3-rex-plugins/plugins/outlinepipeline-plugin.js';
|
||||||
import {EntryScene} from "./Phaser/Login/EntryScene";
|
import {EntryScene} from "./Phaser/Login/EntryScene";
|
||||||
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
|
||||||
import {MenuScene} from "./Phaser/Menu/MenuScene";
|
import {MenuScene} from "./Phaser/Menu/MenuScene";
|
||||||
@ -22,6 +23,8 @@ import {waScaleManager} from "./Phaser/Services/WaScaleManager";
|
|||||||
import {Game} from "./Phaser/Game/Game";
|
import {Game} from "./Phaser/Game/Game";
|
||||||
import App from './Components/App.svelte';
|
import App from './Components/App.svelte';
|
||||||
import {HtmlUtils} from "./WebRtc/HtmlUtils";
|
import {HtmlUtils} from "./WebRtc/HtmlUtils";
|
||||||
|
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
||||||
|
|
||||||
|
|
||||||
const {width, height} = coWebsiteManager.getGameSize();
|
const {width, height} = coWebsiteManager.getGameSize();
|
||||||
|
|
||||||
@ -123,11 +126,11 @@ const config: GameConfig = {
|
|||||||
powerPreference: "low-power",
|
powerPreference: "low-power",
|
||||||
callbacks: {
|
callbacks: {
|
||||||
postBoot: game => {
|
postBoot: game => {
|
||||||
// Commented out to try to fix MacOS bug
|
// Install rexOutlinePipeline only if the renderer is WebGL.
|
||||||
/*const renderer = game.renderer;
|
const renderer = game.renderer;
|
||||||
if (renderer instanceof WebGLRenderer) {
|
if (renderer instanceof WebGLRenderer) {
|
||||||
renderer.pipelines.add(OutlinePipeline.KEY, new OutlinePipeline(game));
|
game.plugins.install('rexOutlinePipeline', OutlinePipelinePlugin, true);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
12
front/src/rex-plugins.d.ts
vendored
12
front/src/rex-plugins.d.ts
vendored
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
declare module 'phaser3-rex-plugins/plugins/virtualjoystick.js' {
|
declare module 'phaser3-rex-plugins/plugins/virtualjoystick.js' {
|
||||||
const content: any; // eslint-disable-line
|
const content: any; // eslint-disable-line
|
||||||
export default content;
|
export default content;
|
||||||
@ -11,6 +10,17 @@ declare module 'phaser3-rex-plugins/plugins/webfontloader-plugin.js' {
|
|||||||
const content: any; // eslint-disable-line
|
const content: any; // eslint-disable-line
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
declare module 'phaser3-rex-plugins/plugins/outlinepipeline-plugin.js' {
|
||||||
|
import GameObject = Phaser.GameObjects.GameObject;
|
||||||
|
|
||||||
|
class OutlinePipelinePlugin {
|
||||||
|
add(gameObject: GameObject, config: object);
|
||||||
|
|
||||||
|
remove(gameObject: GameObject, name?: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OutlinePipelinePlugin;
|
||||||
|
}
|
||||||
declare module 'phaser3-rex-plugins/plugins/gestures.js' {
|
declare module 'phaser3-rex-plugins/plugins/gestures.js' {
|
||||||
export const Pinch: any; // eslint-disable-line
|
export const Pinch: any; // eslint-disable-line
|
||||||
}
|
}
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
@import "style";
|
@import "style";
|
||||||
@import "mobile-style.scss";
|
@import "mobile-style.scss";
|
||||||
@import "fonts.scss";
|
@import "fonts.scss";
|
||||||
|
@import "svelte-style.scss";
|
||||||
|
@ -627,17 +627,15 @@ input[type=range]:focus::-ms-fill-upper {
|
|||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*CONSOLE*/
|
/*GLOBAL MESSAGE*/
|
||||||
|
.message-container {
|
||||||
.message-container,
|
|
||||||
.main-console{
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
top: -80%;
|
top: -80%;
|
||||||
/*left: 10%;*/
|
//left: 10%;
|
||||||
left: 250px;
|
left: 250px;
|
||||||
background: #333333;
|
background: #333333;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
@ -660,7 +658,6 @@ input[type=range]:focus::-ms-fill-upper {
|
|||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.console,
|
|
||||||
.message-container div.clear {
|
.message-container div.clear {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
color: white;
|
color: white;
|
||||||
@ -675,22 +672,11 @@ input[type=range]:focus::-ms-fill-upper {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.message,
|
|
||||||
.main-console div.setting{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console div.message.active,
|
|
||||||
.main-console div.setting.active{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-container div.clear{
|
.message-container div.clear{
|
||||||
width: 100px;
|
width: 100px;
|
||||||
left: calc(50% - 50px);
|
left: calc(50% - 50px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.console img,
|
|
||||||
.message-container div.clear img{
|
.message-container div.clear img{
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
@ -701,112 +687,26 @@ input[type=range]:focus::-ms-fill-upper {
|
|||||||
transform: rotateY(0);
|
transform: rotateY(0);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
.main-console div.console img:hover,
|
|
||||||
.message-container div.clear img:hover{
|
.message-container div.clear img:hover{
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.console img.active,
|
|
||||||
.message-container div.clear img{
|
.message-container div.clear img{
|
||||||
transform: rotateY(3.142rad);
|
transform: rotateY(3.142rad);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.console p,
|
|
||||||
.message-container div.clear p{
|
.message-container div.clear p{
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console div.console:hover,
|
|
||||||
.message-container div.clear:hover {
|
.message-container div.clear:hover {
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||||
top: calc(100% + 5px);
|
top: calc(100% + 5px);
|
||||||
transform: scale(1.2) translateY(3px);
|
transform: scale(1.2) translateY(3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-console #input-send-text{
|
|
||||||
min-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console #input-send-text .ql-editor{
|
|
||||||
color: white;
|
|
||||||
min-height: 200px;
|
|
||||||
max-height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .ql-toolbar{
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .btn-action{
|
|
||||||
margin: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .btn-action .btn{
|
|
||||||
border: 1px solid black;
|
|
||||||
background-color: #00000000;
|
|
||||||
color: #ffda01;
|
|
||||||
border-radius: 15px;
|
|
||||||
padding: 10px 30px;
|
|
||||||
transition: all .2s ease;
|
|
||||||
}
|
|
||||||
.main-console .btn-action .btn:hover{
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
|
||||||
background-color: #ffda01;
|
|
||||||
color: black;
|
|
||||||
border: 1px solid black;
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .menu {
|
|
||||||
padding: 20px;
|
|
||||||
color: #ffffffa6;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .menu span {
|
|
||||||
margin: 20px;
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console .menu span.active {
|
|
||||||
color: white;
|
|
||||||
border-bottom: solid 1px white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console section{
|
|
||||||
text-align: center;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console section.active{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console section div.upload{
|
|
||||||
text-align: center;
|
|
||||||
border: solid 1px #ffda01;
|
|
||||||
height: 150px;
|
|
||||||
margin: 10px 200px;
|
|
||||||
padding: 20px;
|
|
||||||
min-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-console section div.upload label{
|
|
||||||
color: #ffda01;
|
|
||||||
}
|
|
||||||
.main-console section div.upload input{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.main-console section div.upload label img{
|
|
||||||
height: 150px;
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
|
||||||
}
|
|
||||||
.main-console section div.upload label img{
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* VIDEO QUALITY */
|
/* VIDEO QUALITY */
|
||||||
.main-console div.setting h1{
|
.main-console div.setting h1{
|
||||||
|
60
front/style/svelte-style.scss
Normal file
60
front/style/svelte-style.scss
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//Contains all styles not unique to a svelte component.
|
||||||
|
|
||||||
|
//ConsoleGlobalMessage
|
||||||
|
div.main-console.nes-container {
|
||||||
|
pointer-events: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
top: 20vh;
|
||||||
|
width: 50vw;
|
||||||
|
height: 50vh;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #333333;
|
||||||
|
|
||||||
|
.btn-action{
|
||||||
|
margin: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-global-message {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-global-message h2 {
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.global-message {
|
||||||
|
display: flex;
|
||||||
|
max-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu button {
|
||||||
|
margin: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-input {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
//InputTextGlobalMessage
|
||||||
|
.section-input-send-text {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-text .input-send-text .ql-editor{
|
||||||
|
color: white;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-input-send-text .ql-toolbar{
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
}
|
@ -1417,6 +1417,13 @@ create-require@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
|
cross-env@^7.0.3:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||||
|
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.1"
|
||||||
|
|
||||||
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||||
@ -1428,7 +1435,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
|||||||
shebang-command "^1.2.0"
|
shebang-command "^1.2.0"
|
||||||
which "^1.2.9"
|
which "^1.2.9"
|
||||||
|
|
||||||
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||||
@ -4091,6 +4098,10 @@ pbkdf2@^3.0.3:
|
|||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
sha.js "^2.4.8"
|
sha.js "^2.4.8"
|
||||||
|
|
||||||
|
phaser-animated-tiles@workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://codeload.github.com/workadventure/phaser-animated-tiles/tar.gz/da68bbededd605925621dd4f03bd27e69284b254"
|
||||||
|
|
||||||
phaser3-rex-plugins@^1.1.42:
|
phaser3-rex-plugins@^1.1.42:
|
||||||
version "1.1.47"
|
version "1.1.47"
|
||||||
resolved "https://registry.yarnpkg.com/phaser3-rex-plugins/-/phaser3-rex-plugins-1.1.47.tgz#89299369437a0032ad31c64e89a26d20fd8a5867"
|
resolved "https://registry.yarnpkg.com/phaser3-rex-plugins/-/phaser3-rex-plugins-1.1.47.tgz#89299369437a0032ad31c64e89a26d20fd8a5867"
|
||||||
|
120
maps/tests/animated_tiles.json
Normal file
120
maps/tests/animated_tiles.json
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":261.73266830836,
|
||||||
|
"id":3,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"color":"#ffffff",
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nOpen this page\n\nResult:\nThe water tileset should be animated",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":252.4375,
|
||||||
|
"x":46.5894222943362,
|
||||||
|
"y":34.2876372135732
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":8,
|
||||||
|
"nextobjectid":5,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":8,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"animated_tiles.png",
|
||||||
|
"imageheight":32,
|
||||||
|
"imagewidth":256,
|
||||||
|
"margin":0,
|
||||||
|
"name":"animated_tiles",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":8,
|
||||||
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"animation":[
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration":100,
|
||||||
|
"tileid":7
|
||||||
|
}],
|
||||||
|
"id":0
|
||||||
|
}],
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
BIN
maps/tests/animated_tiles.png
Normal file
BIN
maps/tests/animated_tiles.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
164
maps/tests/deprecated_functions.json
Normal file
164
maps/tests/deprecated_functions.json
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":10,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
|
"height":10,
|
||||||
|
"id":1,
|
||||||
|
"name":"floor",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":6,
|
||||||
|
"name":"triggerZone",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"zone",
|
||||||
|
"type":"string",
|
||||||
|
"value":"myTrigger"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":7,
|
||||||
|
"name":"popupZone",
|
||||||
|
"opacity":1,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"zone",
|
||||||
|
"type":"string",
|
||||||
|
"value":"popupZone"
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":147.135497146101,
|
||||||
|
"id":1,
|
||||||
|
"name":"myPopup2",
|
||||||
|
"rotation":0,
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":104.442827410047,
|
||||||
|
"x":142.817125079855,
|
||||||
|
"y":147.448134926559
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":132.434722966794,
|
||||||
|
"id":2,
|
||||||
|
"name":"myPopup1",
|
||||||
|
"rotation":0,
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":125.735549178518,
|
||||||
|
"x":13.649632619596,
|
||||||
|
"y":50.8502491249093
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":67,
|
||||||
|
"id":3,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nWalk on top carpet\nResult:\nA message \"Don't step on my carpet\" is displayed\nIn the console, deprecation warnings MUST be displayed",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":252.4375,
|
||||||
|
"x":2.78125,
|
||||||
|
"y":2.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":67,
|
||||||
|
"id":4,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nWalk on bottom carpet\nResult:\nA series of 2 popups open. A bubble opens. The player cannot move until popup closes.\nWhen the player leaves the zone, the bubble closes.\nIn the console, deprecation warnings MUST be displayed",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":252.438,
|
||||||
|
"x":-1.71899999999999,
|
||||||
|
"y":163.5
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":8,
|
||||||
|
"nextobjectid":5,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"script",
|
||||||
|
"type":"string",
|
||||||
|
"value":"deprecated_script.js"
|
||||||
|
}],
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
79
maps/tests/deprecated_script.js
Normal file
79
maps/tests/deprecated_script.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
console.log('SCRIPT LAUNCHED');
|
||||||
|
//WA.sendChatMessage('Hi, my name is Poly and I repeat what you say!', 'Poly Parrot');
|
||||||
|
var isFirstTimeTuto = false;
|
||||||
|
var textFirstPopup = 'Hey ! This is how to open start a discussion with someone ! You can be 4 max in a booble';
|
||||||
|
var textSecondPopup = 'You can also use the chat to communicate ! ';
|
||||||
|
var targetObjectTutoBubble ='myPopup1';
|
||||||
|
var targetObjectTutoChat ='myPopup2';
|
||||||
|
var popUpExplanation = undefined;
|
||||||
|
function launchTuto (){
|
||||||
|
WA.openPopup(targetObjectTutoBubble, textFirstPopup, [
|
||||||
|
{
|
||||||
|
label: "Next",
|
||||||
|
className: "popUpElement",
|
||||||
|
callback: (popup) => {
|
||||||
|
popup.close();
|
||||||
|
|
||||||
|
WA.openPopup(targetObjectTutoChat, textSecondPopup, [
|
||||||
|
{
|
||||||
|
label: "Open Chat",
|
||||||
|
className: "popUpElement",
|
||||||
|
callback: (popup1) => {
|
||||||
|
WA.sendChatMessage("Hey you can talk here too ! ", 'WA Guide');
|
||||||
|
popup1.close();
|
||||||
|
WA.restorePlayerControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
WA.disablePlayerControls();
|
||||||
|
|
||||||
|
}
|
||||||
|
WA.onChatMessage((message => {
|
||||||
|
console.log('CHAT MESSAGE RECEIVED BY SCRIPT');
|
||||||
|
WA.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot');
|
||||||
|
}));
|
||||||
|
|
||||||
|
WA.onEnterZone('myTrigger', () => {
|
||||||
|
WA.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
|
||||||
|
})
|
||||||
|
|
||||||
|
WA.onLeaveZone('popupZone', () => {
|
||||||
|
})
|
||||||
|
|
||||||
|
WA.onEnterZone('notExist', () => {
|
||||||
|
WA.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot');
|
||||||
|
})
|
||||||
|
|
||||||
|
WA.onEnterZone('popupZone', () => {
|
||||||
|
WA.displayBubble();
|
||||||
|
if (!isFirstTimeTuto) {
|
||||||
|
isFirstTimeTuto = true;
|
||||||
|
launchTuto();
|
||||||
|
}
|
||||||
|
else popUpExplanation = WA.openPopup(targetObjectTutoChat,'Do you want to review the explanation ? ', [
|
||||||
|
{
|
||||||
|
label: "No",
|
||||||
|
className: "popUpElementReviewexplanation",
|
||||||
|
callback: (popup) => {
|
||||||
|
popup.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Yes",
|
||||||
|
className: "popUpElementReviewexplanation",
|
||||||
|
callback: (popup) => {
|
||||||
|
popup.close();
|
||||||
|
launchTuto();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
|
WA.onLeaveZone('popupZone', () => {
|
||||||
|
if (popUpExplanation !== undefined) popUpExplanation.close();
|
||||||
|
WA.removeBubble();
|
||||||
|
})
|
@ -42,12 +42,12 @@
|
|||||||
<a href="#" class="testLink" data-testmap="script_api.json" target="_blank">Testing scripting API with a script</a>
|
<a href="#" class="testLink" data-testmap="script_api.json" target="_blank">Testing scripting API with a script</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-scripting-api"> Success <input type="radio" name="test-scripting-api"> Failure <input type="radio" name="test-scripting-api" checked> Pending
|
<input type="radio" name="test-scripting-api-gotopage"> Success <input type="radio" name="test-scripting-api-gotopage"> Failure <input type="radio" name="test-scripting-api-gotopage" checked> Pending
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" class="testLink" data-testmap="goToPage.json" target="_blank">Testing scripting API with a script</a>
|
<a href="#" class="testLink" data-testmap="goToPage.json" target="_blank">Testing goToPage script Api</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -58,6 +58,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="SoundTest.json" target="_blank">Testing scripting API loadSound() function</a>
|
<a href="#" class="testLink" data-testmap="SoundTest.json" target="_blank">Testing scripting API loadSound() function</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-scripting-deprecated"> Success <input type="radio" name="test-scripting-deprecated"> Failure <input type="radio" name="test-scripting-deprecated" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="deprecated_functions.json" target="_blank">Testing scripting API deprecated function</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio" name="test-autoresize"> Success <input type="radio" name="test-autoresize"> Failure <input type="radio" name="test-autoresize" checked> Pending
|
<input type="radio" name="test-autoresize"> Success <input type="radio" name="test-autoresize"> Failure <input type="radio" name="test-autoresize" checked> Pending
|
||||||
@ -98,6 +106,14 @@
|
|||||||
<a href="#" class="testLink" data-testmap="help_camera_setting.json" target="_blank">Test the HelpCameraSettingScene</a>
|
<a href="#" class="testLink" data-testmap="help_camera_setting.json" target="_blank">Test the HelpCameraSettingScene</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="test-animated-tiles"> Success <input type="radio" name="test-animated-tiles"> Failure <input type="radio" name="test-animated-tiles" checked> Pending
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="testLink" data-testmap="animated_tiles.json" target="_blank">Test animated tiles</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -7,21 +7,21 @@ var targetObjectTutoBubble ='myPopup1';
|
|||||||
var targetObjectTutoChat ='myPopup2';
|
var targetObjectTutoChat ='myPopup2';
|
||||||
var popUpExplanation = undefined;
|
var popUpExplanation = undefined;
|
||||||
function launchTuto (){
|
function launchTuto (){
|
||||||
WA.openPopup(targetObjectTutoBubble, textFirstPopup, [
|
WA.ui.openPopup(targetObjectTutoBubble, textFirstPopup, [
|
||||||
{
|
{
|
||||||
label: "Next",
|
label: "Next",
|
||||||
className: "popUpElement",
|
className: "popUpElement",
|
||||||
callback: (popup) => {
|
callback: (popup) => {
|
||||||
popup.close();
|
popup.close();
|
||||||
|
|
||||||
WA.openPopup(targetObjectTutoChat, textSecondPopup, [
|
WA.ui.openPopup(targetObjectTutoChat, textSecondPopup, [
|
||||||
{
|
{
|
||||||
label: "Open Chat",
|
label: "Open Chat",
|
||||||
className: "popUpElement",
|
className: "popUpElement",
|
||||||
callback: (popup1) => {
|
callback: (popup1) => {
|
||||||
WA.sendChatMessage("Hey you can talk here too ! ", 'WA Guide');
|
WA.chat.sendChatMessage("Hey you can talk here too ! ", 'WA Guide');
|
||||||
popup1.close();
|
popup1.close();
|
||||||
WA.restorePlayerControls();
|
WA.controls.restorePlayerControls();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,32 +29,32 @@ function launchTuto (){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
WA.disablePlayerControls();
|
WA.controls.disablePlayerControls();
|
||||||
|
|
||||||
}
|
}
|
||||||
WA.onChatMessage((message => {
|
WA.chat.onChatMessage((message => {
|
||||||
console.log('CHAT MESSAGE RECEIVED BY SCRIPT');
|
console.log('CHAT MESSAGE RECEIVED BY SCRIPT');
|
||||||
WA.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot');
|
WA.chat.sendChatMessage('Poly Parrot says: "'+message+'"', 'Poly Parrot');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
WA.onEnterZone('myTrigger', () => {
|
WA.room.onEnterZone('myTrigger', () => {
|
||||||
WA.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
|
WA.chat.sendChatMessage("Don't step on my carpet!", 'Poly Parrot');
|
||||||
})
|
})
|
||||||
|
|
||||||
WA.onLeaveZone('popupZone', () => {
|
WA.room.onLeaveZone('popupZone', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
WA.onEnterZone('notExist', () => {
|
WA.room.onEnterZone('notExist', () => {
|
||||||
WA.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot');
|
WA.chat.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot');
|
||||||
})
|
})
|
||||||
|
|
||||||
WA.onEnterZone('popupZone', () => {
|
WA.room.onEnterZone('popupZone', () => {
|
||||||
WA.displayBubble();
|
WA.ui.displayBubble();
|
||||||
if (!isFirstTimeTuto) {
|
if (!isFirstTimeTuto) {
|
||||||
isFirstTimeTuto = true;
|
isFirstTimeTuto = true;
|
||||||
launchTuto();
|
launchTuto();
|
||||||
}
|
}
|
||||||
else popUpExplanation = WA.openPopup(targetObjectTutoChat,'Do you want to review the explanation ? ', [
|
else popUpExplanation = WA.ui.openPopup(targetObjectTutoChat,'Do you want to review the explanation ? ', [
|
||||||
{
|
{
|
||||||
label: "No",
|
label: "No",
|
||||||
className: "popUpElementReviewexplanation",
|
className: "popUpElementReviewexplanation",
|
||||||
@ -73,7 +73,7 @@ WA.onEnterZone('popupZone', () => {
|
|||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
||||||
WA.onLeaveZone('popupZone', () => {
|
WA.room.onLeaveZone('popupZone', () => {
|
||||||
if (popUpExplanation !== undefined) popUpExplanation.close();
|
if (popUpExplanation !== undefined) popUpExplanation.close();
|
||||||
WA.removeBubble();
|
WA.ui.removeBubble();
|
||||||
})
|
})
|
||||||
|
@ -3473,9 +3473,9 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
|
|||||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||||
|
|
||||||
set-getter@^0.1.0:
|
set-getter@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
|
resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.1.tgz#a3110e1b461d31a9cfc8c5c9ee2e9737ad447102"
|
||||||
integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=
|
integrity sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==
|
||||||
dependencies:
|
dependencies:
|
||||||
to-object-path "^0.3.0"
|
to-object-path "^0.3.0"
|
||||||
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
/dist/
|
|
||||||
/node_modules/
|
|
||||||
/dist/bundle.js
|
|
||||||
/yarn-error.log
|
|
||||||
/Dockerfile
|
|
Loading…
Reference in New Issue
Block a user