merged develop

This commit is contained in:
Piotr 'pwh' Hanusiak
2022-03-24 14:56:42 +01:00
137 changed files with 1628 additions and 1402 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ server {
rewrite ^/jwt /index.html break;
}
location ~ ^/[@_]/ {
location ~ ^/[@_*]/ {
try_files $uri $uri/ /index.html;
}
}
+1
View File
@@ -58,6 +58,7 @@
"simple-peer": "^9.11.0",
"socket.io-client": "^2.3.0",
"standardized-audio-context": "^25.2.4",
"ts-deferred": "^1.0.4",
"ts-proto": "^1.96.0",
"typesafe-i18n": "^2.59.0",
"uuidv4": "^6.2.10",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

-77
View File
@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

-1
View File
@@ -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

-16
View File
@@ -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

File diff suppressed because one or more lines are too long

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

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;
+9
View File
@@ -36,6 +36,10 @@ import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
import { isColorEvent } from "./ColorEvent";
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
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 {
data: T;
@@ -45,6 +49,8 @@ export interface TypedMessageEvent<T> extends MessageEvent {
* List event types sent from an iFrame to WorkAdventure
*/
export type IframeEventMap = {
addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent;
removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent;
loadPage: LoadPageEvent;
chat: ChatEvent;
cameraFollowPlayer: CameraFollowPlayerEvent;
@@ -58,6 +64,7 @@ export type IframeEventMap = {
displayBubble: null;
removeBubble: null;
onPlayerMove: undefined;
onOpenActionMenu: undefined;
onCameraUpdate: undefined;
showLayer: LayerEvent;
hideLayer: LayerEvent;
@@ -90,6 +97,8 @@ export interface IframeResponseEventMap {
enterZoneEvent: ChangeZoneEvent;
leaveZoneEvent: ChangeZoneEvent;
buttonClickedEvent: ButtonClickedEvent;
remotePlayerClickedEvent: RemotePlayerClickedEvent;
actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent;
hasPlayerMoved: HasPlayerMovedEvent;
wasCameraUpdated: WasCameraUpdatedEvent;
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;
+43
View File
@@ -34,6 +34,16 @@ import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
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> = (
query: IframeQueryMap[T]["query"],
@@ -63,6 +73,15 @@ class IframeListener {
private readonly _cameraFollowPlayerStream: Subject<CameraFollowPlayerEvent> = new Subject();
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();
public readonly enablePlayerControlStream = this._enablePlayerControlStream.asObservable();
@@ -241,6 +260,16 @@ class IframeListener {
this._removeBubbleStream.next();
} else if (payload.type == "onPlayerMove") {
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") {
this._trackCameraUpdateStream.next();
} 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) {
this.postMessage({
type: "wasCameraUpdated",
+113 -5
View File
@@ -8,6 +8,12 @@ import { ActionMessage } from "./Ui/ActionMessage";
import { isMessageReferenceEvent } from "../Events/ui/TriggerActionMessageEvent";
import { Menu } from "./Ui/Menu";
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;
const popups: Map<number, Popup> = new Map<number, Popup>();
@@ -42,7 +48,77 @@ export interface ActionMessageOptions {
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> {
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 = [
apiCallback({
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++;
const popup = new Popup(popupId);
const btnMap = new Map<number, () => void>();
@@ -119,7 +224,10 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
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);
if (typeof options === "function") {
@@ -168,15 +276,15 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
return menu;
}
displayBubble(): void {
public displayBubble(): void {
sendToWorkadventure({ type: "displayBubble", data: null });
}
removeBubble(): void {
public removeBubble(): void {
sendToWorkadventure({ type: "removeBubble", data: null });
}
displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
public displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
const actionMessage = new ActionMessage(actionMessageOptions, () => {
actionMessages.delete(actionMessage.uuid);
});
@@ -2,10 +2,12 @@
import { actionsMenuStore } from "../../Stores/ActionsMenuStore";
import { onDestroy } from "svelte";
import type { ActionsMenuAction } from "../../Stores/ActionsMenuStore";
import type { Unsubscriber } from "svelte/store";
import type { ActionsMenuData } from "../../Stores/ActionsMenuStore";
let actionsMenuData: ActionsMenuData | undefined;
let sortedActions: ActionsMenuAction[] | undefined;
let actionsMenuStoreUnsubscriber: Unsubscriber | null;
@@ -21,6 +23,20 @@
actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((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(() => {
@@ -37,15 +53,15 @@
<button type="button" class="nes-btn is-error close" on:click={closeActionsMenu}>&times</button>
<h2>{actionsMenuData.playerName}</h2>
<div class="actions">
{#each [...actionsMenuData.actions] as { actionName, callback }}
{#each sortedActions ?? [] as action}
<button
type="button"
class="nes-btn"
class="nes-btn {action.style ?? ''}"
on:click|preventDefault={() => {
callback();
action.callback();
}}
>
{actionName}
{action.actionName}
</button>
{/each}
</div>
@@ -61,6 +77,7 @@
height: max-content !important;
max-height: 40vh;
margin-top: 200px;
z-index: 425;
pointer-events: auto;
font-family: "Press Start 2P";
@@ -68,7 +85,7 @@
color: whitesmoke;
.actions {
max-height: calc(100% - 50px);
max-height: 30vh;
width: 100%;
display: block;
overflow-x: hidden;
@@ -9,6 +9,8 @@
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import uploadFile from "../images/jitsi.png";
export let index: number;
export let coWebsite: CoWebsite;
export let vertical: boolean;
@@ -21,7 +23,7 @@
onMount(() => {
icon.src = isJitsi
? "/resources/logos/jitsi.png"
? uploadFile
: `${ICON_URL}/icon?url=${coWebsite.getUrl().hostname}&size=64..96..256&fallback_icon_color=14304c`;
icon.alt = coWebsite.getUrl().hostname;
icon.onload = () => {
@@ -350,9 +352,14 @@
color: white;
padding: 4px;
border-radius: 4px;
p {
margin-bottom: 0;
}
&.hide {
display: none;
}
}
}
</style>
@@ -18,5 +18,7 @@
display: flex;
padding-top: 2%;
height: 100%;
position: relative;
z-index: 200;
}
</style>
@@ -1,8 +1,6 @@
<script lang="ts">
import { fly } from "svelte/transition";
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 LL from "../../i18n/i18n-svelte";
@@ -33,9 +31,9 @@
<p class="err">
{$LL.camera.help.firefoxContent()}
</p>
<img src={firefoxImg} alt="" />
<img src={$LL.camera.help.screen.firefox()} alt="" />
{:else if isChrome && !isAndroid}
<img src={chromeImg} alt="" />
<img src={$LL.camera.help.screen.chrome()} alt="" />
{/if}
</p>
</section>
+14 -1
View File
@@ -3,6 +3,7 @@
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
import { DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
import logoImg from "../images/logo.png";
import poweredByWorkAdventureImg from "../images/Powered_By_WorkAdventure_Big.png";
import { gameManager } from "../../Phaser/Game/GameManager";
import LL from "../../i18n/i18n-svelte";
@@ -13,6 +14,8 @@
let name = gameManager.getPlayerName() || "";
let startValidating = false;
let logo = gameManager.currentStartedRoom.loginSceneLogo ?? logoImg;
function submit() {
startValidating = true;
@@ -25,7 +28,7 @@
<form class="loginScene" on:submit|preventDefault={submit}>
<section class="text-center">
<img src={logoImg} alt="WorkAdventure logo" />
<img src={logo} alt="" />
</section>
<section class="text-center">
<h2>{$LL.login.input.name.placeholder()}</h2>
@@ -60,6 +63,11 @@
<section class="action">
<button type="submit" class="nes-btn is-primary loginSceneFormSubmit">{$LL.login.continue()}</button>
</section>
{#if logo !== logoImg}
<section class="text-center powered-by">
<img src={poweredByWorkAdventureImg} alt="Powered by WorkAdventure" />
</section>
{/if}
</form>
<style lang="scss">
@@ -132,6 +140,11 @@
width: 100%;
margin: 20px 0;
}
&.powered-by {
position: fixed;
bottom: 0;
}
}
}
</style>
+5 -4
View File
@@ -54,6 +54,7 @@
});
</script>
<!-- Components ordered by z-index -->
<div id="main-layout" bind:this={mainLayout}>
<aside id="main-layout-left-aside">
{#if $menuIconVisiblilityStore}
@@ -104,14 +105,14 @@
<ShareLinkMapModal />
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<FollowMenu />
{/if}
{#if $actionsMenuStore}
<ActionsMenu />
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<FollowMenu />
{/if}
{#if $requestVisitCardsStore}
<VisitCard visitCardUrl={$requestVisitCardsStore} />
{/if}
@@ -76,6 +76,7 @@
transform: translate(-50%, 0);
margin-top: 200px;
max-width: 80vw;
z-index: 350;
iframe {
border: 0;
Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

+18 -3
View File
@@ -330,9 +330,12 @@ class ConnectionManager {
throw new Error("No Auth code provided");
}
}
const { authToken, userUuid, email, username, locale } = await Axios.get(`${PUSHER_URL}/login-callback`, {
params: { code, nonce, token, playUri: this.currentRoom?.key },
}).then((res) => {
const { authToken, userUuid, email, username, locale, textures } = await Axios.get(
`${PUSHER_URL}/login-callback`,
{
params: { code, nonce, token, playUri: this.currentRoom?.key },
}
).then((res) => {
return res.data;
});
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
userIsConnected.set(true);
}
+12
View File
@@ -31,6 +31,8 @@ export class Room {
private _group: string | null = null;
private _expireOn: Date | undefined;
private _canReport: boolean = false;
private _loadingLogo: string | undefined;
private _loginSceneLogo: string | undefined;
private constructor(private roomUrl: URL) {
this.id = roomUrl.pathname;
@@ -126,6 +128,8 @@ export class Room {
this._expireOn = new Date(data.expireOn);
}
this._canReport = data.canReport ?? false;
this._loadingLogo = data.loadingLogo ?? undefined;
this._loginSceneLogo = data.loginSceneLogo ?? undefined;
return new MapDetail(data.mapUrl);
} else {
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 {
return this._canReport;
}
get loadingLogo(): string | undefined {
return this._loadingLogo;
}
get loginSceneLogo(): string | undefined {
return this._loginSceneLogo;
}
}
+2
View File
@@ -349,7 +349,9 @@ export class RoomConnection implements RoomConnection {
break;
}
}
if (this.closed) {
this.closeConnection();
break;
}
+71 -39
View File
@@ -1,10 +1,12 @@
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
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 LogoResource: string = "static/images/logo.png";
const LogoFrame: ImageFrameConfig = { frameWidth: 310, frameHeight: 60 };
const loadingBarHeight: number = 16;
const padding: number = 5;
@@ -14,9 +16,15 @@ export class Loader {
private progress!: Phaser.GameObjects.Graphics;
private progressAmount: number = 0;
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 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 {
// If there is nothing to load, do not display the loader.
@@ -24,43 +32,53 @@ export class Loader {
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 promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
return res(
(this.logo = this.scene.add.image(
this.scene.game.renderer.width / 2,
this.scene.game.renderer.height / 2 - 150,
LogoNameIndex
))
);
} else {
//add loading if logo image is not ready
this.loadingText = this.scene.add.text(
//add loading if logo image until logo image is ready
this.loadingText = this.scene.add.text(
this.scene.game.renderer.width / 2,
this.scene.game.renderer.height / 2 - 50,
TextName
);
const logoPromise = this.superLoad.image(this.logoNameIndex, logoResource);
logoPromise
.then((texture) => {
this.logo = this.scene.add.image(
this.scene.game.renderer.width / 2,
this.scene.game.renderer.height / 2 - 50,
TextName
this.scene.game.renderer.height / 2 - 150,
texture
);
}
this.scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
this.scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
if (this.loadingText) {
this.loadingText.destroy();
}
return res(
(this.logo = this.scene.add.image(
this.loadingText?.destroy();
})
.catch((e) => console.warn("Could not load logo: ", logoResource, e));
let poweredByLogoPromise: CancelablePromise<Texture> | undefined;
if (gameManager.currentStartedRoom.loadingLogo) {
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.height / 2 - 150,
LogoNameIndex
))
this.scene.game.renderer.height - 50,
texture
);
})
.catch((e) =>
console.warn('Could not load image "static/images/Powered_By_WorkAdventure_Small.png"', e)
);
});
});
}
this.progressContainer = this.scene.add.graphics();
this.progress = this.scene.add.graphics();
this.progressContainer.fillStyle(0x444444, 0.8);
this.progress = this.scene.add.graphics();
this.resize();
@@ -68,26 +86,35 @@ export class Loader {
this.progressAmount = value;
this.drawProgress();
});
const resizeFunction = this.resize.bind(this);
this.scene.scale.on(Phaser.Scale.Events.RESIZE, resizeFunction);
this.scene.load.on("complete", () => {
if (this.loadingText) {
this.loadingText.destroy();
}
promiseLoadLogoTexture
.then((resLoadingImage: Phaser.GameObjects.Image) => {
resLoadingImage.destroy();
})
.catch((e) => console.error(e));
logoPromise.cancel();
poweredByLogoPromise?.cancel();
this.logo?.destroy();
this.poweredByLogo?.destroy();
this.progress.destroy();
this.progressContainer.destroy();
if (this.scene instanceof DirtyScene) {
this.scene.markDirty();
}
this.scene.scale.off(Phaser.Scale.Events.RESIZE, resizeFunction);
});
}
public removeLoader(): void {
if (this.scene.load.textureManager.exists(LogoNameIndex)) {
this.scene.load.textureManager.remove(LogoNameIndex);
if (this.scene.load.textureManager.exists(this.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.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() {
+2 -2
View File
@@ -57,8 +57,8 @@ export class SoundMeter {
this.context = context;
this.analyser = this.context.createAnalyser();
this.analyser.fftSize = 2048;
const bufferLength = this.analyser.fftSize;
this.analyser.fftSize = 256;
const bufferLength = this.analyser.frequencyBinCount;
this.dataArray = new Uint8Array(bufferLength);
}
+31 -6
View File
@@ -23,6 +23,7 @@ import { createColorStore } from "../../Stores/OutlineColorStore";
import type { OutlineableInterface } from "../Game/OutlineableInterface";
import type CancelablePromise from "cancelable-promise";
import { TalkIcon } from "../Components/TalkIcon";
import { Deferred } from "ts-deferred";
const playerNameY = -25;
const interactiveRadius = 35;
@@ -46,6 +47,11 @@ export abstract class Character extends Container implements OutlineableInterfac
private readonly outlineColorStoreUnsubscribe: Unsubscriber;
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(
scene: GameScene,
x: number,
@@ -74,12 +80,13 @@ export abstract class Character extends Container implements OutlineableInterfac
this.addTextures(textures, frame);
this.invisible = false;
this.playAnimation(direction, moving);
this.textureLoadedDeferred.resolve();
return this.getSnapshot().then((htmlImageElementSrc) => {
this._pictureStore.set(htmlImageElementSrc);
});
})
.catch(() => {
return lazyLoadPlayerCharacterTextures(scene.load, [
return lazyLoadPlayerCharacterTextures(scene.superLoad, [
{
id: "color_22",
img: "resources/customisation/character_color/character_color21.png",
@@ -88,11 +95,20 @@ export abstract class Character extends Container implements OutlineableInterfac
id: "eyes_23",
img: "resources/customisation/character_eyes/character_eyes23.png",
},
]).then((textures) => {
this.addTextures(textures, frame);
this.invisible = false;
this.playAnimation(direction, moving);
});
])
.then((textures) => {
this.addTextures(textures, frame);
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(() => {
this.texturePromise = undefined;
@@ -453,4 +469,13 @@ export abstract class Character extends Container implements OutlineableInterfac
public characterFarAwayOutline(): void {
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;
}
}
+5 -21
View File
@@ -1,5 +1,7 @@
//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 {
[key: string]: BodyResourceDescriptionInterface;
}
@@ -33,24 +35,6 @@ export enum PlayerTexturesKey {
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 {
private PLAYER_RESOURCES: BodyResourceDescriptionListInterface = {};
private COLOR_RESOURCES: BodyResourceDescriptionListInterface = {};
@@ -61,7 +45,7 @@ export class PlayerTextures {
private ACCESSORIES_RESOURCES: BodyResourceDescriptionListInterface = {};
private LAYERS: BodyResourceDescriptionListInterface[] = [];
public loadPlayerTexturesMetadata(metadata: PlayerTexturesMetadata): void {
public loadPlayerTexturesMetadata(metadata: WokaList): void {
this.mapTexturesMetadataIntoResources(metadata);
}
@@ -88,7 +72,7 @@ export class PlayerTextures {
return this.LAYERS;
}
private mapTexturesMetadataIntoResources(metadata: PlayerTexturesMetadata): void {
private mapTexturesMetadataIntoResources(metadata: WokaList): void {
this.PLAYER_RESOURCES = this.getMappedResources(metadata.woka);
this.COLOR_RESOURCES = this.getMappedResources(metadata.body);
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 = {};
if (!category) {
return {};
@@ -2,6 +2,8 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin;
import type { CharacterTexture } from "../../Connexion/LocalUser";
import { BodyResourceDescriptionInterface, mapLayerToLevel, PlayerTextures, PlayerTexturesKey } from "./PlayerTextures";
import CancelablePromise from "cancelable-promise";
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
import Texture = Phaser.Textures.Texture;
export interface FrameConfig {
frameWidth: number;
@@ -35,81 +37,33 @@ export const loadAllDefaultModels = (
};
export const loadWokaTexture = (
loaderPlugin: LoaderPlugin,
superLoaderPlugin: SuperLoaderPlugin,
texture: BodyResourceDescriptionInterface
): CancelablePromise<BodyResourceDescriptionInterface> => {
return createLoadingPromise(loaderPlugin, texture, {
): CancelablePromise<Texture> => {
return superLoaderPlugin.spritesheet(texture.id, texture.img, {
frameWidth: 32,
frameHeight: 32,
});
};
export const lazyLoadPlayerCharacterTextures = (
loadPlugin: LoaderPlugin,
superLoaderPlugin: SuperLoaderPlugin,
textures: BodyResourceDescriptionInterface[]
): CancelablePromise<string[]> => {
const promisesList: CancelablePromise<unknown>[] = [];
textures.forEach((texture) => {
try {
//TODO refactor
if (!loadPlugin.textureManager.exists(texture.id)) {
promisesList.push(
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 promisesList: CancelablePromise<Texture>[] = [];
for (const texture of textures) {
promisesList.push(
superLoaderPlugin.spritesheet(texture.id, texture.img, {
frameWidth: 32,
frameHeight: 32,
})
);
}
const returnPromise: CancelablePromise<Texture[]> = CancelablePromise.all(promisesList);
//If the loading fail, we render the default model instead.
return returnPromise.then((keys) =>
keys.map((key) => {
return typeof key !== "string" ? key.id : key;
return returnPromise.then(() =>
textures.map((key) => {
return key.id;
})
);
};
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);
});
};
+45 -22
View File
@@ -1,5 +1,5 @@
import { requestVisitCardsStore } from "../../Stores/GameStore";
import { ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
import { ActionsMenuAction, ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
import { Character } from "../Entity/Character";
import type { GameScene } from "../Game/GameScene";
import type { PointInterface } from "../../Connexion/ConnexionModels";
@@ -8,21 +8,28 @@ import type { Unsubscriber } from "svelte/store";
import type { ActivatableInterface } from "../Game/ActivatableInterface";
import type CancelablePromise from "cancelable-promise";
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)
*/
export class RemotePlayer extends Character implements ActivatableInterface {
public userId: number;
public readonly userId: number;
public readonly userUuid: string;
public readonly activationRadius: number;
private registeredActions: { actionName: string; callback: Function }[];
private visitCardUrl: string | null;
private isActionsMenuInitialized: boolean = false;
private actionsMenuStoreUnsubscriber: Unsubscriber;
constructor(
userId: number,
userUuid: string,
Scene: GameScene,
x: number,
y: number,
@@ -39,10 +46,9 @@ export class RemotePlayer extends Character implements ActivatableInterface {
//set data
this.userId = userId;
this.userUuid = userUuid;
this.visitCardUrl = visitCardUrl;
this.registeredActions = [];
this.registerDefaultActionsMenuActions();
this.setClickable(this.registeredActions.length > 0);
this.setClickable(this.getDefaultActionsMenuActions().length > 0);
this.activationRadius = activationRadius ?? 96;
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
this.isActionsMenuInitialized = value ? true : false;
@@ -63,17 +69,19 @@ export class RemotePlayer extends Character implements ActivatableInterface {
}
}
public registerActionsMenuAction(action: { actionName: string; callback: Function }): void {
this.registeredActions.push(action);
this.updateIsClickable();
public registerActionsMenuAction(action: ActionsMenuAction): void {
actionsMenuStore.addAction({
...action,
priority: action.priority ?? 0,
callback: () => {
action.callback();
actionsMenuStore.clear();
},
});
}
public unregisterActionsMenuAction(actionName: string) {
const index = this.registeredActions.findIndex((action) => action.actionName === actionName);
if (index !== -1) {
this.registeredActions.splice(index, 1);
}
this.updateIsClickable();
actionsMenuStore.removeAction(actionName);
}
public activate(): void {
@@ -90,37 +98,52 @@ export class RemotePlayer extends Character implements ActivatableInterface {
return this.isClickable();
}
private updateIsClickable(): void {
this.setClickable(this.registeredActions.length > 0);
}
private toggleActionsMenu(): void {
if (this.isActionsMenuInitialized) {
actionsMenuStore.clear();
return;
}
actionsMenuStore.initialize(this.playerName);
for (const action of this.registeredActions) {
actionsMenuStore.addAction(action.actionName, action.callback);
for (const action of this.getDefaultActionsMenuActions()) {
actionsMenuStore.addAction(action);
}
}
private registerDefaultActionsMenuActions(): void {
private getDefaultActionsMenuActions(): ActionsMenuAction[] {
const actions: ActionsMenuAction[] = [];
if (this.visitCardUrl) {
this.registeredActions.push({
actions.push({
actionName: LL.woka.menu.businessCard(),
protected: true,
priority: 1,
callback: () => {
requestVisitCardsStore.set(this.visitCardUrl);
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 {
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
this.toggleActionsMenu();
this.emit(RemotePlayerEvent.Clicked);
}
});
}
+1 -1
View File
@@ -19,7 +19,7 @@ export class GameManager {
private companion: string | null;
private startRoom!: Room;
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.
private scenePlugin!: Phaser.Scenes.ScenePlugin;
+60 -30
View File
@@ -18,7 +18,7 @@ import { soundManager } from "./SoundManager";
import { SharedVariablesManager } from "./SharedVariablesManager";
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
import { lazyLoadPlayerCharacterTextures, loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
import { lazyLoadPlayerCharacterTextures } from "../Entity/PlayerTexturesLoadingManager";
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
import { iframeListener } from "../../Api/IframeListener";
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 { SimplePeer } from "../../WebRtc/SimplePeer";
import { Loader } from "../Components/Loader";
import { RemotePlayer } from "../Entity/RemotePlayer";
import { RemotePlayer, RemotePlayerEvent } from "../Entity/RemotePlayer";
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
import { PlayerAnimationDirections } from "../Player/Animation";
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
@@ -97,8 +97,10 @@ import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
import { JitsiCoWebsite } from "../../WebRtc/CoWebsite/JitsiCoWebsite";
import { SimpleCoWebsite } from "../../WebRtc/CoWebsite/SimpleCoWebsite";
import type { CoWebsite } from "../../WebRtc/CoWebsite/CoWesbite";
import { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
import type { VideoPeer } from "../../WebRtc/VideoPeer";
import CancelablePromise from "cancelable-promise";
import { Deferred } from "ts-deferred";
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
export interface GameSceneInitInterface {
initPosition: PointInterface | null;
reconnecting: boolean;
@@ -164,13 +166,9 @@ export class GameScene extends DirtyScene {
private playersPositionInterpolator = new PlayersPositionInterpolator();
public connection: RoomConnection | undefined;
private simplePeer!: SimplePeer;
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
private connectionAnswerPromiseResolve!: (
value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>
) => void;
private connectionAnswerPromiseDeferred: Deferred<RoomJoinedMessageInterface>;
// A promise that will resolve when the "create" method is called (signaling loading is ended)
private createPromise: Promise<void>;
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
private createPromiseDeferred: Deferred<void>;
private iframeSubscriptionList!: Array<Subscription>;
private peerStoreUnsubscribe!: Unsubscriber;
private emoteUnsubscribe!: Unsubscriber;
@@ -220,6 +218,7 @@ export class GameScene extends DirtyScene {
private loader: Loader;
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
private firstCameraUpdateSent: boolean = false;
public readonly superLoad: SuperLoaderPlugin;
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
super({
@@ -232,13 +231,10 @@ export class GameScene extends DirtyScene {
this.MapUrlFile = MapUrlFile;
this.roomUrl = room.key;
this.createPromise = new Promise<void>((resolve, reject): void => {
this.createPromiseResolve = resolve;
});
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
this.connectionAnswerPromiseResolve = resolve;
});
this.createPromiseDeferred = new Deferred<void>();
this.connectionAnswerPromiseDeferred = new Deferred<RoomJoinedMessageInterface>();
this.loader = new Loader(this);
this.superLoad = new SuperLoaderPlugin(this);
}
//hook preload scene
@@ -408,11 +404,11 @@ export class GameScene extends DirtyScene {
this.load.on("complete", () => {
// 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
this.createPromise
this.createPromiseDeferred.promise
.then(async () => {
itemFactory.create(this);
const roomJoinedAnswer = await this.connectionAnswerPromise;
const roomJoinedAnswer = await this.connectionAnswerPromiseDeferred.promise;
for (const object of objectsOfType) {
// 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
const scripts = this.getScriptUrls(this.mapFile);
const disableModuleMode = this.getProperty(this.mapFile, GameMapProperties.SCRIPT_DISABLE_MODULE_SUPPORT) as
@@ -635,7 +631,7 @@ export class GameScene extends DirtyScene {
}
const talkIconVolumeTreshold = 10;
let oldPeerNumber = 0;
const oldPeers = new Map<number, VideoPeer>();
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
this.volumeStoreUnsubscribers.forEach((unsubscribe) => unsubscribe());
this.volumeStoreUnsubscribers.clear();
@@ -652,10 +648,17 @@ export class GameScene extends DirtyScene {
}
const newPeerNumber = peers.size;
if (newPeerNumber > oldPeerNumber) {
if (newPeerNumber > oldPeers.size) {
this.playSound("audio-webrtc-in");
} else if (newPeerNumber < oldPeerNumber) {
} else if (newPeerNumber < oldPeers.size) {
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 (!this.localVolumeStoreUnsubscriber) {
@@ -673,7 +676,10 @@ export class GameScene extends DirtyScene {
this.localVolumeStoreUnsubscriber = undefined;
}
}
oldPeerNumber = newPeerNumber;
oldPeers.clear();
for (const [key, val] of peers) {
oldPeers.set(key, val);
}
});
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(() => {
this.scene.wake();
})
@@ -739,7 +749,7 @@ export class GameScene extends DirtyScene {
.then((onConnect: OnConnectInterface) => {
this.connection = onConnect.connection;
lazyLoadPlayerCharacterTextures(this.load, onConnect.room.characterLayers)
lazyLoadPlayerCharacterTextures(this.superLoad, onConnect.room.characterLayers)
.then((layers) => {
this.currentPlayerTexturesResolve(layers);
})
@@ -868,7 +878,7 @@ export class GameScene extends DirtyScene {
);
//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.
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(
iframeListener.trackCameraUpdateStream.subscribe(() => {
if (!this.firstCameraUpdateSent) {
@@ -1266,7 +1293,7 @@ ${escapedMessage}
iframeListener.registerAnswerer("getState", async () => {
// The sharedVariablesManager is not instantiated before the connection is established. So we need to wait
// for the connection to send back the answer.
await this.connectionAnswerPromise;
await this.connectionAnswerPromiseDeferred.promise;
return {
mapUrl: this.MapUrlFile,
startLayerName: this.startPositionCalculator.startLayerName,
@@ -1289,7 +1316,7 @@ ${escapedMessage}
})
);
iframeListener.registerAnswerer("loadTileset", (eventTileset) => {
return this.connectionAnswerPromise.then(() => {
return this.connectionAnswerPromiseDeferred.promise.then(() => {
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
let newFirstgid = 1;
@@ -1890,9 +1917,10 @@ ${escapedMessage}
return;
}
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, addPlayerData.characterLayers);
const texturesPromise = lazyLoadPlayerCharacterTextures(this.superLoad, addPlayerData.characterLayers);
const player = new RemotePlayer(
addPlayerData.userId,
addPlayerData.userUuid,
this,
addPlayerData.position.x,
addPlayerData.position.y,
@@ -1920,6 +1948,10 @@ ${escapedMessage}
this.activatablesManager.handlePointerOutActivatableObject();
this.markDirty();
});
player.on(RemotePlayerEvent.Clicked, () => {
iframeListener.sendRemotePlayerClickedEvent({ id: player.userId });
});
}
/**
@@ -2056,8 +2088,6 @@ ${escapedMessage}
right: camera.scrollX + camera.width,
bottom: camera.scrollY + camera.height,
});
this.loader.resize();
}
private getObjectLayerData(objectName: string): ITiledMapObject | undefined {
@@ -1,41 +1,14 @@
import { ResizableScene } from "./ResizableScene";
import { BodyResourceDescriptionInterface, PlayerTexturesKey } from "../Entity/PlayerTextures";
import { loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
import type CancelablePromise from "cancelable-promise";
import { PlayerTextures } from "../Entity/PlayerTextures";
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
export abstract class AbstractCharacterScene extends ResizableScene {
protected playerTextures: PlayerTextures;
protected superLoad: SuperLoaderPlugin;
constructor(params: { key: string }) {
super(params);
this.playerTextures = new PlayerTextures();
}
loadCustomSceneSelectCharacters(): Promise<BodyResourceDescriptionInterface[]> {
const textures = this.playerTextures.getTexturesResources(PlayerTexturesKey.Woka);
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
if (textures) {
for (const texture of Object.values(textures)) {
if (texture.level === -1) {
continue;
}
promises.push(loadWokaTexture(this.load, texture));
}
}
return Promise.all(promises);
}
loadSelectSceneCharacters(): Promise<BodyResourceDescriptionInterface[]> {
const promises: CancelablePromise<BodyResourceDescriptionInterface>[] = [];
for (const textures of this.playerTextures.getLayers()) {
for (const texture of Object.values(textures)) {
if (texture.level !== -1) {
continue;
}
promises.push(loadWokaTexture(this.load, texture));
}
}
return Promise.all(promises);
this.superLoad = new SuperLoaderPlugin(this);
}
}
+22 -36
View File
@@ -25,6 +25,7 @@ import {
} from "../Components/CustomizeWoka/WokaBodyPartSlot";
import { DraggableGridEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/DraggableGrid";
import { Button } from "../Components/Ui/Button";
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
export const CustomizeSceneName = "CustomizeScene";
@@ -63,45 +64,30 @@ export class CustomizeScene extends AbstractCharacterScene {
this.load.image("iconEyes", "/resources/icons/icon_eyes.png");
this.load.image("iconBody", "/resources/icons/icon_body.png");
const wokaMetadataKey = "woka-list";
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
this.cache.json.remove(wokaMetadataKey);
// FIXME: window.location.href is wrong. We need the URL of the main room (so we need to apply any redirect before!)
this.load.json(
wokaMetadataKey,
`${PUSHER_URL}/woka/list/` + encodeURIComponent(window.location.href),
undefined,
{
responseType: "text",
headers: {
Authorization: localUserStore.getAuthToken() ?? "",
this.superLoad
.json(
wokaMetadataKey,
`${PUSHER_URL}/woka/list?roomUrl=` + encodeURIComponent(gameManager.currentStartedRoom.href),
undefined,
{
responseType: "text",
headers: {
Authorization: localUserStore.getAuthToken() ?? "",
},
withCredentials: true,
},
withCredentials: true,
}
);
this.load.once(`filecomplete-json-${wokaMetadataKey}`, () => {
this.playerTextures.loadPlayerTexturesMetadata(this.cache.json.get(wokaMetadataKey));
this.loadCustomSceneSelectCharacters()
.then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
if (
bodyResourceDescription.level == undefined ||
bodyResourceDescription.level < 0 ||
bodyResourceDescription.level > 5
) {
throw new Error("Texture level is null");
}
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
})
.catch((e) => console.error(e));
(key, type, data) => {
this.playerTextures.loadPlayerTexturesMetadata(wokaList.parse(data));
this.layers = loadAllLayers(this.load, this.playerTextures);
this.lazyloadingAttempt = false;
//this function must stay at the end of preload function
this.loader.addLoader();
});
this.layers = loadAllLayers(this.load, this.playerTextures);
this.lazyloadingAttempt = false;
}
)
.catch((e) => console.error(e));
//this function must stay at the end of preload function
this.loader.addLoader();
}
public create(): void {
+2
View File
@@ -7,6 +7,8 @@ import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
import LL from "../../i18n/i18n-svelte";
import { get } from "svelte/store";
import { localeDetector } from "../../i18n/locales";
import { PlayerTextures } from "../Entity/PlayerTextures";
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
export const EntrySceneName = "EntryScene";
+22 -28
View File
@@ -16,6 +16,7 @@ import { analyticsClient } from "../../Administration/AnalyticsClient";
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
import { customizeAvailableStore } from "../../Stores/SelectCharacterSceneStore";
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
//todo: put this constants in a dedicated file
export const SelectCharacterSceneName = "SelectCharacterScene";
@@ -44,38 +45,31 @@ export class SelectCharacterScene extends AbstractCharacterScene {
}
preload() {
const wokaMetadataKey = "woka-list";
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
this.cache.json.remove(wokaMetadataKey);
// FIXME: window.location.href is wrong. We need the URL of the main room (so we need to apply any redirect before!)
this.load.json(
wokaMetadataKey,
`${PUSHER_URL}/woka/list/` + encodeURIComponent(window.location.href),
undefined,
{
responseType: "text",
headers: {
Authorization: localUserStore.getAuthToken() ?? "",
this.superLoad
.json(
wokaMetadataKey,
`${PUSHER_URL}/woka/list?roomUrl=` + encodeURIComponent(gameManager.currentStartedRoom.href),
undefined,
{
responseType: "text",
headers: {
Authorization: localUserStore.getAuthToken() ?? "",
},
withCredentials: true,
},
withCredentials: true,
}
);
this.load.once(`filecomplete-json-${wokaMetadataKey}`, () => {
this.playerTextures.loadPlayerTexturesMetadata(this.cache.json.get(wokaMetadataKey));
this.loadSelectSceneCharacters()
.then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
this.playerModels.push(bodyResourceDescription);
});
this.lazyloadingAttempt = true;
})
.catch((e) => console.error(e));
this.playerModels = loadAllDefaultModels(this.load, this.playerTextures);
this.lazyloadingAttempt = false;
(key, type, data) => {
this.playerTextures.loadPlayerTexturesMetadata(wokaList.parse(data));
this.playerModels = loadAllDefaultModels(this.load, this.playerTextures);
this.lazyloadingAttempt = false;
}
)
.catch((e) => console.error(e));
//this function must stay at the end of preload function
this.loader.addLoader();
});
//this function must stay at the end of preload function
this.loader.addLoader();
}
create() {

Some files were not shown because too many files have changed in this diff Show More