merged develop
@@ -55,7 +55,8 @@
|
|||||||
"query-string": "^6.13.3",
|
"query-string": "^6.13.3",
|
||||||
"redis": "^3.1.2",
|
"redis": "^3.1.2",
|
||||||
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
"uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0",
|
||||||
"uuidv4": "^6.0.7"
|
"uuidv4": "^6.0.7",
|
||||||
|
"zod": "^3.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/busboy": "^0.2.3",
|
"@types/busboy": "^0.2.3",
|
||||||
|
|||||||
@@ -2258,3 +2258,8 @@ yn@3.1.1:
|
|||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
|
|
||||||
|
zod@^3.12.0:
|
||||||
|
version "3.14.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.2.tgz#0b4ed79085c471adce0e7f2c0a4fbb5ddc516ba2"
|
||||||
|
integrity sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw==
|
||||||
|
|||||||
@@ -162,3 +162,34 @@ class ActionMessage {
|
|||||||
remove() {};
|
remove() {};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Adding custom ActionsMenu Action
|
||||||
|
|
||||||
|
When clicking on other player's WOKA, the contextual menu (we call it ActionsMenu) is displayed with some default Actions. It is possible to add custom actions right when player is clicked:
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<img src="images/actions-menu-1.png" class="figure-img img-fluid rounded" alt="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
To do that, we need to listen for the `onRemotePlayerClicked` stream and make use of the `remotePlayer` object that is passed by as a payload.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
WA.ui.onRemotePlayerClicked.subscribe((remotePlayer) => {
|
||||||
|
remotePlayer.addAction('Ask to tell a joke', () => {
|
||||||
|
console.log('I am NOT telling you a joke!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`remotePlayer.addAction(actionName, callback)` returns an Action object, which can remove itself from ActionsMenu:
|
||||||
|
```javascript
|
||||||
|
const action = remotePlayer.addAction('This will disappear!', () => {
|
||||||
|
console.log('You managed to click me!');
|
||||||
|
});
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
action.remove();
|
||||||
|
},
|
||||||
|
1000,
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|||||||
|
After Width: | Height: | Size: 6.9 KiB |
@@ -45,7 +45,7 @@ server {
|
|||||||
rewrite ^/jwt /index.html break;
|
rewrite ^/jwt /index.html break;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/[@_]/ {
|
location ~ ^/[@_*]/ {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
"simple-peer": "^9.11.0",
|
"simple-peer": "^9.11.0",
|
||||||
"socket.io-client": "^2.3.0",
|
"socket.io-client": "^2.3.0",
|
||||||
"standardized-audio-context": "^25.2.4",
|
"standardized-audio-context": "^25.2.4",
|
||||||
|
"ts-deferred": "^1.0.4",
|
||||||
"ts-proto": "^1.96.0",
|
"ts-proto": "^1.96.0",
|
||||||
"typesafe-i18n": "^2.59.0",
|
"typesafe-i18n": "^2.59.0",
|
||||||
"uuidv4": "^6.2.10",
|
"uuidv4": "^6.2.10",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg2985" version="1.1" inkscape:version="0.48.4 r9939" width="485.33627" height="485.33627" sodipodi:docname="600px-France_road_sign_B1j.svg[1].png">
|
|
||||||
<metadata id="metadata2991">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
|
||||||
<dc:title/>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<defs id="defs2989"/>
|
|
||||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1272" inkscape:window-height="745" id="namedview2987" showgrid="false" inkscape:snap-global="true" inkscape:snap-grids="true" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" inkscape:snap-smooth-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-object-midpoints="true" inkscape:snap-center="false" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:zoom="0.59970176" inkscape:cx="390.56499" inkscape:cy="244.34365" inkscape:window-x="86" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid type="xygrid" id="grid2995" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true" originx="-57.33186px" originy="-57.33186px"/>
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<g inkscape:groupmode="layer" id="layer1" inkscape:label="1" style="display:inline" transform="translate(-57.33186,-57.33186)">
|
|
||||||
<path sodipodi:type="arc" style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path2997" sodipodi:cx="300" sodipodi:cy="300" sodipodi:rx="240" sodipodi:ry="240" d="M 540,300 C 540,432.54834 432.54834,540 300,540 167.45166,540 60,432.54834 60,300 60,167.45166 167.45166,60 300,60 432.54834,60 540,167.45166 540,300 z" transform="matrix(1.0058783,0,0,1.0058783,-1.76349,-1.76349)"/>
|
|
||||||
<path sodipodi:type="arc" style="color:#000000;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4005" sodipodi:cx="304.75" sodipodi:cy="214.75" sodipodi:rx="44.75" sodipodi:ry="44.75" d="m 349.5,214.75 c 0,24.71474 -20.03526,44.75 -44.75,44.75 -24.71474,0 -44.75,-20.03526 -44.75,-44.75 0,-24.71474 20.03526,-44.75 44.75,-44.75 24.71474,0 44.75,20.03526 44.75,44.75 z" transform="matrix(5.1364411,0,0,5.1364411,-1265.3304,-803.05073)"/>
|
|
||||||
<rect style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect4001" width="345" height="80.599998" x="127.5" y="259.70001"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 111 KiB |
@@ -1,77 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 188.149 188.149" style="enable-background:new 0 0 188.149 188.149;" xml:space="preserve">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<defs>
|
|
||||||
<circle id="SVGID_1_" cx="94.075" cy="94.075" r="94.074"/>
|
|
||||||
</defs>
|
|
||||||
<use xlink:href="#SVGID_1_" style="overflow:visible;fill:#4AC8EB;"/>
|
|
||||||
<clipPath id="SVGID_2_">
|
|
||||||
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
|
|
||||||
</clipPath>
|
|
||||||
<g style="clip-path:url(#SVGID_2_);">
|
|
||||||
<path style="fill:#A57561;" d="M148.572,197.629v0.01H39.507v-0.01c0-15.124,6.147-28.809,16.09-38.679
|
|
||||||
c0.463-0.463,0.926-0.905,1.408-1.347c1.43-1.326,2.931-2.57,4.493-3.732c1.028-0.771,2.098-1.491,3.177-2.189
|
|
||||||
c1.08-0.699,2.19-1.357,3.331-1.975c0.021-0.021,0.042-0.021,0.042-0.021c0.441-0.247,0.873-0.493,1.306-0.761
|
|
||||||
c1.295-0.761,2.519-1.624,3.69-2.56c4.966-3.948,8.812-9.254,11.001-15.34v-0.011c1.306-3.629,2.016-7.546,2.016-11.639
|
|
||||||
l16.121,0.072c0,4.04,0.688,7.927,1.964,11.525c2.169,6.117,5.994,11.433,10.96,15.401c0.339,0.277,0.688,0.545,1.038,0.802
|
|
||||||
c0.483,0.36,0.977,0.71,1.47,1.039c0.37,0.246,0.751,0.493,1.132,0.72c0.421,0.257,0.853,0.514,1.285,0.75
|
|
||||||
c0.041,0.011,0.071,0.021,0.103,0.041c0.03,0.02,0.062,0.041,0.093,0.061c1.265,0.699,2.498,1.439,3.69,2.221
|
|
||||||
c0.401,0.258,0.802,0.524,1.192,0.803c0.515,0.37,1.039,0.74,1.543,1.131h0.021C139.966,163.875,148.572,179.729,148.572,197.629
|
|
||||||
z"/>
|
|
||||||
<path style="fill:#EB6D4A;" d="M148.572,197.629H39.507c0-15.124,6.147-28.809,16.09-38.679c0.463-0.463,0.926-0.905,1.408-1.347
|
|
||||||
c1.43-1.326,2.931-2.581,4.493-3.742c1.028-0.762,2.098-1.491,3.177-2.18c1.08-0.699,2.19-1.357,3.331-1.975
|
|
||||||
c0.021-0.021,0.042-0.021,0.042-0.021c0.441-0.247,0.873-0.493,1.306-0.761c1.295-0.761,2.519-1.624,3.69-2.56
|
|
||||||
c5.347,5.469,12.79,8.852,21.046,8.852c8.226,0,15.669-3.393,21.016-8.842c0.339,0.277,0.688,0.545,1.038,0.802
|
|
||||||
c0.483,0.36,0.977,0.71,1.47,1.039c0.37,0.246,0.751,0.493,1.132,0.72c0.421,0.267,0.853,0.514,1.285,0.75
|
|
||||||
c0.041,0.011,0.071,0.021,0.103,0.041c0.03,0.011,0.062,0.031,0.093,0.052c1.265,0.699,2.498,1.439,3.69,2.23
|
|
||||||
c0.401,0.258,0.802,0.524,1.192,0.803c0.515,0.37,1.039,0.74,1.543,1.131h0.021C139.966,163.875,148.572,179.729,148.572,197.629
|
|
||||||
z"/>
|
|
||||||
<path style="fill:#A57561;" d="M52.183,46.81v34.117c0,28.977,25.437,52.466,41.857,52.466c16.421,0,41.858-23.489,41.858-52.466
|
|
||||||
V46.81H52.183z"/>
|
|
||||||
<path style="fill:#141720;" d="M52.183,76.823L52.183,76.823c2.063,0,3.734-1.671,3.734-3.733V49.356h-3.734V76.823z"/>
|
|
||||||
<path style="fill:#141720;" d="M135.899,76.823L135.899,76.823V49.356h-3.733V73.09
|
|
||||||
C132.165,75.152,133.836,76.823,135.899,76.823z"/>
|
|
||||||
<path style="fill:#141720;" d="M135.893,48.33c0,4.884-0.328,6.061-3.734,5.801c-0.137-2.367-17.141-4.296-38.111-4.296
|
|
||||||
c-20.985,0-37.989,1.929-38.126,4.296c-3.406,0.26-3.734-0.917-3.734-5.801c0-0.479,0.014-0.984,0.027-1.519
|
|
||||||
c0.52-12.052,7.318-34.582,41.833-34.582c34.5,0,41.299,22.53,41.818,34.582C135.879,47.346,135.893,47.852,135.893,48.33z"/>
|
|
||||||
</g>
|
|
||||||
<path style="clip-path:url(#SVGID_2_);fill:#FFFFFF;" d="M115.106,146.119c-3.517,10.826-10.601,21.539-21.036,30.299
|
|
||||||
c-10.436-8.76-17.509-19.473-21.025-30.299c0.052,0.02,0.113,0.041,0.165,0.061c5.531,4.955,12.852,7.979,20.86,7.979
|
|
||||||
c8.009,0,15.319-3.013,20.851-7.968C114.982,146.17,115.044,146.14,115.106,146.119z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 80 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M512,84.85,427.15,0,256,171.15,84.85,0,0,84.85,171.15,256,0,427.15,84.85,512,256,340.85,427.15,512,512,427.15,340.85,256Z" transform="translate(0 0)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 319 B |
@@ -1 +0,0 @@
|
|||||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><defs><image width="12" height="14" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOAQMAAAAhc2+vAAAAAXNSR0IB2cksfwAAAAZQTFRFAAAA////pdmf3QAAAAJ0Uk5TAP9bkSK1AAAAJUlEQVR4nGNgOMDAoMDw/wMDCDgwMDQwQIAASBgE/j8ACRswAACLjwYPIknTggAAAABJRU5ErkJggg=="/><image width="12" height="12" id="img2" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMAgMAAAArG7R0AAAAAXNSR0IB2cksfwAAAAlQTFRFAAAA/////wAAzV63nAAAAAN0Uk5TAP8BHlUJOgAAACJJREFUeJxjYGAQYGBgYGEIDQ0F0xA+BwMDEi80NASqigEAOD8CVqGVgwsAAAAASUVORK5CYII="/></defs><style></style><use href="#img1" x="2" y="1" /><use href="#img2" x="2" y="2" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 717 B |
@@ -1 +0,0 @@
|
|||||||
<svg height="682pt" viewBox="-21 -47 682.66669 682" width="682pt" xmlns="http://www.w3.org/2000/svg"><path d="m640 86.65625v283.972656c0 48.511719-39.472656 87.988282-87.988281 87.988282h-279.152344l-185.183594 128.863281v-128.863281c-48.375-.164063-87.675781-39.574219-87.675781-87.988282v-283.972656c0-48.515625 39.472656-87.988281 87.988281-87.988281h464.023438c48.515625 0 87.988281 39.472656 87.988281 87.988281zm0 0" fill="#ffdb2d"/><path d="m640 86.65625v283.972656c0 48.511719-39.472656 87.988282-87.988281 87.988282h-232.109375v-459.949219h232.109375c48.515625 0 87.988281 39.472656 87.988281 87.988281zm0 0" fill="#ffaa20"/><g fill="#fff"><path d="m171.296875 131.167969h297.40625v37.5h-297.40625zm0 0"/><path d="m171.296875 211.167969h297.40625v37.5h-297.40625zm0 0"/><path d="m171.296875 291.167969h297.40625v37.5h-297.40625zm0 0"/></g><path d="m319.902344 131.167969h148.800781v37.5h-148.800781zm0 0" fill="#e1e1e3"/><path d="m319.902344 211.167969h148.800781v37.5h-148.800781zm0 0" fill="#e1e1e3"/><path d="m319.902344 291.167969h148.800781v37.5h-148.800781zm0 0" fill="#e1e1e3"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg id="i-fullscreen-exit" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
|
||||||
<path d="M4 12 L12 12 12 4 M20 4 L20 12 28 12 M4 20 L12 20 12 28 M28 20 L20 20 20 28" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 329 B |
@@ -1,3 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg id="i-fullscreen" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
|
||||||
<path d="M4 12 L4 4 12 4 M20 4 L28 4 28 12 M4 20 L4 28 12 28 M28 20 L28 28 20 28" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 322 B |
@@ -1,18 +0,0 @@
|
|||||||
<?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="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 451.7 512" style="enable-background:new 0 0 451.7 512;" xml:space="preserve">
|
|
||||||
<path d="M436.9,212.6L237.2,12.9c-11.7-11.7-30.7-11.7-42.4,0s-11.7,30.7,0,42.4L394.5,255c11.5,11.9,30.5,12.2,42.4,0.7
|
|
||||||
c11.9-11.5,12.2-30.5,0.7-42.4C437.4,213.1,437.2,212.8,436.9,212.6z"/>
|
|
||||||
<path d="M179.5,83.1l-1.5,7.5c-10.4,53-36,103.4-70.6,144.3l109,108.3c40.7-34.9,90.2-61.5,143.1-72.3l7.5-1.5L179.5,83.1z"/>
|
|
||||||
<path d="M87.4,257l-74.2,74.2c-17.6,17.6-17.6,46.1,0,63.6c0,0,0,0,0,0l42.4,42.4c17.6,17.6,46.1,17.6,63.6,0c0,0,0,0,0,0l74.2-74.2
|
|
||||||
L87.4,257z M98,373.7c-6.1,5.6-15.6,5.3-21.2-0.8c-5.4-5.8-5.4-14.7,0-20.5l21.2-21.2c6-5.8,15.5-5.6,21.2,0.4
|
|
||||||
c5.6,5.8,5.6,15,0,20.8L98,373.7z"/>
|
|
||||||
<path d="M256.1,445.3l20.4-20.4c17.6-17.6,17.6-46.1,0-63.6l-15.1-15.2c-8.4,5.7-16.4,11.7-24.2,18.3l18.1,18.1
|
|
||||||
c5.8,5.9,5.8,15.3,0,21.2l-20.7,20.8l-30.5-29.5l-42.4,42.4l68.1,65.9c11.7,11.7,30.7,11.7,42.4,0c11.7-11.7,11.7-30.7,0-42.4l0,0
|
|
||||||
L256.1,445.3z"/>
|
|
||||||
<path d="M316.7,0c-8.3,0-15,6.7-15,15v30c0,8.3,6.7,15,15,15c8.3,0,15-6.7,15-15V15C331.7,6.7,325,0,316.7,0z"/>
|
|
||||||
<path d="M436.7,120h-30c-8.3,0-15,6.7-15,15s6.7,15,15,15h30c8.3,0,15-6.7,15-15S445,120,436.7,120z"/>
|
|
||||||
<path d="M417.3,34.4c-5.9-5.9-15.4-5.9-21.2,0l-30,30c-6,5.8-6.1,15.3-0.4,21.2c5.8,6,15.3,6.1,21.2,0.4c0.1-0.1,0.2-0.2,0.4-0.4
|
|
||||||
l30-30C423.2,49.7,423.2,40.2,417.3,34.4z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 377.87"><defs><style>.cls-1{fill:#ffda01;}</style></defs><path class="cls-1" d="M494.6,67.07H17.4A17.4,17.4,0,0,0,0,84.46V343.84a17.4,17.4,0,0,0,17.4,17.39H494.6A17.4,17.4,0,0,0,512,343.84V84.46a17.4,17.4,0,0,0-17.4-17.39Z" transform="translate(0 -67.07)"/><path class="cls-1" d="M355.42,414.75H296.35V391.42h-80.7v23.33H156.58a15.1,15.1,0,1,0,0,30.19H355.42a15.1,15.1,0,1,0,0-30.19Z" transform="translate(0 -67.07)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 512 B |
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
|
||||||
<style type="text/css">
|
|
||||||
.st0{fill:#FFFFFF;}
|
|
||||||
</style>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M163.2,351.1c-2.4-23.4-1.1-46.7,3.9-69.2c2.6-11-2.1-23.8-9.4-29.6l-36.8-39.7C142.5,160,170,126.2,216.8,95
|
|
||||||
l45.1,27.2c9,7.3,21.3,9.1,32,4.4c21.2-9.5,43.7-15.4,67.2-17.7c16.9-1.7,29.3-16.8,27.6-33.7L381.5,5
|
|
||||||
c-1.7-16.9-16.8-29.3-33.7-27.6C154-2.8,12.4,170.8,32.1,364.5c1.7,16.9,16.8,29.3,33.7,27.6l69.9-7.1
|
|
||||||
C152.5,383.1,164.9,368,163.2,351.1z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 804 B |
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
|
||||||
<style type="text/css">
|
|
||||||
.st0{fill:#FFFFFF;}
|
|
||||||
</style>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path class="st0" d="M32.6,256.8c17.3-15.9,36.8-28.8,57.8-38.3c10.4-4.5,17.8-15.9,18.1-25.3l9.8-53.2
|
|
||||||
c55-14.2,98.5-12.3,151.6,6.5l5.2,52.4c-0.5,11.6,5.4,22.5,15.6,28.3c20.3,11.3,38.5,25.8,54.4,43.2c11.5,12.5,31,13.4,43.5,1.9
|
|
||||||
l51.9-47.7c12.5-11.5,13.4-31,1.9-43.5c-131.8-143.5-355.6-153-499-21.3c-12.5,11.5-13.4,31-1.9,43.5l47.5,51.8
|
|
||||||
C0.6,267.4,20.1,268.3,32.6,256.8z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 810 B |
@@ -1 +0,0 @@
|
|||||||
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56.48 56.48"><defs><style>.cls-1{fill:#e76e54;}.cls-2{fill:#fff;}</style></defs><path class="cls-1" d="M39.94,512H16.54L0,495.46v-23.4l16.54-16.54h23.4l16.54,16.54v23.4Z" transform="translate(0 -455.52)"/><path class="cls-2" d="M33.54,485.52H23l-1.77-21.18H35.3Z" transform="translate(0 -455.52)"/><path class="cls-2" d="M23,492.58H33.54v10.59H23Z" transform="translate(0 -455.52)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 477 B |
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path d="M481.508,210.336L68.414,38.926c-17.403-7.222-37.064-4.045-51.309,8.287C2.86,59.547-3.098,78.551,1.558,96.808
|
|
||||||
L38.327,241h180.026c8.284,0,15.001,6.716,15.001,15.001c0,8.284-6.716,15.001-15.001,15.001H38.327L1.558,415.193
|
|
||||||
c-4.656,18.258,1.301,37.262,15.547,49.595c14.274,12.357,33.937,15.495,51.31,8.287l413.094-171.409
|
|
||||||
C500.317,293.862,512,276.364,512,256.001C512,235.638,500.317,218.139,481.508,210.336z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 985 B |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 441.78"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M481.51,210.34,68.41,38.93A49.44,49.44,0,0,0,1.56,96.81L38.33,241h180a15,15,0,1,1,0,30h-180L1.56,415.19a49.43,49.43,0,0,0,66.86,57.88l413.09-171.4a49.44,49.44,0,0,0,0-91.33Z" transform="translate(0 -35.11)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 379 B |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 441.78"><defs><style>.cls-1{fill:#ffda01;}</style></defs><path class="cls-1" d="M481.51,210.34,68.41,38.93A49.44,49.44,0,0,0,1.56,96.81L38.33,241h180a15,15,0,1,1,0,30h-180L1.56,415.19a49.43,49.43,0,0,0,66.86,57.88l413.09-171.4a49.44,49.44,0,0,0,0-91.33Z" transform="translate(0 -35.11)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 382 B |
@@ -1,20 +0,0 @@
|
|||||||
<?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="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path d="M453.6,237.3c-1.5-18.8-5.6-37-12.3-54.5l46.1-37l-75-93.6L366.5,89c-15.8-10.7-33-18.9-51.1-24.6V6.1h-120v58.7
|
|
||||||
c-19,6.1-36.8,15-53.2,26.5l-46.3-36L22.3,150l47.2,36.6c-6.3,17.5-10,35.8-11.2,54.5L0,255l27.9,116.7l41-9.8
|
|
||||||
c20.2-20.2,38.4-38.4,62.4-62.4C99.4,213,163.5,120.6,256.1,120.6c73.4,0,132.9,59.5,132.9,132.9c0,90.7-89,154.7-174.8,126.2
|
|
||||||
c-6.9,6.9-77.9,77.9-88.9,88.9l79.1,37.3l26.3-55.8c18.2,2.3,36.3,2.1,54.1-0.5l26.9,55.1L419.6,452l-26.9-54.9
|
|
||||||
c13.3-12.7,24.7-27,34.1-42.8l59,13.2L512,250.4L453.6,237.3z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path d="M336,219.4l-7.6-19.1L282.6,246L262,225.4l45.8-45.8l-19.1-7.6c-74.9-29.8-144.2,52.2-104.9,120.7
|
|
||||||
C82.6,393.9,169.1,307.5,47.6,429c-17,17,18.4,52.5,35.4,35.4c70.6-70.6,2-2,137.5-137.5C289.6,360.5,364.5,291,336,219.4z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.81"><defs><style>.cls-1{fill:#fff;}</style></defs><path class="cls-1" d="M453.58,237.31a195.46,195.46,0,0,0-12.33-54.5l46.14-37-75-93.62L366.55,89a196.1,196.1,0,0,0-51.12-24.58V6.1h-120V64.75a195.85,195.85,0,0,0-53.23,26.53l-46.34-36L22.3,150l47.16,36.64a196.64,196.64,0,0,0-11.19,54.46L0,255,27.91,371.68l41-9.81,62.4-62.39C99.44,213,163.49,120.57,256.09,120.57A133,133,0,0,1,389,253.51c0,90.69-89,154.71-174.78,126.22l-88.88,88.89,79.1,37.28,26.31-55.81a199.26,199.26,0,0,0,54.12-.45l27,55.07L419.6,452l-26.88-54.93a197.42,197.42,0,0,0,34.06-42.84l59,13.22,26.2-117Z" transform="translate(0 -6.1)"/><path class="cls-1" d="M336,219.37l-7.61-19.14L282.55,246,262,225.44l45.79-45.78L288.63,172c-74.92-29.8-144.18,52.17-104.87,120.7C82.63,393.88,169.06,307.46,47.55,429,30.51,446,66,481.44,83,464.4c70.58-70.59,2-2,137.48-137.47C289.61,360.46,364.47,291,336,219.37Z" transform="translate(0 -6.1)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 994 B |
@@ -1 +0,0 @@
|
|||||||
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.81"><defs><style>.cls-1{fill:#ffda01;}</style></defs><path class="cls-1" d="M453.58,237.31a195.46,195.46,0,0,0-12.33-54.5l46.14-37-75-93.62L366.55,89a196.1,196.1,0,0,0-51.12-24.58V6.1h-120V64.75a195.85,195.85,0,0,0-53.23,26.53l-46.34-36L22.3,150l47.16,36.64a196.64,196.64,0,0,0-11.19,54.46L0,255,27.91,371.68l41-9.81,62.4-62.39C99.44,213,163.49,120.57,256.09,120.57A133,133,0,0,1,389,253.51c0,90.69-89,154.71-174.78,126.22l-88.88,88.89,79.1,37.28,26.31-55.81a199.26,199.26,0,0,0,54.12-.45l27,55.07L419.6,452l-26.88-54.93a197.42,197.42,0,0,0,34.06-42.84l59,13.22,26.2-117Z" transform="translate(0 -6.1)"/><path class="cls-1" d="M336,219.37l-7.61-19.14L282.55,246,262,225.44l45.79-45.78L288.63,172c-74.92-29.8-144.18,52.17-104.87,120.7C82.63,393.88,169.06,307.46,47.55,429,30.51,446,66,481.44,83,464.4c70.58-70.59,2-2,137.48-137.47C289.61,360.46,364.47,291,336,219.37Z" transform="translate(0 -6.1)"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 771 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 231 B |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 639 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 622 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 300 KiB |
|
Before Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 410 KiB |
|
Before Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 291 KiB |
|
Before Width: | Height: | Size: 729 KiB |
|
Before Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 615 B |
@@ -0,0 +1,12 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isActionsMenuActionClickedEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isNumber,
|
||||||
|
actionName: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export type ActionsMenuActionClickedEvent = tg.GuardedType<typeof isActionsMenuActionClickedEvent>;
|
||||||
|
|
||||||
|
export type ActionsMenuActionClickedEventCallback = (event: ActionsMenuActionClickedEvent) => void;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isAddActionsMenuKeyToRemotePlayerEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isNumber,
|
||||||
|
actionKey: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export type AddActionsMenuKeyToRemotePlayerEvent = tg.GuardedType<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
||||||
|
|
||||||
|
export type AddActionsMenuKeyToRemotePlayerEventCallback = (event: AddActionsMenuKeyToRemotePlayerEvent) => void;
|
||||||
@@ -36,6 +36,10 @@ import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
|
|||||||
import { isColorEvent } from "./ColorEvent";
|
import { isColorEvent } from "./ColorEvent";
|
||||||
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
|
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
|
||||||
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
|
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
|
||||||
|
import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent";
|
||||||
|
import type { AddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
|
||||||
|
import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent";
|
||||||
|
import type { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||||
|
|
||||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||||
data: T;
|
data: T;
|
||||||
@@ -45,6 +49,8 @@ export interface TypedMessageEvent<T> extends MessageEvent {
|
|||||||
* List event types sent from an iFrame to WorkAdventure
|
* List event types sent from an iFrame to WorkAdventure
|
||||||
*/
|
*/
|
||||||
export type IframeEventMap = {
|
export type IframeEventMap = {
|
||||||
|
addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent;
|
||||||
|
removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent;
|
||||||
loadPage: LoadPageEvent;
|
loadPage: LoadPageEvent;
|
||||||
chat: ChatEvent;
|
chat: ChatEvent;
|
||||||
cameraFollowPlayer: CameraFollowPlayerEvent;
|
cameraFollowPlayer: CameraFollowPlayerEvent;
|
||||||
@@ -58,6 +64,7 @@ export type IframeEventMap = {
|
|||||||
displayBubble: null;
|
displayBubble: null;
|
||||||
removeBubble: null;
|
removeBubble: null;
|
||||||
onPlayerMove: undefined;
|
onPlayerMove: undefined;
|
||||||
|
onOpenActionMenu: undefined;
|
||||||
onCameraUpdate: undefined;
|
onCameraUpdate: undefined;
|
||||||
showLayer: LayerEvent;
|
showLayer: LayerEvent;
|
||||||
hideLayer: LayerEvent;
|
hideLayer: LayerEvent;
|
||||||
@@ -90,6 +97,8 @@ export interface IframeResponseEventMap {
|
|||||||
enterZoneEvent: ChangeZoneEvent;
|
enterZoneEvent: ChangeZoneEvent;
|
||||||
leaveZoneEvent: ChangeZoneEvent;
|
leaveZoneEvent: ChangeZoneEvent;
|
||||||
buttonClickedEvent: ButtonClickedEvent;
|
buttonClickedEvent: ButtonClickedEvent;
|
||||||
|
remotePlayerClickedEvent: RemotePlayerClickedEvent;
|
||||||
|
actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent;
|
||||||
hasPlayerMoved: HasPlayerMovedEvent;
|
hasPlayerMoved: HasPlayerMovedEvent;
|
||||||
wasCameraUpdated: WasCameraUpdatedEvent;
|
wasCameraUpdated: WasCameraUpdatedEvent;
|
||||||
menuItemClicked: MenuItemClickedEvent;
|
menuItemClicked: MenuItemClickedEvent;
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
// TODO: Change for player Clicked, add all neccessary data
|
||||||
|
export const isRemotePlayerClickedEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isNumber,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message sent from the game to the iFrame when RemotePlayer is clicked.
|
||||||
|
*/
|
||||||
|
export type RemotePlayerClickedEvent = tg.GuardedType<typeof isRemotePlayerClickedEvent>;
|
||||||
|
|
||||||
|
export type RemotePlayerClickedEventCallback = (event: RemotePlayerClickedEvent) => void;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isNumber,
|
||||||
|
actionKey: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export type RemoveActionsMenuKeyFromRemotePlayerEvent = tg.GuardedType<
|
||||||
|
typeof isRemoveActionsMenuKeyFromRemotePlayerEvent
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = (
|
||||||
|
event: RemoveActionsMenuKeyFromRemotePlayerEvent
|
||||||
|
) => void;
|
||||||
@@ -34,6 +34,16 @@ import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
|
|||||||
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
||||||
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
|
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
|
||||||
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
||||||
|
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
|
||||||
|
import {
|
||||||
|
AddActionsMenuKeyToRemotePlayerEvent,
|
||||||
|
isAddActionsMenuKeyToRemotePlayerEvent,
|
||||||
|
} from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
||||||
|
import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent";
|
||||||
|
import {
|
||||||
|
isRemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||||
|
RemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||||
|
} from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||||
query: IframeQueryMap[T]["query"],
|
query: IframeQueryMap[T]["query"],
|
||||||
@@ -63,6 +73,15 @@ class IframeListener {
|
|||||||
private readonly _cameraFollowPlayerStream: Subject<CameraFollowPlayerEvent> = new Subject();
|
private readonly _cameraFollowPlayerStream: Subject<CameraFollowPlayerEvent> = new Subject();
|
||||||
public readonly cameraFollowPlayerStream = this._cameraFollowPlayerStream.asObservable();
|
public readonly cameraFollowPlayerStream = this._cameraFollowPlayerStream.asObservable();
|
||||||
|
|
||||||
|
private readonly _addActionsMenuKeyToRemotePlayerStream: Subject<AddActionsMenuKeyToRemotePlayerEvent> =
|
||||||
|
new Subject();
|
||||||
|
public readonly addActionsMenuKeyToRemotePlayerStream = this._addActionsMenuKeyToRemotePlayerStream.asObservable();
|
||||||
|
|
||||||
|
private readonly _removeActionsMenuKeyFromRemotePlayerEvent: Subject<RemoveActionsMenuKeyFromRemotePlayerEvent> =
|
||||||
|
new Subject();
|
||||||
|
public readonly removeActionsMenuKeyFromRemotePlayerEvent =
|
||||||
|
this._removeActionsMenuKeyFromRemotePlayerEvent.asObservable();
|
||||||
|
|
||||||
private readonly _enablePlayerControlStream: Subject<void> = new Subject();
|
private readonly _enablePlayerControlStream: Subject<void> = new Subject();
|
||||||
public readonly enablePlayerControlStream = this._enablePlayerControlStream.asObservable();
|
public readonly enablePlayerControlStream = this._enablePlayerControlStream.asObservable();
|
||||||
|
|
||||||
@@ -241,6 +260,16 @@ class IframeListener {
|
|||||||
this._removeBubbleStream.next();
|
this._removeBubbleStream.next();
|
||||||
} else if (payload.type == "onPlayerMove") {
|
} else if (payload.type == "onPlayerMove") {
|
||||||
this.sendPlayerMove = true;
|
this.sendPlayerMove = true;
|
||||||
|
} else if (
|
||||||
|
payload.type == "addActionsMenuKeyToRemotePlayer" &&
|
||||||
|
isAddActionsMenuKeyToRemotePlayerEvent(payload.data)
|
||||||
|
) {
|
||||||
|
this._addActionsMenuKeyToRemotePlayerStream.next(payload.data);
|
||||||
|
} else if (
|
||||||
|
payload.type == "removeActionsMenuKeyFromRemotePlayer" &&
|
||||||
|
isRemoveActionsMenuKeyFromRemotePlayerEvent(payload.data)
|
||||||
|
) {
|
||||||
|
this._removeActionsMenuKeyFromRemotePlayerEvent.next(payload.data);
|
||||||
} else if (payload.type == "onCameraUpdate") {
|
} else if (payload.type == "onCameraUpdate") {
|
||||||
this._trackCameraUpdateStream.next();
|
this._trackCameraUpdateStream.next();
|
||||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
||||||
@@ -439,6 +468,20 @@ class IframeListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendRemotePlayerClickedEvent(event: RemotePlayerClickedEvent) {
|
||||||
|
this.postMessage({
|
||||||
|
type: "remotePlayerClickedEvent",
|
||||||
|
data: event,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendActionsMenuActionClickedEvent(event: ActionsMenuActionClickedEvent) {
|
||||||
|
this.postMessage({
|
||||||
|
type: "actionsMenuActionClickedEvent",
|
||||||
|
data: event,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
sendCameraUpdated(event: WasCameraUpdatedEvent) {
|
sendCameraUpdated(event: WasCameraUpdatedEvent) {
|
||||||
this.postMessage({
|
this.postMessage({
|
||||||
type: "wasCameraUpdated",
|
type: "wasCameraUpdated",
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import { ActionMessage } from "./Ui/ActionMessage";
|
|||||||
import { isMessageReferenceEvent } from "../Events/ui/TriggerActionMessageEvent";
|
import { isMessageReferenceEvent } from "../Events/ui/TriggerActionMessageEvent";
|
||||||
import { Menu } from "./Ui/Menu";
|
import { Menu } from "./Ui/Menu";
|
||||||
import type { RequireOnlyOne } from "../types";
|
import type { RequireOnlyOne } from "../types";
|
||||||
|
import { isRemotePlayerClickedEvent, RemotePlayerClickedEvent } from "../Events/RemotePlayerClickedEvent";
|
||||||
|
import {
|
||||||
|
ActionsMenuActionClickedEvent,
|
||||||
|
isActionsMenuActionClickedEvent,
|
||||||
|
} from "../Events/ActionsMenuActionClickedEvent";
|
||||||
|
import { Observable, Subject } from "rxjs";
|
||||||
|
|
||||||
let popupId = 0;
|
let popupId = 0;
|
||||||
const popups: Map<number, Popup> = new Map<number, Popup>();
|
const popups: Map<number, Popup> = new Map<number, Popup>();
|
||||||
@@ -42,7 +48,77 @@ export interface ActionMessageOptions {
|
|||||||
callback: () => void;
|
callback: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RemotePlayerInterface {
|
||||||
|
addAction(key: string, callback: Function): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemotePlayer implements RemotePlayerInterface {
|
||||||
|
private id: number;
|
||||||
|
|
||||||
|
private actions: Map<string, ActionsMenuAction> = new Map<string, ActionsMenuAction>();
|
||||||
|
|
||||||
|
constructor(id: number) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addAction(key: string, callback: Function): ActionsMenuAction {
|
||||||
|
const newAction = new ActionsMenuAction(this, key, callback);
|
||||||
|
this.actions.set(key, newAction);
|
||||||
|
sendToWorkadventure({
|
||||||
|
type: "addActionsMenuKeyToRemotePlayer",
|
||||||
|
data: { id: this.id, actionKey: key },
|
||||||
|
});
|
||||||
|
return newAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public callAction(key: string): void {
|
||||||
|
const action = this.actions.get(key);
|
||||||
|
if (action) {
|
||||||
|
action.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeAction(key: string): void {
|
||||||
|
this.actions.delete(key);
|
||||||
|
sendToWorkadventure({
|
||||||
|
type: "removeActionsMenuKeyFromRemotePlayer",
|
||||||
|
data: { id: this.id, actionKey: key },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ActionsMenuAction {
|
||||||
|
private remotePlayer: RemotePlayer;
|
||||||
|
private key: string;
|
||||||
|
private callback: Function;
|
||||||
|
|
||||||
|
constructor(remotePlayer: RemotePlayer, key: string, callback: Function) {
|
||||||
|
this.remotePlayer = remotePlayer;
|
||||||
|
this.key = key;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public call(): void {
|
||||||
|
this.callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public remove(): void {
|
||||||
|
this.remotePlayer.removeAction(this.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiCommands> {
|
export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiCommands> {
|
||||||
|
public readonly _onRemotePlayerClicked: Subject<RemotePlayerInterface>;
|
||||||
|
public readonly onRemotePlayerClicked: Observable<RemotePlayerInterface>;
|
||||||
|
|
||||||
|
private currentlyClickedRemotePlayer?: RemotePlayer;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._onRemotePlayerClicked = new Subject<RemotePlayerInterface>();
|
||||||
|
this.onRemotePlayerClicked = this._onRemotePlayerClicked.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
callbacks = [
|
callbacks = [
|
||||||
apiCallback({
|
apiCallback({
|
||||||
type: "buttonClickedEvent",
|
type: "buttonClickedEvent",
|
||||||
@@ -82,9 +158,38 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "remotePlayerClickedEvent",
|
||||||
|
typeChecker: isRemotePlayerClickedEvent,
|
||||||
|
callback: (payloadData: RemotePlayerClickedEvent) => {
|
||||||
|
this.currentlyClickedRemotePlayer = new RemotePlayer(payloadData.id);
|
||||||
|
this._onRemotePlayerClicked.next(this.currentlyClickedRemotePlayer);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "actionsMenuActionClickedEvent",
|
||||||
|
typeChecker: isActionsMenuActionClickedEvent,
|
||||||
|
callback: (payloadData: ActionsMenuActionClickedEvent) => {
|
||||||
|
this.currentlyClickedRemotePlayer?.callAction(payloadData.actionName);
|
||||||
|
},
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
public addActionsMenuKeyToRemotePlayer(id: number, actionKey: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
type: "addActionsMenuKeyToRemotePlayer",
|
||||||
|
data: { id, actionKey },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeActionsMenuKeyFromRemotePlayer(id: number, actionKey: string): void {
|
||||||
|
sendToWorkadventure({
|
||||||
|
type: "removeActionsMenuKeyFromRemotePlayer",
|
||||||
|
data: { id, actionKey },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||||
popupId++;
|
popupId++;
|
||||||
const popup = new Popup(popupId);
|
const popup = new Popup(popupId);
|
||||||
const btnMap = new Map<number, () => void>();
|
const btnMap = new Map<number, () => void>();
|
||||||
@@ -119,7 +224,10 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
|||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerMenuCommand(commandDescriptor: string, options: MenuOptions | ((commandDescriptor: string) => void)): Menu {
|
public registerMenuCommand(
|
||||||
|
commandDescriptor: string,
|
||||||
|
options: MenuOptions | ((commandDescriptor: string) => void)
|
||||||
|
): Menu {
|
||||||
const menu = new Menu(commandDescriptor);
|
const menu = new Menu(commandDescriptor);
|
||||||
|
|
||||||
if (typeof options === "function") {
|
if (typeof options === "function") {
|
||||||
@@ -168,15 +276,15 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
|||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
displayBubble(): void {
|
public displayBubble(): void {
|
||||||
sendToWorkadventure({ type: "displayBubble", data: null });
|
sendToWorkadventure({ type: "displayBubble", data: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBubble(): void {
|
public removeBubble(): void {
|
||||||
sendToWorkadventure({ type: "removeBubble", data: null });
|
sendToWorkadventure({ type: "removeBubble", data: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
public displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
||||||
const actionMessage = new ActionMessage(actionMessageOptions, () => {
|
const actionMessage = new ActionMessage(actionMessageOptions, () => {
|
||||||
actionMessages.delete(actionMessage.uuid);
|
actionMessages.delete(actionMessage.uuid);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
import { actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
import { actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||||
import { onDestroy } from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
|
|
||||||
|
import type { ActionsMenuAction } from "../../Stores/ActionsMenuStore";
|
||||||
import type { Unsubscriber } from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import type { ActionsMenuData } from "../../Stores/ActionsMenuStore";
|
import type { ActionsMenuData } from "../../Stores/ActionsMenuStore";
|
||||||
|
|
||||||
let actionsMenuData: ActionsMenuData | undefined;
|
let actionsMenuData: ActionsMenuData | undefined;
|
||||||
|
let sortedActions: ActionsMenuAction[] | undefined;
|
||||||
|
|
||||||
let actionsMenuStoreUnsubscriber: Unsubscriber | null;
|
let actionsMenuStoreUnsubscriber: Unsubscriber | null;
|
||||||
|
|
||||||
@@ -21,6 +23,20 @@
|
|||||||
|
|
||||||
actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value) => {
|
actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value) => {
|
||||||
actionsMenuData = value;
|
actionsMenuData = value;
|
||||||
|
if (actionsMenuData) {
|
||||||
|
sortedActions = [...actionsMenuData.actions.values()].sort((a, b) => {
|
||||||
|
const ap = a.priority ?? 0;
|
||||||
|
const bp = b.priority ?? 0;
|
||||||
|
if (ap > bp) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ap < bp) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@@ -37,15 +53,15 @@
|
|||||||
<button type="button" class="nes-btn is-error close" on:click={closeActionsMenu}>×</button>
|
<button type="button" class="nes-btn is-error close" on:click={closeActionsMenu}>×</button>
|
||||||
<h2>{actionsMenuData.playerName}</h2>
|
<h2>{actionsMenuData.playerName}</h2>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
{#each [...actionsMenuData.actions] as { actionName, callback }}
|
{#each sortedActions ?? [] as action}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="nes-btn"
|
class="nes-btn {action.style ?? ''}"
|
||||||
on:click|preventDefault={() => {
|
on:click|preventDefault={() => {
|
||||||
callback();
|
action.callback();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{actionName}
|
{action.actionName}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
@@ -61,6 +77,7 @@
|
|||||||
height: max-content !important;
|
height: max-content !important;
|
||||||
max-height: 40vh;
|
max-height: 40vh;
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
|
z-index: 425;
|
||||||
|
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
@@ -68,7 +85,7 @@
|
|||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
max-height: calc(100% - 50px);
|
max-height: 30vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
|
||||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
|
||||||
|
import uploadFile from "../images/jitsi.png";
|
||||||
|
|
||||||
export let index: number;
|
export let index: number;
|
||||||
export let coWebsite: CoWebsite;
|
export let coWebsite: CoWebsite;
|
||||||
export let vertical: boolean;
|
export let vertical: boolean;
|
||||||
@@ -21,7 +23,7 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
icon.src = isJitsi
|
icon.src = isJitsi
|
||||||
? "/resources/logos/jitsi.png"
|
? uploadFile
|
||||||
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
||||||
icon.alt = coWebsite.getUrl().hostname;
|
icon.alt = coWebsite.getUrl().hostname;
|
||||||
icon.onload = () => {
|
icon.onload = () => {
|
||||||
@@ -350,9 +352,14 @@
|
|||||||
color: white;
|
color: white;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,5 +18,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding-top: 2%;
|
padding-top: 2%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
z-index: 200;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
|
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
|
||||||
import firefoxImg from "./images/help-setting-camera-permission-firefox.png";
|
|
||||||
import chromeImg from "./images/help-setting-camera-permission-chrome.png";
|
|
||||||
import { getNavigatorType, isAndroid as isAndroidFct, NavigatorType } from "../../WebRtc/DeviceUtils";
|
import { getNavigatorType, isAndroid as isAndroidFct, NavigatorType } from "../../WebRtc/DeviceUtils";
|
||||||
import LL from "../../i18n/i18n-svelte";
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
|
||||||
@@ -33,9 +31,9 @@
|
|||||||
<p class="err">
|
<p class="err">
|
||||||
{$LL.camera.help.firefoxContent()}
|
{$LL.camera.help.firefoxContent()}
|
||||||
</p>
|
</p>
|
||||||
<img src={firefoxImg} alt="" />
|
<img src={$LL.camera.help.screen.firefox()} alt="" />
|
||||||
{:else if isChrome && !isAndroid}
|
{:else if isChrome && !isAndroid}
|
||||||
<img src={chromeImg} alt="" />
|
<img src={$LL.camera.help.screen.chrome()} alt="" />
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
||||||
import { DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
|
import { DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
|
||||||
import logoImg from "../images/logo.png";
|
import logoImg from "../images/logo.png";
|
||||||
|
import poweredByWorkAdventureImg from "../images/Powered_By_WorkAdventure_Big.png";
|
||||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import LL from "../../i18n/i18n-svelte";
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
|
||||||
@@ -13,6 +14,8 @@
|
|||||||
let name = gameManager.getPlayerName() || "";
|
let name = gameManager.getPlayerName() || "";
|
||||||
let startValidating = false;
|
let startValidating = false;
|
||||||
|
|
||||||
|
let logo = gameManager.currentStartedRoom.loginSceneLogo ?? logoImg;
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
startValidating = true;
|
startValidating = true;
|
||||||
|
|
||||||
@@ -25,7 +28,7 @@
|
|||||||
|
|
||||||
<form class="loginScene" on:submit|preventDefault={submit}>
|
<form class="loginScene" on:submit|preventDefault={submit}>
|
||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<img src={logoImg} alt="WorkAdventure logo" />
|
<img src={logo} alt="" />
|
||||||
</section>
|
</section>
|
||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<h2>{$LL.login.input.name.placeholder()}</h2>
|
<h2>{$LL.login.input.name.placeholder()}</h2>
|
||||||
@@ -60,6 +63,11 @@
|
|||||||
<section class="action">
|
<section class="action">
|
||||||
<button type="submit" class="nes-btn is-primary loginSceneFormSubmit">{$LL.login.continue()}</button>
|
<button type="submit" class="nes-btn is-primary loginSceneFormSubmit">{$LL.login.continue()}</button>
|
||||||
</section>
|
</section>
|
||||||
|
{#if logo !== logoImg}
|
||||||
|
<section class="text-center powered-by">
|
||||||
|
<img src={poweredByWorkAdventureImg} alt="Powered by WorkAdventure" />
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -132,6 +140,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.powered-by {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Components ordered by z-index -->
|
||||||
<div id="main-layout" bind:this={mainLayout}>
|
<div id="main-layout" bind:this={mainLayout}>
|
||||||
<aside id="main-layout-left-aside">
|
<aside id="main-layout-left-aside">
|
||||||
{#if $menuIconVisiblilityStore}
|
{#if $menuIconVisiblilityStore}
|
||||||
@@ -104,14 +105,14 @@
|
|||||||
<ShareLinkMapModal />
|
<ShareLinkMapModal />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $followStateStore !== "off" || $peerStore.size > 0}
|
|
||||||
<FollowMenu />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $actionsMenuStore}
|
{#if $actionsMenuStore}
|
||||||
<ActionsMenu />
|
<ActionsMenu />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if $followStateStore !== "off" || $peerStore.size > 0}
|
||||||
|
<FollowMenu />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if $requestVisitCardsStore}
|
{#if $requestVisitCardsStore}
|
||||||
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@
|
|||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
|
z-index: 350;
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|||||||
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -330,9 +330,12 @@ class ConnectionManager {
|
|||||||
throw new Error("No Auth code provided");
|
throw new Error("No Auth code provided");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { authToken, userUuid, email, username, locale } = await Axios.get(`${PUSHER_URL}/login-callback`, {
|
const { authToken, userUuid, email, username, locale, textures } = await Axios.get(
|
||||||
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
`${PUSHER_URL}/login-callback`,
|
||||||
}).then((res) => {
|
{
|
||||||
|
params: { code, nonce, token, playUri: this.currentRoom?.key },
|
||||||
|
}
|
||||||
|
).then((res) => {
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
localUserStore.setAuthToken(authToken);
|
localUserStore.setAuthToken(authToken);
|
||||||
@@ -361,6 +364,18 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (textures) {
|
||||||
|
const layers: string[] = [];
|
||||||
|
for (const texture of textures) {
|
||||||
|
if (texture !== undefined) {
|
||||||
|
layers.push(texture.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (layers.length > 0) {
|
||||||
|
gameManager.setCharacterLayers(layers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//user connected, set connected store for menu at true
|
//user connected, set connected store for menu at true
|
||||||
userIsConnected.set(true);
|
userIsConnected.set(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export class Room {
|
|||||||
private _group: string | null = null;
|
private _group: string | null = null;
|
||||||
private _expireOn: Date | undefined;
|
private _expireOn: Date | undefined;
|
||||||
private _canReport: boolean = false;
|
private _canReport: boolean = false;
|
||||||
|
private _loadingLogo: string | undefined;
|
||||||
|
private _loginSceneLogo: string | undefined;
|
||||||
|
|
||||||
private constructor(private roomUrl: URL) {
|
private constructor(private roomUrl: URL) {
|
||||||
this.id = roomUrl.pathname;
|
this.id = roomUrl.pathname;
|
||||||
@@ -126,6 +128,8 @@ export class Room {
|
|||||||
this._expireOn = new Date(data.expireOn);
|
this._expireOn = new Date(data.expireOn);
|
||||||
}
|
}
|
||||||
this._canReport = data.canReport ?? false;
|
this._canReport = data.canReport ?? false;
|
||||||
|
this._loadingLogo = data.loadingLogo ?? undefined;
|
||||||
|
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
|
||||||
return new MapDetail(data.mapUrl);
|
return new MapDetail(data.mapUrl);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
throw new Error("Data received by the /map endpoint of the Pusher is not in a valid format.");
|
||||||
@@ -233,4 +237,12 @@ export class Room {
|
|||||||
get canReport(): boolean {
|
get canReport(): boolean {
|
||||||
return this._canReport;
|
return this._canReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get loadingLogo(): string | undefined {
|
||||||
|
return this._loadingLogo;
|
||||||
|
}
|
||||||
|
|
||||||
|
get loginSceneLogo(): string | undefined {
|
||||||
|
return this._loginSceneLogo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -349,7 +349,9 @@ export class RoomConnection implements RoomConnection {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.closed) {
|
if (this.closed) {
|
||||||
|
this.closeConnection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
||||||
import { DirtyScene } from "../Game/DirtyScene";
|
import { DirtyScene } from "../Game/DirtyScene";
|
||||||
|
import { gameManager } from "../Game/GameManager";
|
||||||
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import Image = Phaser.GameObjects.Image;
|
||||||
|
import Texture = Phaser.Textures.Texture;
|
||||||
|
|
||||||
const LogoNameIndex: string = "logoLoading";
|
|
||||||
const TextName: string = "Loading...";
|
const TextName: string = "Loading...";
|
||||||
const LogoResource: string = "static/images/logo.png";
|
|
||||||
const LogoFrame: ImageFrameConfig = { frameWidth: 310, frameHeight: 60 };
|
|
||||||
|
|
||||||
const loadingBarHeight: number = 16;
|
const loadingBarHeight: number = 16;
|
||||||
const padding: number = 5;
|
const padding: number = 5;
|
||||||
@@ -14,9 +16,15 @@ export class Loader {
|
|||||||
private progress!: Phaser.GameObjects.Graphics;
|
private progress!: Phaser.GameObjects.Graphics;
|
||||||
private progressAmount: number = 0;
|
private progressAmount: number = 0;
|
||||||
private logo: Phaser.GameObjects.Image | undefined;
|
private logo: Phaser.GameObjects.Image | undefined;
|
||||||
|
private logoPoweredBy: Phaser.GameObjects.Image | undefined;
|
||||||
|
private poweredByLogo: Phaser.GameObjects.Image | undefined;
|
||||||
private loadingText: Phaser.GameObjects.Text | null = null;
|
private loadingText: Phaser.GameObjects.Text | null = null;
|
||||||
|
private logoNameIndex!: string;
|
||||||
|
private superLoad: SuperLoaderPlugin;
|
||||||
|
|
||||||
public constructor(private scene: Phaser.Scene) {}
|
public constructor(private scene: Phaser.Scene) {
|
||||||
|
this.superLoad = new SuperLoaderPlugin(scene);
|
||||||
|
}
|
||||||
|
|
||||||
public addLoader(): void {
|
public addLoader(): void {
|
||||||
// If there is nothing to load, do not display the loader.
|
// If there is nothing to load, do not display the loader.
|
||||||
@@ -24,43 +32,53 @@ export class Loader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logoResource = gameManager.currentStartedRoom.loadingLogo ?? "static/images/logo.png";
|
||||||
|
this.logoNameIndex = "logoLoading" + logoResource;
|
||||||
|
|
||||||
const loadingBarWidth: number = Math.floor(this.scene.game.renderer.width / 3);
|
const loadingBarWidth: number = Math.floor(this.scene.game.renderer.width / 3);
|
||||||
|
|
||||||
const promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
|
//add loading if logo image until logo image is ready
|
||||||
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
|
this.loadingText = this.scene.add.text(
|
||||||
return res(
|
this.scene.game.renderer.width / 2,
|
||||||
(this.logo = this.scene.add.image(
|
this.scene.game.renderer.height / 2 - 50,
|
||||||
this.scene.game.renderer.width / 2,
|
TextName
|
||||||
this.scene.game.renderer.height / 2 - 150,
|
);
|
||||||
LogoNameIndex
|
|
||||||
))
|
const logoPromise = this.superLoad.image(this.logoNameIndex, logoResource);
|
||||||
);
|
logoPromise
|
||||||
} else {
|
.then((texture) => {
|
||||||
//add loading if logo image is not ready
|
this.logo = this.scene.add.image(
|
||||||
this.loadingText = this.scene.add.text(
|
|
||||||
this.scene.game.renderer.width / 2,
|
this.scene.game.renderer.width / 2,
|
||||||
this.scene.game.renderer.height / 2 - 50,
|
this.scene.game.renderer.height / 2 - 150,
|
||||||
TextName
|
texture
|
||||||
);
|
);
|
||||||
}
|
|
||||||
this.scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
|
this.loadingText?.destroy();
|
||||||
this.scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
|
})
|
||||||
if (this.loadingText) {
|
.catch((e) => console.warn("Could not load logo: ", logoResource, e));
|
||||||
this.loadingText.destroy();
|
|
||||||
}
|
let poweredByLogoPromise: CancelablePromise<Texture> | undefined;
|
||||||
return res(
|
if (gameManager.currentStartedRoom.loadingLogo) {
|
||||||
(this.logo = this.scene.add.image(
|
poweredByLogoPromise = this.superLoad.image(
|
||||||
|
"poweredByLogo",
|
||||||
|
"static/images/Powered_By_WorkAdventure_Small.png"
|
||||||
|
);
|
||||||
|
poweredByLogoPromise
|
||||||
|
.then((texture) => {
|
||||||
|
this.poweredByLogo = this.scene.add.image(
|
||||||
this.scene.game.renderer.width / 2,
|
this.scene.game.renderer.width / 2,
|
||||||
this.scene.game.renderer.height / 2 - 150,
|
this.scene.game.renderer.height - 50,
|
||||||
LogoNameIndex
|
texture
|
||||||
))
|
);
|
||||||
|
})
|
||||||
|
.catch((e) =>
|
||||||
|
console.warn('Could not load image "static/images/Powered_By_WorkAdventure_Small.png"', e)
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.progressContainer = this.scene.add.graphics();
|
this.progressContainer = this.scene.add.graphics();
|
||||||
this.progress = this.scene.add.graphics();
|
|
||||||
this.progressContainer.fillStyle(0x444444, 0.8);
|
this.progressContainer.fillStyle(0x444444, 0.8);
|
||||||
|
this.progress = this.scene.add.graphics();
|
||||||
|
|
||||||
this.resize();
|
this.resize();
|
||||||
|
|
||||||
@@ -68,26 +86,35 @@ export class Loader {
|
|||||||
this.progressAmount = value;
|
this.progressAmount = value;
|
||||||
this.drawProgress();
|
this.drawProgress();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const resizeFunction = this.resize.bind(this);
|
||||||
|
this.scene.scale.on(Phaser.Scale.Events.RESIZE, resizeFunction);
|
||||||
|
|
||||||
this.scene.load.on("complete", () => {
|
this.scene.load.on("complete", () => {
|
||||||
if (this.loadingText) {
|
if (this.loadingText) {
|
||||||
this.loadingText.destroy();
|
this.loadingText.destroy();
|
||||||
}
|
}
|
||||||
promiseLoadLogoTexture
|
logoPromise.cancel();
|
||||||
.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
poweredByLogoPromise?.cancel();
|
||||||
resLoadingImage.destroy();
|
|
||||||
})
|
this.logo?.destroy();
|
||||||
.catch((e) => console.error(e));
|
this.poweredByLogo?.destroy();
|
||||||
|
|
||||||
this.progress.destroy();
|
this.progress.destroy();
|
||||||
this.progressContainer.destroy();
|
this.progressContainer.destroy();
|
||||||
if (this.scene instanceof DirtyScene) {
|
if (this.scene instanceof DirtyScene) {
|
||||||
this.scene.markDirty();
|
this.scene.markDirty();
|
||||||
}
|
}
|
||||||
|
this.scene.scale.off(Phaser.Scale.Events.RESIZE, resizeFunction);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeLoader(): void {
|
public removeLoader(): void {
|
||||||
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
|
if (this.scene.load.textureManager.exists(this.logoNameIndex)) {
|
||||||
this.scene.load.textureManager.remove(LogoNameIndex);
|
this.scene.load.textureManager.remove(this.logoNameIndex);
|
||||||
|
}
|
||||||
|
if (this.scene.load.textureManager.exists("poweredByLogo")) {
|
||||||
|
this.scene.load.textureManager.remove("poweredByLogo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +141,11 @@ export class Loader {
|
|||||||
this.logo.x = this.scene.game.renderer.width / 2;
|
this.logo.x = this.scene.game.renderer.width / 2;
|
||||||
this.logo.y = this.scene.game.renderer.height / 2 - 150;
|
this.logo.y = this.scene.game.renderer.height / 2 - 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.poweredByLogo) {
|
||||||
|
this.poweredByLogo.x = this.scene.game.renderer.width / 2;
|
||||||
|
this.poweredByLogo.y = this.scene.game.renderer.height - 40;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private drawProgress() {
|
private drawProgress() {
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ export class SoundMeter {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.analyser = this.context.createAnalyser();
|
this.analyser = this.context.createAnalyser();
|
||||||
|
|
||||||
this.analyser.fftSize = 2048;
|
this.analyser.fftSize = 256;
|
||||||
const bufferLength = this.analyser.fftSize;
|
const bufferLength = this.analyser.frequencyBinCount;
|
||||||
this.dataArray = new Uint8Array(bufferLength);
|
this.dataArray = new Uint8Array(bufferLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { createColorStore } from "../../Stores/OutlineColorStore";
|
|||||||
import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
import type { OutlineableInterface } from "../Game/OutlineableInterface";
|
||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
import { TalkIcon } from "../Components/TalkIcon";
|
import { TalkIcon } from "../Components/TalkIcon";
|
||||||
|
import { Deferred } from "ts-deferred";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
const interactiveRadius = 35;
|
const interactiveRadius = 35;
|
||||||
@@ -46,6 +47,11 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
private readonly outlineColorStoreUnsubscribe: Unsubscriber;
|
private readonly outlineColorStoreUnsubscribe: Unsubscriber;
|
||||||
private texturePromise: CancelablePromise<string[] | void> | undefined;
|
private texturePromise: CancelablePromise<string[] | void> | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A deferred promise that resolves when the texture of the character is actually displayed.
|
||||||
|
*/
|
||||||
|
private textureLoadedDeferred = new Deferred<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: GameScene,
|
scene: GameScene,
|
||||||
x: number,
|
x: number,
|
||||||
@@ -74,12 +80,13 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
this.addTextures(textures, frame);
|
this.addTextures(textures, frame);
|
||||||
this.invisible = false;
|
this.invisible = false;
|
||||||
this.playAnimation(direction, moving);
|
this.playAnimation(direction, moving);
|
||||||
|
this.textureLoadedDeferred.resolve();
|
||||||
return this.getSnapshot().then((htmlImageElementSrc) => {
|
return this.getSnapshot().then((htmlImageElementSrc) => {
|
||||||
this._pictureStore.set(htmlImageElementSrc);
|
this._pictureStore.set(htmlImageElementSrc);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
return lazyLoadPlayerCharacterTextures(scene.load, [
|
return lazyLoadPlayerCharacterTextures(scene.superLoad, [
|
||||||
{
|
{
|
||||||
id: "color_22",
|
id: "color_22",
|
||||||
img: "resources/customisation/character_color/character_color21.png",
|
img: "resources/customisation/character_color/character_color21.png",
|
||||||
@@ -88,11 +95,20 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
id: "eyes_23",
|
id: "eyes_23",
|
||||||
img: "resources/customisation/character_eyes/character_eyes23.png",
|
img: "resources/customisation/character_eyes/character_eyes23.png",
|
||||||
},
|
},
|
||||||
]).then((textures) => {
|
])
|
||||||
this.addTextures(textures, frame);
|
.then((textures) => {
|
||||||
this.invisible = false;
|
this.addTextures(textures, frame);
|
||||||
this.playAnimation(direction, moving);
|
this.invisible = false;
|
||||||
});
|
this.playAnimation(direction, moving);
|
||||||
|
this.textureLoadedDeferred.resolve();
|
||||||
|
return this.getSnapshot().then((htmlImageElementSrc) => {
|
||||||
|
this._pictureStore.set(htmlImageElementSrc);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this.textureLoadedDeferred.reject(e);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.texturePromise = undefined;
|
this.texturePromise = undefined;
|
||||||
@@ -453,4 +469,13 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
public characterFarAwayOutline(): void {
|
public characterFarAwayOutline(): void {
|
||||||
this.outlineColorStore.characterFarAway();
|
this.outlineColorStore.characterFarAway();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves as soon as a texture is displayed for the user.
|
||||||
|
* The promise will return when the required texture is loaded OR when the fallback texture is loaded (in case
|
||||||
|
* the required texture could not be loaded).
|
||||||
|
*/
|
||||||
|
public getTextureLoadedPromise(): PromiseLike<void> {
|
||||||
|
return this.textureLoadedDeferred.promise;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
//The list of all the player textures, both the default models and the partial textures used for customization
|
//The list of all the player textures, both the default models and the partial textures used for customization
|
||||||
|
|
||||||
|
import { WokaList, WokaPartType } from "../../Messages/JsonMessages/PlayerTextures";
|
||||||
|
|
||||||
export interface BodyResourceDescriptionListInterface {
|
export interface BodyResourceDescriptionListInterface {
|
||||||
[key: string]: BodyResourceDescriptionInterface;
|
[key: string]: BodyResourceDescriptionInterface;
|
||||||
}
|
}
|
||||||
@@ -33,24 +35,6 @@ export enum PlayerTexturesKey {
|
|||||||
Woka = "woka",
|
Woka = "woka",
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayerTexturesMetadata = Record<PlayerTexturesKey, PlayerTexturesCategory>;
|
|
||||||
|
|
||||||
interface PlayerTexturesCategory {
|
|
||||||
collections: PlayerTexturesCollection[];
|
|
||||||
required?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PlayerTexturesCollection {
|
|
||||||
name: string;
|
|
||||||
textures: PlayerTexturesRecord[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PlayerTexturesRecord {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PlayerTextures {
|
export class PlayerTextures {
|
||||||
private PLAYER_RESOURCES: BodyResourceDescriptionListInterface = {};
|
private PLAYER_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||||
private COLOR_RESOURCES: BodyResourceDescriptionListInterface = {};
|
private COLOR_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||||
@@ -61,7 +45,7 @@ export class PlayerTextures {
|
|||||||
private ACCESSORIES_RESOURCES: BodyResourceDescriptionListInterface = {};
|
private ACCESSORIES_RESOURCES: BodyResourceDescriptionListInterface = {};
|
||||||
private LAYERS: BodyResourceDescriptionListInterface[] = [];
|
private LAYERS: BodyResourceDescriptionListInterface[] = [];
|
||||||
|
|
||||||
public loadPlayerTexturesMetadata(metadata: PlayerTexturesMetadata): void {
|
public loadPlayerTexturesMetadata(metadata: WokaList): void {
|
||||||
this.mapTexturesMetadataIntoResources(metadata);
|
this.mapTexturesMetadataIntoResources(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +72,7 @@ export class PlayerTextures {
|
|||||||
return this.LAYERS;
|
return this.LAYERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapTexturesMetadataIntoResources(metadata: PlayerTexturesMetadata): void {
|
private mapTexturesMetadataIntoResources(metadata: WokaList): void {
|
||||||
this.PLAYER_RESOURCES = this.getMappedResources(metadata.woka);
|
this.PLAYER_RESOURCES = this.getMappedResources(metadata.woka);
|
||||||
this.COLOR_RESOURCES = this.getMappedResources(metadata.body);
|
this.COLOR_RESOURCES = this.getMappedResources(metadata.body);
|
||||||
this.EYES_RESOURCES = this.getMappedResources(metadata.eyes);
|
this.EYES_RESOURCES = this.getMappedResources(metadata.eyes);
|
||||||
@@ -107,7 +91,7 @@ export class PlayerTextures {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMappedResources(category: PlayerTexturesCategory): BodyResourceDescriptionListInterface {
|
private getMappedResources(category: WokaPartType): BodyResourceDescriptionListInterface {
|
||||||
const resources: BodyResourceDescriptionListInterface = {};
|
const resources: BodyResourceDescriptionListInterface = {};
|
||||||
if (!category) {
|
if (!category) {
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin;
|
|||||||
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
import type { CharacterTexture } from "../../Connexion/LocalUser";
|
||||||
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
|
import Texture = Phaser.Textures.Texture;
|
||||||
|
|
||||||
export interface FrameConfig {
|
export interface FrameConfig {
|
||||||
frameWidth: number;
|
frameWidth: number;
|
||||||
@@ -35,81 +37,33 @@ export const loadAllDefaultModels = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const loadWokaTexture = (
|
export const loadWokaTexture = (
|
||||||
loaderPlugin: LoaderPlugin,
|
superLoaderPlugin: SuperLoaderPlugin,
|
||||||
texture: BodyResourceDescriptionInterface
|
texture: BodyResourceDescriptionInterface
|
||||||
): CancelablePromise<BodyResourceDescriptionInterface> => {
|
): CancelablePromise<Texture> => {
|
||||||
return createLoadingPromise(loaderPlugin, texture, {
|
return superLoaderPlugin.spritesheet(texture.id, texture.img, {
|
||||||
frameWidth: 32,
|
frameWidth: 32,
|
||||||
frameHeight: 32,
|
frameHeight: 32,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lazyLoadPlayerCharacterTextures = (
|
export const lazyLoadPlayerCharacterTextures = (
|
||||||
loadPlugin: LoaderPlugin,
|
superLoaderPlugin: SuperLoaderPlugin,
|
||||||
textures: BodyResourceDescriptionInterface[]
|
textures: BodyResourceDescriptionInterface[]
|
||||||
): CancelablePromise<string[]> => {
|
): CancelablePromise<string[]> => {
|
||||||
const promisesList: CancelablePromise<unknown>[] = [];
|
const promisesList: CancelablePromise<Texture>[] = [];
|
||||||
textures.forEach((texture) => {
|
for (const texture of textures) {
|
||||||
try {
|
promisesList.push(
|
||||||
//TODO refactor
|
superLoaderPlugin.spritesheet(texture.id, texture.img, {
|
||||||
if (!loadPlugin.textureManager.exists(texture.id)) {
|
frameWidth: 32,
|
||||||
promisesList.push(
|
frameHeight: 32,
|
||||||
createLoadingPromise(loadPlugin, texture, {
|
})
|
||||||
frameWidth: 32,
|
);
|
||||||
frameHeight: 32,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let returnPromise: CancelablePromise<Array<string | BodyResourceDescriptionInterface>>;
|
|
||||||
if (promisesList.length > 0) {
|
|
||||||
loadPlugin.start();
|
|
||||||
returnPromise = CancelablePromise.all(promisesList).then(() => textures);
|
|
||||||
} else {
|
|
||||||
returnPromise = CancelablePromise.resolve(textures);
|
|
||||||
}
|
}
|
||||||
|
const returnPromise: CancelablePromise<Texture[]> = CancelablePromise.all(promisesList);
|
||||||
|
|
||||||
//If the loading fail, we render the default model instead.
|
return returnPromise.then(() =>
|
||||||
return returnPromise.then((keys) =>
|
textures.map((key) => {
|
||||||
keys.map((key) => {
|
return key.id;
|
||||||
return typeof key !== "string" ? key.id : key;
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createLoadingPromise = (
|
|
||||||
loadPlugin: LoaderPlugin,
|
|
||||||
playerResourceDescriptor: BodyResourceDescriptionInterface,
|
|
||||||
frameConfig: FrameConfig
|
|
||||||
) => {
|
|
||||||
return new CancelablePromise<BodyResourceDescriptionInterface>((res, rej, cancel) => {
|
|
||||||
if (loadPlugin.textureManager.exists(playerResourceDescriptor.id)) {
|
|
||||||
return res(playerResourceDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(() => {
|
|
||||||
loadPlugin.off("loaderror");
|
|
||||||
loadPlugin.off("filecomplete-spritesheet-" + playerResourceDescriptor.id);
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
loadPlugin.spritesheet(playerResourceDescriptor.id, playerResourceDescriptor.img, frameConfig);
|
|
||||||
const errorCallback = (file: { src: string }) => {
|
|
||||||
if (file.src !== playerResourceDescriptor.img) return;
|
|
||||||
console.error("failed loading player resource: ", playerResourceDescriptor);
|
|
||||||
rej(playerResourceDescriptor);
|
|
||||||
loadPlugin.off("filecomplete-spritesheet-" + playerResourceDescriptor.id, successCallback);
|
|
||||||
loadPlugin.off("loaderror", errorCallback);
|
|
||||||
};
|
|
||||||
const successCallback = () => {
|
|
||||||
loadPlugin.off("loaderror", errorCallback);
|
|
||||||
res(playerResourceDescriptor);
|
|
||||||
};
|
|
||||||
|
|
||||||
loadPlugin.once("filecomplete-spritesheet-" + playerResourceDescriptor.id, successCallback);
|
|
||||||
loadPlugin.on("loaderror", errorCallback);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||||
import { ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
import { ActionsMenuAction, ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||||
import { Character } from "../Entity/Character";
|
import { Character } from "../Entity/Character";
|
||||||
import type { GameScene } from "../Game/GameScene";
|
import type { GameScene } from "../Game/GameScene";
|
||||||
import type { PointInterface } from "../../Connexion/ConnexionModels";
|
import type { PointInterface } from "../../Connexion/ConnexionModels";
|
||||||
@@ -8,21 +8,28 @@ import type { Unsubscriber } from "svelte/store";
|
|||||||
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
||||||
import type CancelablePromise from "cancelable-promise";
|
import type CancelablePromise from "cancelable-promise";
|
||||||
import LL from "../../i18n/i18n-svelte";
|
import LL from "../../i18n/i18n-svelte";
|
||||||
|
import { blackListManager } from "../../WebRtc/BlackListManager";
|
||||||
|
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
||||||
|
|
||||||
|
export enum RemotePlayerEvent {
|
||||||
|
Clicked = "Clicked",
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||||
*/
|
*/
|
||||||
export class RemotePlayer extends Character implements ActivatableInterface {
|
export class RemotePlayer extends Character implements ActivatableInterface {
|
||||||
public userId: number;
|
public readonly userId: number;
|
||||||
|
public readonly userUuid: string;
|
||||||
public readonly activationRadius: number;
|
public readonly activationRadius: number;
|
||||||
|
|
||||||
private registeredActions: { actionName: string; callback: Function }[];
|
|
||||||
private visitCardUrl: string | null;
|
private visitCardUrl: string | null;
|
||||||
private isActionsMenuInitialized: boolean = false;
|
private isActionsMenuInitialized: boolean = false;
|
||||||
private actionsMenuStoreUnsubscriber: Unsubscriber;
|
private actionsMenuStoreUnsubscriber: Unsubscriber;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
userId: number,
|
userId: number,
|
||||||
|
userUuid: string,
|
||||||
Scene: GameScene,
|
Scene: GameScene,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
@@ -39,10 +46,9 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
|
|
||||||
//set data
|
//set data
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.userUuid = userUuid;
|
||||||
this.visitCardUrl = visitCardUrl;
|
this.visitCardUrl = visitCardUrl;
|
||||||
this.registeredActions = [];
|
this.setClickable(this.getDefaultActionsMenuActions().length > 0);
|
||||||
this.registerDefaultActionsMenuActions();
|
|
||||||
this.setClickable(this.registeredActions.length > 0);
|
|
||||||
this.activationRadius = activationRadius ?? 96;
|
this.activationRadius = activationRadius ?? 96;
|
||||||
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
||||||
this.isActionsMenuInitialized = value ? true : false;
|
this.isActionsMenuInitialized = value ? true : false;
|
||||||
@@ -63,17 +69,19 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerActionsMenuAction(action: { actionName: string; callback: Function }): void {
|
public registerActionsMenuAction(action: ActionsMenuAction): void {
|
||||||
this.registeredActions.push(action);
|
actionsMenuStore.addAction({
|
||||||
this.updateIsClickable();
|
...action,
|
||||||
|
priority: action.priority ?? 0,
|
||||||
|
callback: () => {
|
||||||
|
action.callback();
|
||||||
|
actionsMenuStore.clear();
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public unregisterActionsMenuAction(actionName: string) {
|
public unregisterActionsMenuAction(actionName: string) {
|
||||||
const index = this.registeredActions.findIndex((action) => action.actionName === actionName);
|
actionsMenuStore.removeAction(actionName);
|
||||||
if (index !== -1) {
|
|
||||||
this.registeredActions.splice(index, 1);
|
|
||||||
}
|
|
||||||
this.updateIsClickable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public activate(): void {
|
public activate(): void {
|
||||||
@@ -90,37 +98,52 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
|||||||
return this.isClickable();
|
return this.isClickable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateIsClickable(): void {
|
|
||||||
this.setClickable(this.registeredActions.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private toggleActionsMenu(): void {
|
private toggleActionsMenu(): void {
|
||||||
if (this.isActionsMenuInitialized) {
|
if (this.isActionsMenuInitialized) {
|
||||||
actionsMenuStore.clear();
|
actionsMenuStore.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
actionsMenuStore.initialize(this.playerName);
|
actionsMenuStore.initialize(this.playerName);
|
||||||
for (const action of this.registeredActions) {
|
for (const action of this.getDefaultActionsMenuActions()) {
|
||||||
actionsMenuStore.addAction(action.actionName, action.callback);
|
actionsMenuStore.addAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerDefaultActionsMenuActions(): void {
|
private getDefaultActionsMenuActions(): ActionsMenuAction[] {
|
||||||
|
const actions: ActionsMenuAction[] = [];
|
||||||
if (this.visitCardUrl) {
|
if (this.visitCardUrl) {
|
||||||
this.registeredActions.push({
|
actions.push({
|
||||||
actionName: LL.woka.menu.businessCard(),
|
actionName: LL.woka.menu.businessCard(),
|
||||||
|
protected: true,
|
||||||
|
priority: 1,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
requestVisitCardsStore.set(this.visitCardUrl);
|
requestVisitCardsStore.set(this.visitCardUrl);
|
||||||
actionsMenuStore.clear();
|
actionsMenuStore.clear();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actions.push({
|
||||||
|
actionName: blackListManager.isBlackListed(this.userUuid)
|
||||||
|
? LL.report.block.unblock()
|
||||||
|
: LL.report.block.block(),
|
||||||
|
protected: true,
|
||||||
|
priority: -1,
|
||||||
|
style: "is-error",
|
||||||
|
callback: () => {
|
||||||
|
showReportScreenStore.set({ userId: this.userId, userName: this.name });
|
||||||
|
actionsMenuStore.clear();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindEventHandlers(): void {
|
private bindEventHandlers(): void {
|
||||||
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
||||||
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
|
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
|
||||||
this.toggleActionsMenu();
|
this.toggleActionsMenu();
|
||||||
|
this.emit(RemotePlayerEvent.Clicked);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class GameManager {
|
|||||||
private companion: string | null;
|
private companion: string | null;
|
||||||
private startRoom!: Room;
|
private startRoom!: Room;
|
||||||
private cameraSetup?: { video: unknown; audio: unknown };
|
private cameraSetup?: { video: unknown; audio: unknown };
|
||||||
currentGameSceneName: string | null = null;
|
private currentGameSceneName: string | null = null;
|
||||||
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
||||||
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { soundManager } from "./SoundManager";
|
|||||||
import { SharedVariablesManager } from "./SharedVariablesManager";
|
import { SharedVariablesManager } from "./SharedVariablesManager";
|
||||||
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
||||||
|
|
||||||
import { lazyLoadPlayerCharacterTextures, loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||||
import { iframeListener } from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, JITSI_URL, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
@@ -30,7 +30,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
|
|||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
||||||
import { Loader } from "../Components/Loader";
|
import { Loader } from "../Components/Loader";
|
||||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
import { RemotePlayer, RemotePlayerEvent } from "../Entity/RemotePlayer";
|
||||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||||
@@ -97,8 +97,10 @@ import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
|
|||||||
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
|
||||||
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
|
||||||
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
|
||||||
import { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
|
import type { VideoPeer } from "../../WebRtc/VideoPeer";
|
||||||
import CancelablePromise from "cancelable-promise";
|
import CancelablePromise from "cancelable-promise";
|
||||||
|
import { Deferred } from "ts-deferred";
|
||||||
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
reconnecting: boolean;
|
reconnecting: boolean;
|
||||||
@@ -164,13 +166,9 @@ export class GameScene extends DirtyScene {
|
|||||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||||
public connection: RoomConnection | undefined;
|
public connection: RoomConnection | undefined;
|
||||||
private simplePeer!: SimplePeer;
|
private simplePeer!: SimplePeer;
|
||||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
private connectionAnswerPromiseDeferred: Deferred<RoomJoinedMessageInterface>;
|
||||||
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)
|
||||||
private createPromise: Promise<void>;
|
private createPromiseDeferred: Deferred<void>;
|
||||||
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
|
|
||||||
private iframeSubscriptionList!: Array<Subscription>;
|
private iframeSubscriptionList!: Array<Subscription>;
|
||||||
private peerStoreUnsubscribe!: Unsubscriber;
|
private peerStoreUnsubscribe!: Unsubscriber;
|
||||||
private emoteUnsubscribe!: Unsubscriber;
|
private emoteUnsubscribe!: Unsubscriber;
|
||||||
@@ -220,6 +218,7 @@ export class GameScene extends DirtyScene {
|
|||||||
private loader: Loader;
|
private loader: Loader;
|
||||||
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
|
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
|
||||||
private firstCameraUpdateSent: boolean = false;
|
private firstCameraUpdateSent: boolean = false;
|
||||||
|
public readonly superLoad: SuperLoaderPlugin;
|
||||||
|
|
||||||
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
|
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
|
||||||
super({
|
super({
|
||||||
@@ -232,13 +231,10 @@ export class GameScene extends DirtyScene {
|
|||||||
this.MapUrlFile = MapUrlFile;
|
this.MapUrlFile = MapUrlFile;
|
||||||
this.roomUrl = room.key;
|
this.roomUrl = room.key;
|
||||||
|
|
||||||
this.createPromise = new Promise<void>((resolve, reject): void => {
|
this.createPromiseDeferred = new Deferred<void>();
|
||||||
this.createPromiseResolve = resolve;
|
this.connectionAnswerPromiseDeferred = new Deferred<RoomJoinedMessageInterface>();
|
||||||
});
|
|
||||||
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
|
|
||||||
this.connectionAnswerPromiseResolve = resolve;
|
|
||||||
});
|
|
||||||
this.loader = new Loader(this);
|
this.loader = new Loader(this);
|
||||||
|
this.superLoad = new SuperLoaderPlugin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//hook preload scene
|
//hook preload scene
|
||||||
@@ -408,11 +404,11 @@ export class GameScene extends DirtyScene {
|
|||||||
this.load.on("complete", () => {
|
this.load.on("complete", () => {
|
||||||
// FIXME: the factory might fail because the resources might not be loaded yet...
|
// FIXME: the factory might fail because the resources might not be loaded yet...
|
||||||
// We would need to add a loader ended event in addition to the createPromise
|
// We would need to add a loader ended event in addition to the createPromise
|
||||||
this.createPromise
|
this.createPromiseDeferred.promise
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
itemFactory.create(this);
|
itemFactory.create(this);
|
||||||
|
|
||||||
const roomJoinedAnswer = await this.connectionAnswerPromise;
|
const roomJoinedAnswer = await this.connectionAnswerPromiseDeferred.promise;
|
||||||
|
|
||||||
for (const object of objectsOfType) {
|
for (const object of objectsOfType) {
|
||||||
// TODO: we should pass here a factory to create sprites (maybe?)
|
// TODO: we should pass here a factory to create sprites (maybe?)
|
||||||
@@ -609,7 +605,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createPromiseResolve();
|
this.createPromiseDeferred.resolve();
|
||||||
// Now, let's load the script, if any
|
// Now, let's load the script, if any
|
||||||
const scripts = this.getScriptUrls(this.mapFile);
|
const scripts = this.getScriptUrls(this.mapFile);
|
||||||
const disableModuleMode = this.getProperty(this.mapFile, GameMapProperties.SCRIPT_DISABLE_MODULE_SUPPORT) as
|
const disableModuleMode = this.getProperty(this.mapFile, GameMapProperties.SCRIPT_DISABLE_MODULE_SUPPORT) as
|
||||||
@@ -635,7 +631,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const talkIconVolumeTreshold = 10;
|
const talkIconVolumeTreshold = 10;
|
||||||
let oldPeerNumber = 0;
|
const oldPeers = new Map<number, VideoPeer>();
|
||||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||||
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
|
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
|
||||||
this.volumeStoreUnsubscribers.clear();
|
this.volumeStoreUnsubscribers.clear();
|
||||||
@@ -652,10 +648,17 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newPeerNumber = peers.size;
|
const newPeerNumber = peers.size;
|
||||||
if (newPeerNumber > oldPeerNumber) {
|
if (newPeerNumber > oldPeers.size) {
|
||||||
this.playSound("audio-webrtc-in");
|
this.playSound("audio-webrtc-in");
|
||||||
} else if (newPeerNumber < oldPeerNumber) {
|
} else if (newPeerNumber < oldPeers.size) {
|
||||||
this.playSound("audio-webrtc-out");
|
this.playSound("audio-webrtc-out");
|
||||||
|
const oldPeersKeys = oldPeers.keys();
|
||||||
|
const newPeersKeys = Array.from(peers.keys());
|
||||||
|
for (const oldKey of oldPeersKeys) {
|
||||||
|
if (!newPeersKeys.includes(oldKey)) {
|
||||||
|
this.MapPlayersByKey.get(oldKey)?.showTalkIcon(false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (newPeerNumber > 0) {
|
if (newPeerNumber > 0) {
|
||||||
if (!this.localVolumeStoreUnsubscriber) {
|
if (!this.localVolumeStoreUnsubscriber) {
|
||||||
@@ -673,7 +676,10 @@ export class GameScene extends DirtyScene {
|
|||||||
this.localVolumeStoreUnsubscriber = undefined;
|
this.localVolumeStoreUnsubscriber = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldPeerNumber = newPeerNumber;
|
oldPeers.clear();
|
||||||
|
for (const [key, val] of peers) {
|
||||||
|
oldPeers.set(key, val);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
this.emoteUnsubscribe = emoteStore.subscribe((emote) => {
|
||||||
@@ -702,7 +708,11 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises])
|
Promise.all([
|
||||||
|
this.connectionAnswerPromiseDeferred.promise as Promise<unknown>,
|
||||||
|
...scriptPromises,
|
||||||
|
this.CurrentPlayer.getTextureLoadedPromise() as Promise<unknown>,
|
||||||
|
])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.scene.wake();
|
this.scene.wake();
|
||||||
})
|
})
|
||||||
@@ -739,7 +749,7 @@ export class GameScene extends DirtyScene {
|
|||||||
.then((onConnect: OnConnectInterface) => {
|
.then((onConnect: OnConnectInterface) => {
|
||||||
this.connection = onConnect.connection;
|
this.connection = onConnect.connection;
|
||||||
|
|
||||||
lazyLoadPlayerCharacterTextures(this.load, onConnect.room.characterLayers)
|
lazyLoadPlayerCharacterTextures(this.superLoad, onConnect.room.characterLayers)
|
||||||
.then((layers) => {
|
.then((layers) => {
|
||||||
this.currentPlayerTexturesResolve(layers);
|
this.currentPlayerTexturesResolve(layers);
|
||||||
})
|
})
|
||||||
@@ -868,7 +878,7 @@ export class GameScene extends DirtyScene {
|
|||||||
);
|
);
|
||||||
|
|
||||||
//this.initUsersPosition(roomJoinedMessage.users);
|
//this.initUsersPosition(roomJoinedMessage.users);
|
||||||
this.connectionAnswerPromiseResolve(onConnect.room);
|
this.connectionAnswerPromiseDeferred.resolve(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.
|
||||||
|
|
||||||
if (this.scene.isSleeping()) {
|
if (this.scene.isSleeping()) {
|
||||||
@@ -1108,6 +1118,23 @@ ${escapedMessage}
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.iframeSubscriptionList.push(
|
||||||
|
iframeListener.addActionsMenuKeyToRemotePlayerStream.subscribe((data) => {
|
||||||
|
this.MapPlayersByKey.get(data.id)?.registerActionsMenuAction({
|
||||||
|
actionName: data.actionKey,
|
||||||
|
callback: () => {
|
||||||
|
iframeListener.sendActionsMenuActionClickedEvent({ actionName: data.actionKey, id: data.id });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.iframeSubscriptionList.push(
|
||||||
|
iframeListener.removeActionsMenuKeyFromRemotePlayerEvent.subscribe((data) => {
|
||||||
|
this.MapPlayersByKey.get(data.id)?.unregisterActionsMenuAction(data.actionKey);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.iframeSubscriptionList.push(
|
this.iframeSubscriptionList.push(
|
||||||
iframeListener.trackCameraUpdateStream.subscribe(() => {
|
iframeListener.trackCameraUpdateStream.subscribe(() => {
|
||||||
if (!this.firstCameraUpdateSent) {
|
if (!this.firstCameraUpdateSent) {
|
||||||
@@ -1266,7 +1293,7 @@ ${escapedMessage}
|
|||||||
iframeListener.registerAnswerer("getState", async () => {
|
iframeListener.registerAnswerer("getState", async () => {
|
||||||
// The sharedVariablesManager is not instantiated before the connection is established. So we need to wait
|
// The sharedVariablesManager is not instantiated before the connection is established. So we need to wait
|
||||||
// for the connection to send back the answer.
|
// for the connection to send back the answer.
|
||||||
await this.connectionAnswerPromise;
|
await this.connectionAnswerPromiseDeferred.promise;
|
||||||
return {
|
return {
|
||||||
mapUrl: this.MapUrlFile,
|
mapUrl: this.MapUrlFile,
|
||||||
startLayerName: this.startPositionCalculator.startLayerName,
|
startLayerName: this.startPositionCalculator.startLayerName,
|
||||||
@@ -1289,7 +1316,7 @@ ${escapedMessage}
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
|
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
|
||||||
return this.connectionAnswerPromise.then(() => {
|
return this.connectionAnswerPromiseDeferred.promise.then(() => {
|
||||||
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
||||||
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
||||||
let newFirstgid = 1;
|
let newFirstgid = 1;
|
||||||
@@ -1890,9 +1917,10 @@ ${escapedMessage}
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, addPlayerData.characterLayers);
|
const texturesPromise = lazyLoadPlayerCharacterTextures(this.superLoad, addPlayerData.characterLayers);
|
||||||
const player = new RemotePlayer(
|
const player = new RemotePlayer(
|
||||||
addPlayerData.userId,
|
addPlayerData.userId,
|
||||||
|
addPlayerData.userUuid,
|
||||||
this,
|
this,
|
||||||
addPlayerData.position.x,
|
addPlayerData.position.x,
|
||||||
addPlayerData.position.y,
|
addPlayerData.position.y,
|
||||||
@@ -1920,6 +1948,10 @@ ${escapedMessage}
|
|||||||
this.activatablesManager.handlePointerOutActivatableObject();
|
this.activatablesManager.handlePointerOutActivatableObject();
|
||||||
this.markDirty();
|
this.markDirty();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
player.on(RemotePlayerEvent.Clicked, () => {
|
||||||
|
iframeListener.sendRemotePlayerClickedEvent({ id: player.userId });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2056,8 +2088,6 @@ ${escapedMessage}
|
|||||||
right: camera.scrollX + camera.width,
|
right: camera.scrollX + camera.width,
|
||||||
bottom: camera.scrollY + camera.height,
|
bottom: camera.scrollY + camera.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loader.resize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getObjectLayerData(objectName: string): ITiledMapObject | undefined {
|
private getObjectLayerData(objectName: string): ITiledMapObject | undefined {
|
||||||
|
|||||||