merged develop
@@ -45,7 +45,7 @@ server {
|
||||
rewrite ^/jwt /index.html break;
|
||||
}
|
||||
|
||||
location ~ ^/[@_]/ {
|
||||
location ~ ^/[@_*]/ {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
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 { 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;
|
||||
@@ -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",
|
||||
|
||||
@@ -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}>×</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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
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");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,9 @@ export class RoomConnection implements RoomConnection {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.closed) {
|
||||
this.closeConnection();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||