From f76abf3e338103d3a26a7bbfa99e00ff943fb741 Mon Sep 17 00:00:00 2001 From: Mirek Kaspar Date: Sat, 29 Apr 2023 15:41:54 +0200 Subject: [PATCH 1/4] New matchmaker queue screen with easy customization --- Matchmaker/.gitignore | 1 + Matchmaker/Docs/Customizing the Queue UI.md | 10 +++++ Matchmaker/README.md | 12 ++++++ Matchmaker/config.json | 3 +- .../html/sample/images/favicon-16x16.png | Bin 0 -> 959 bytes .../html/sample/images/favicon-32x32.png | Bin 0 -> 2240 bytes .../html/sample/images/favicon-96x96.png | Bin 0 -> 5649 bytes Matchmaker/html/sample/images/favicon.ico | Bin 0 -> 15086 bytes Matchmaker/html/sample/images/ue-logo.png | Bin 0 -> 17974 bytes Matchmaker/html/sample/queue/queue.html | 35 ++++++++++++++++++ Matchmaker/html/sample/queue/styles.css | 33 +++++++++++++++++ Matchmaker/matchmaker.js | 34 ++++++++++------- Matchmaker/package-lock.json | 4 +- 13 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 Matchmaker/.gitignore create mode 100644 Matchmaker/Docs/Customizing the Queue UI.md create mode 100644 Matchmaker/README.md create mode 100644 Matchmaker/html/sample/images/favicon-16x16.png create mode 100644 Matchmaker/html/sample/images/favicon-32x32.png create mode 100644 Matchmaker/html/sample/images/favicon-96x96.png create mode 100644 Matchmaker/html/sample/images/favicon.ico create mode 100644 Matchmaker/html/sample/images/ue-logo.png create mode 100644 Matchmaker/html/sample/queue/queue.html create mode 100644 Matchmaker/html/sample/queue/styles.css diff --git a/Matchmaker/.gitignore b/Matchmaker/.gitignore new file mode 100644 index 00000000..f00ee426 --- /dev/null +++ b/Matchmaker/.gitignore @@ -0,0 +1 @@ +html/custom/ \ No newline at end of file diff --git a/Matchmaker/Docs/Customizing the Queue UI.md b/Matchmaker/Docs/Customizing the Queue UI.md new file mode 100644 index 00000000..2858de44 --- /dev/null +++ b/Matchmaker/Docs/Customizing the Queue UI.md @@ -0,0 +1,10 @@ +## Customizing the Queue UI + +The Matchmaker server allows for custom HTML UI to be displayed. In order to create a custom queue UI template: + +1. Duplicate the `Matchmaker/html/sample` directory as `Matchmaker/html/custom`. +2. Edit `Matchmaker/html/custom/queue/queue.html` as needed. + +It is required to keep the same directory struture and file names for the template (`.html`) files. The Matchmaker server will prefer the `custom` directory over `sample`. The `custom` directory always needs to contain all templates from the `sample` directory. + +The `custom` directory can contain additional files, which may be referenced in the template files with a path relative to `Matchmaker/html/custom`. For example, an image located as `Matchmaker/html/custom/images/1.png` could be referenced as `` in a template (`.html`) file. diff --git a/Matchmaker/README.md b/Matchmaker/README.md new file mode 100644 index 00000000..92f83ffe --- /dev/null +++ b/Matchmaker/README.md @@ -0,0 +1,12 @@ +# Pixel Streaming Matchmaker + +Instead of having all users connect to the same stream, you may want each person to end up in their own interactive experiences. To do this, you can run a separate stack of Pixel Streaming components for each user, and direct each user to a separate Signaling and Web Server to start a connection. + +You can set up each stack of Pixel Streaming components on a separate host, or you can put more than one stack on the same host as long as you configure the port settings for the components within each stack so that they all communicate over different ports. See the Pixel Streaming Reference for details on these port settings. + +To help set up this kind of configuration, the Pixel Streaming system can use a **matchmaker** server that tracks which Signaling and Web Servers are available, and whether they are being used by a client connection. + + +## Docs +- [Hosting and Networking Guide](https://docs.unrealengine.com/5.1/en-US/hosting-and-networking-guide-for-pixel-streaming-in-unreal-engine/) +- [Customizing the Queue UI](Docs/Customizing%20the%20Queue%20UI.md) diff --git a/Matchmaker/config.json b/Matchmaker/config.json index 9ee3c27e..5cb0a20e 100644 --- a/Matchmaker/config.json +++ b/Matchmaker/config.json @@ -2,5 +2,6 @@ "HttpPort": 90, "UseHTTPS": false, "MatchmakerPort": 9999, - "LogToFile": true + "LogToFile": true, + "EnableWebserver": true } \ No newline at end of file diff --git a/Matchmaker/html/sample/images/favicon-16x16.png b/Matchmaker/html/sample/images/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..90dfb93008abb21f21759965739f1489a31ec160 GIT binary patch literal 959 zcma)(Ur1AN6vvO6IyJQ@^G|#4C< zq^IVk0zkUeVsfD05i?B!o=0?CNYpR`Qj$<)o7#f5B`B;`IEiEZ8H)8Oc z$M%8(&TKaM{XUba9ODf^WC)=sN=H$83^rQu+e+f^iL16(**1rg{vMl#u021ifY5PL4MgW8krx%A7f~UbkEJbR`&Cl9G}#T!%(e zcF!C4%pVZr&$=ONzSiY>J3TiuGdErDdY_p3>2sQ9X<=z`IZu;vwHvo$NOw<_r82kj z&Dg}nr+s~W+pE8%_Et_Dt=4A1%l)}y&*JwgI4oZ^pH@YWDhb}Ogbo-&8+4>VM;AF6 zA~1|VlVgMkggjn4XZWij5EK=;?cWWro{aZm!^zl$NKjT=Jz)u~0gq3zd3=huQESi_ z>Wg%|7DsaHBN=TiZP5BvH6&0}Yip}siP30C>w{t6yDJ}25OQLQPJcAeAPAL zWTi>M^{GI!+7$FrvZqDy2Ad<)pNFAjQR28lS(FLKvjwck)4V8)g&a#8*dm%pdhF2S T{SsCa@8Sfon(d|$qx;fNp-LZf literal 0 HcmV?d00001 diff --git a/Matchmaker/html/sample/images/favicon-32x32.png b/Matchmaker/html/sample/images/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..87bd73146a540936a1b80d46647ab5d5edf991fa GIT binary patch literal 2240 zcmZ{l2{e>#8^`aljwMZFn=D_J>@lmsV+mPC*&`H%Ss2-3P$SI9l6pn2trum|&e!*z^PT5h&vl;r`d$C)y3c*x=gIMOciteaA`Jl8 z;6icmhP}qRAtm5nnq`kMOeIDM%? z(dSeBm1wBU;5B)he_b_1GPLv6vx^9?_B8xr(D@jZZ|!=;?Ull$5|Gf}Qy)hBGnILL!qZ zY79Rvn3=1M52dZGD5MI*&h$+*YHMT!v)QF(W-$cI@21I1v*Lo~FX#W%m+q$h?wrT? zFuhO|^m&oZjEK-ulatTu>SeSwh$%Q~Vr1vL_0kZ*{pYNKtGheF)b!!lmZ;2tg-mYUoLHA17Z^YMp zti8jqsOOl$38?~u??!zngEqzuuYLPYc7*ijwTN>gZ>g%Oy`OvAAtr)ggoQOO`WP04 z9y-KbTSH`J_m3ssIkL8DAtNIb<7A6$>**nsnB<0%_jxL0uB=#Sokl8S*K)7jWBdFS zaeuUbVnX*cB|}Ep1eMpt3=gLxFMRzv_V>!|L+>QKKPj386mtrHKWmv(F$EEc2jZq*^dqx7Sc!@A zV-IE6$;nOZMZ=9-Y#v11nx7sf{`ClbARs_fP3}fRLl!E%p@IB$=A|=9#n{L}p40UX zaalA~>UIX|>a}b9XYd=GEPKl2!l`DhoMMlDki<-%DS9zTlX=_$WCyQwFI&#j6 zgM)+mC(^rV?Nf^rc?wO3Zr28h=;fqP6l{jMWjT z(yNr60dRLOT9VCXW@cEdyT^D_t{$V>7+JJj_VCDvJ@T}eF87e2wCuK+h-(vYy^s}fnEmIBHh_8uSiQSyB z9X(ojaIZ4wg~_9|-z76h1e zMW675s89%Uh@mD#(W6-q(r zrlvHU8I??@;&5g}a|;?H1V;^_hSG5)Jl&jZ0%w@O{n4y$sKOP1i=(>(&ptT)-x$io A^8f$< literal 0 HcmV?d00001 diff --git a/Matchmaker/html/sample/images/favicon-96x96.png b/Matchmaker/html/sample/images/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..ab2064a8715de1fd88d479ee63cb8a6f474bfce4 GIT binary patch literal 5649 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 literal 0 HcmV?d00001 diff --git a/Matchmaker/html/sample/images/favicon.ico b/Matchmaker/html/sample/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0b46e9800a59b31765d3a9495229dcd169394924 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/Matchmaker/html/sample/queue/queue.html b/Matchmaker/html/sample/queue/queue.html new file mode 100644 index 00000000..941ea439 --- /dev/null +++ b/Matchmaker/html/sample/queue/queue.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + +
+
+ +

All Streaming Hosts Busy

+

Please wait,

+

checking all ${cirrusServers.size} hosts again in 3 seconds.

+
+
+ + + + \ No newline at end of file diff --git a/Matchmaker/html/sample/queue/styles.css b/Matchmaker/html/sample/queue/styles.css new file mode 100644 index 00000000..194157fc --- /dev/null +++ b/Matchmaker/html/sample/queue/styles.css @@ -0,0 +1,33 @@ +* { box-sizing: border-box; } + +body { + background-color: black; + color: white; + font-family: 'Montserrat', sans-serif; + margin: 0; +} + +main { + display: flex; + height: 100vh; + justify-content: center; + align-items: center; +} + +section { + text-align: center; +} + +h1 { + font-size: 1.8em; + text-transform: uppercase; +} + +p { + text-align: center; +} + +#logo { + display: inline-block; + height: 20vh; +} \ No newline at end of file diff --git a/Matchmaker/matchmaker.js b/Matchmaker/matchmaker.js index a1afca6a..b9ff3bdb 100644 --- a/Matchmaker/matchmaker.js +++ b/Matchmaker/matchmaker.js @@ -10,7 +10,9 @@ const defaultConfig = { MatchmakerPort: 9999, // Log to file - LogToFile: true + LogToFile: true, + + EnableWebserver: true, }; // Similar to the Signaling Server (SS) code, load in a config.json file for the MM parameters @@ -86,21 +88,27 @@ if (config.UseHTTPS) { }); } +let htmlDirectory = 'html/sample' +if(config.EnableWebserver) { + // Setup folders + + if (fs.existsSync('html/custom')) { + app.use(express.static(path.join(__dirname, '/html/custom'))) + htmlDirectory = 'html/custom' + } else { + app.use(express.static(path.join(__dirname, '/html/sample'))) + } +} + // No servers are available so send some simple JavaScript to the client to make // it retry after a short period of time. function sendRetryResponse(res) { - res.send(`All ${cirrusServers.size} Cirrus servers are in use. Retrying in 3 seconds. - `); + // find check if a custom template should be used or the sample one + let html = fs.readFileSync(`${htmlDirectory}/queue/queue.html`, { encoding: 'utf8' }) + html = html.replace(/\$\{cirrusServers\.size\}/gm, cirrusServers.size) + + res.setHeader('content-type', 'text/html') + res.send(html) } // Get a Cirrus server if there is one available which has no clients connected. diff --git a/Matchmaker/package-lock.json b/Matchmaker/package-lock.json index 2cba76e5..55fe9616 100644 --- a/Matchmaker/package-lock.json +++ b/Matchmaker/package-lock.json @@ -1,11 +1,11 @@ { - "name": "cirrus-matchmaker", + "name": "@epicgames-ps/cirrus-matchmaker", "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "cirrus-matchmaker", + "name": "@epicgames-ps/cirrus-matchmaker", "version": "0.0.1", "dependencies": { "cors": "^2.8.5", From c6c3e4cd876c248b7962733f502d7a69403165fd Mon Sep 17 00:00:00 2001 From: Mirek Kaspar Date: Tue, 18 Jul 2023 10:11:13 +0300 Subject: [PATCH 2/4] fixed html template of the matchmaker queue screen --- Matchmaker/html/sample/queue/queue.html | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Matchmaker/html/sample/queue/queue.html b/Matchmaker/html/sample/queue/queue.html index 941ea439..1fe95dd8 100644 --- a/Matchmaker/html/sample/queue/queue.html +++ b/Matchmaker/html/sample/queue/queue.html @@ -1,15 +1,18 @@ - - - - - - - - - - - - + + + + + + Looking for a streaming host... + + + + + + + + +
From c6bfe087665ff928f2b9ead9315dddc53ae39663 Mon Sep 17 00:00:00 2001 From: mcottontensor <80377552+mcottontensor@users.noreply.github.com> Date: Tue, 25 Jul 2023 11:35:47 +1000 Subject: [PATCH 3/4] Create run-test.yml Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com> --- .github/workflows/run-test.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/run-test.yml diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml new file mode 100644 index 00000000..81b207db --- /dev/null +++ b/.github/workflows/run-test.yml @@ -0,0 +1,25 @@ +name: Run Stream Test + +on: workflow_dispatch + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 16.x, 18.x, 20.x] + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: Build Client + working-directory: ./Testing/StreamTest/TestClient + run: npm build + - name: Run Test + working-directory: ./Testing/StreamTest + run: npm start From f20b38bb306043a1681537838d18a5e69e9d2391 Mon Sep 17 00:00:00 2001 From: mcottontensor <80377552+mcottontensor@users.noreply.github.com> Date: Tue, 25 Jul 2023 11:45:43 +1000 Subject: [PATCH 4/4] Delete run-test.yml Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com> --- .github/workflows/run-test.yml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/run-test.yml diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml deleted file mode 100644 index 81b207db..00000000 --- a/.github/workflows/run-test.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Run Stream Test - -on: workflow_dispatch - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14.x, 16.x, 18.x, 20.x] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Build Client - working-directory: ./Testing/StreamTest/TestClient - run: npm build - - name: Run Test - working-directory: ./Testing/StreamTest - run: npm start