Set up basic WebSocket frontend
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | ||||
| assets/main.js | ||||
| dist | ||||
| node_modules | ||||
							
								
								
									
										39
									
								
								assets/game.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,39 @@ | ||||
| <!DOCTYPE html> | ||||
| <html style="height:100%"> | ||||
|   <head> | ||||
|     <link rel="manifest" href="manifest.json" /> | ||||
|     <link rel="icon" href="images/logo96.png" type="image/png" /> | ||||
|     <title>Blastmud</title> | ||||
|     <style> | ||||
|       .button { | ||||
|           border: solid black 1px; | ||||
|           padding: 5px; | ||||
|           cursor: pointer; | ||||
|           text-decoration: none; | ||||
|           border-radius: 10px; | ||||
|           color: white; | ||||
|           background: grey; | ||||
|       } | ||||
|     </style> | ||||
|     <link rel="stylesheet" href="xterm.css" /> | ||||
|     <script src="xterm.js"></script> | ||||
|   </head> | ||||
|   <body style="background: black; height: 100%"> | ||||
|     <div style="background: black; color: white; display: flex; flex-direction: column; margin: 0px; height: 100%; width: 100%"> | ||||
|       <h1 style="text-align: center">Play Blastmud</h1> | ||||
|       <div id="console" style="flex: 1"> </div> | ||||
|     </div> | ||||
|     <div id="over18" style="position: absolute; top: 0; left: 0; background: rgba(80,80,80,0.8); width: 100%; height: 100%"> | ||||
|       <div style="display: block; padding: 10px; background: white; width: 80%; margin-left: auto; margin-right: auto; margin-top: 10%; border-radius: 10px;"> | ||||
|         <h1>You must be 18+ to play Blastmud</h1> | ||||
|         <p>This game is restricted to adults (18 years or above). It contains violence, | ||||
|           sex scenes, and online interactions with other adults.</p> | ||||
|         <div style="text-align: right"> | ||||
|           <a class="button" href="https://google.com/">I'm under 18</a> | ||||
|           <a class="button" href="#" onclick="over18();">I'm 18 or over</a> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </body> | ||||
|   <script src="main.js"></script> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo144.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo168.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo48.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo72.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/images/logo96.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										38
									
								
								assets/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,38 @@ | ||||
| { | ||||
|   "$schema": "https://json.schemastore.org/web-manifest-combined.json", | ||||
|   "name": "BlastMud", | ||||
|   "short_name": "BlastMud", | ||||
|   "start_url": ".", | ||||
|   "display": "standalone", | ||||
|   "background_color": "#000", | ||||
|   "description": "A post-apocalyptic multi user dungeon game", | ||||
|   "icons": [{ | ||||
|     "src": "images/logo48.png", | ||||
|     "sizes": "48x48", | ||||
|     "type": "image/png" | ||||
|   }, { | ||||
|     "src": "images/logo72.png", | ||||
|     "sizes": "72x72", | ||||
|     "type": "image/png" | ||||
|   }, { | ||||
|     "src": "images/logo96.png", | ||||
|     "sizes": "96x96", | ||||
|     "type": "image/png" | ||||
|   }, { | ||||
|     "src": "images/logo144.png", | ||||
|     "sizes": "144x144", | ||||
|     "type": "image/png" | ||||
|   }, { | ||||
|     "src": "images/logo168.png", | ||||
|     "sizes": "168x168", | ||||
|     "type": "image/png" | ||||
|   }, { | ||||
|     "src": "images/logo192.png", | ||||
|     "sizes": "192x192", | ||||
|     "type": "image/png" | ||||
|   }], | ||||
|   "related_applications": [{ | ||||
|     "platform": "play", | ||||
|     "url": "https://play.google.com/store/apps/details?id=org.blastmud.game" | ||||
|   }] | ||||
| } | ||||
							
								
								
									
										9
									
								
								assets/offline.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,9 @@ | ||||
| <html> | ||||
|   <body> | ||||
|     <h1>You're offline</h1> | ||||
|     <p>This app only works when you are online. | ||||
|       Check your network connection and try again. | ||||
|       If your network connection is okay, our servers might be | ||||
|       under maintenance - try again later.</p> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										60
									
								
								assets/service-worker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,60 @@ | ||||
| /* | ||||
| Copyright 2015, 2019 Google Inc. All Rights Reserved. | ||||
|  Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  you may not use this file except in compliance with the License. | ||||
|  You may obtain a copy of the License at | ||||
|  http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  Unless required by applicable law or agreed to in writing, software | ||||
|  distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  See the License for the specific language governing permissions and | ||||
|  limitations under the License. | ||||
| */ | ||||
| const OFFLINE_VERSION = 1; | ||||
| const CACHE_NAME = 'offline'; | ||||
| const OFFLINE_URL = 'offline.html'; | ||||
| self.addEventListener('install', (event) => { | ||||
|   event.waitUntil((async () => { | ||||
|     const cache = await caches.open(CACHE_NAME); | ||||
|     await cache.add(new Request(OFFLINE_URL, {cache: 'reload'})); | ||||
|   })()); | ||||
| }); | ||||
| self.addEventListener('activate', (event) => { | ||||
|   event.waitUntil((async () => { | ||||
|     // Enable navigation preload if it's supported.
 | ||||
|     // See https://developers.google.com/web/updates/2017/02/navigation-preload
 | ||||
|     if ('navigationPreload' in self.registration) { | ||||
|       await self.registration.navigationPreload.enable(); | ||||
|     } | ||||
|   })()); | ||||
|   // Tell the active service worker to take control of the page immediately.
 | ||||
|   self.clients.claim(); | ||||
| }); | ||||
| self.addEventListener('fetch', (event) => { | ||||
|   // We only want to call event.respondWith() if this is a navigation request
 | ||||
|   // for an HTML page.
 | ||||
|   if (event.request.mode === 'navigate') { | ||||
|     event.respondWith((async () => { | ||||
|       try { | ||||
|         // First, try to use the navigation preload response if it's supported.
 | ||||
|         const preloadResponse = await event.preloadResponse; | ||||
|         if (preloadResponse && preloadResponse.type !== 'error') { | ||||
|           return preloadResponse; | ||||
|         } | ||||
| 
 | ||||
|         const networkResponse = await fetch(event.request); | ||||
|         return networkResponse; | ||||
|       } catch (error) { | ||||
|         // catch is only triggered if an exception is thrown, which is likely
 | ||||
|         // due to a network error.
 | ||||
|         // If fetch() returns a valid HTTP response with a response code in
 | ||||
|         // the 4xx or 5xx range, the catch() will NOT be called.
 | ||||
|         console.log('Fetch failed; returning offline page instead.', error); | ||||
| 
 | ||||
|         const cache = await caches.open(CACHE_NAME); | ||||
|         const cachedResponse = await cache.match(OFFLINE_URL); | ||||
|         return cachedResponse; | ||||
|       } | ||||
|     })()); | ||||
|   } | ||||
| }); | ||||
							
								
								
									
										191
									
								
								assets/xterm.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,191 @@ | ||||
| /** | ||||
|  * Copyright (c) 2014 The xterm.js authors. All rights reserved. | ||||
|  * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) | ||||
|  * https://github.com/chjj/term.js | ||||
|  * @license MIT | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * Originally forked from (with the author's permission): | ||||
|  *   Fabrice Bellard's javascript vt100 for jslinux: | ||||
|  *   http://bellard.org/jslinux/ | ||||
|  *   Copyright (c) 2011 Fabrice Bellard | ||||
|  *   The original design remains. The terminal itself | ||||
|  *   has been extended to include xterm CSI codes, among | ||||
|  *   other features. | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  *  Default styles for xterm.js | ||||
|  */ | ||||
| 
 | ||||
| .xterm { | ||||
|     cursor: text; | ||||
|     position: relative; | ||||
|     user-select: none; | ||||
|     -ms-user-select: none; | ||||
|     -webkit-user-select: none; | ||||
| } | ||||
| 
 | ||||
| .xterm.focus, | ||||
| .xterm:focus { | ||||
|     outline: none; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-helpers { | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     /** | ||||
|      * The z-index of the helpers must be higher than the canvases in order for | ||||
|      * IMEs to appear on top. | ||||
|      */ | ||||
|     z-index: 5; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-helper-textarea { | ||||
|     padding: 0; | ||||
|     border: 0; | ||||
|     margin: 0; | ||||
|     /* Move textarea out of the screen to the far left, so that the cursor is not visible */ | ||||
|     position: absolute; | ||||
|     opacity: 0; | ||||
|     left: -9999em; | ||||
|     top: 0; | ||||
|     width: 0; | ||||
|     height: 0; | ||||
|     z-index: -5; | ||||
|     /** Prevent wrapping so the IME appears against the textarea at the correct position */ | ||||
|     white-space: nowrap; | ||||
|     overflow: hidden; | ||||
|     resize: none; | ||||
| } | ||||
| 
 | ||||
| .xterm .composition-view { | ||||
|     /* TODO: Composition position got messed up somewhere */ | ||||
|     background: #000; | ||||
|     color: #FFF; | ||||
|     display: none; | ||||
|     position: absolute; | ||||
|     white-space: nowrap; | ||||
|     z-index: 1; | ||||
| } | ||||
| 
 | ||||
| .xterm .composition-view.active { | ||||
|     display: block; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-viewport { | ||||
|     /* On OS X this is required in order for the scroll bar to appear fully opaque */ | ||||
|     background-color: #000; | ||||
|     overflow-y: scroll; | ||||
|     cursor: default; | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-screen { | ||||
|     position: relative; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-screen canvas { | ||||
|     position: absolute; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-scroll-area { | ||||
|     visibility: hidden; | ||||
| } | ||||
| 
 | ||||
| .xterm-char-measure-element { | ||||
|     display: inline-block; | ||||
|     visibility: hidden; | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     left: -9999em; | ||||
|     line-height: normal; | ||||
| } | ||||
| 
 | ||||
| .xterm.enable-mouse-events { | ||||
|     /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ | ||||
|     cursor: default; | ||||
| } | ||||
| 
 | ||||
| .xterm.xterm-cursor-pointer, | ||||
| .xterm .xterm-cursor-pointer { | ||||
|     cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .xterm.column-select.focus { | ||||
|     /* Column selection mode */ | ||||
|     cursor: crosshair; | ||||
| } | ||||
| 
 | ||||
| .xterm .xterm-accessibility, | ||||
| .xterm .xterm-message { | ||||
|     position: absolute; | ||||
|     left: 0; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 10; | ||||
|     color: transparent; | ||||
| } | ||||
| 
 | ||||
| .xterm .live-region { | ||||
|     position: absolute; | ||||
|     left: -9999px; | ||||
|     width: 1px; | ||||
|     height: 1px; | ||||
|     overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| .xterm-dim { | ||||
|     opacity: 0.5; | ||||
| } | ||||
| 
 | ||||
| .xterm-underline-1 { text-decoration: underline; } | ||||
| .xterm-underline-2 { text-decoration: double underline; } | ||||
| .xterm-underline-3 { text-decoration: wavy underline; } | ||||
| .xterm-underline-4 { text-decoration: dotted underline; } | ||||
| .xterm-underline-5 { text-decoration: dashed underline; } | ||||
| 
 | ||||
| .xterm-strikethrough { | ||||
|     text-decoration: line-through; | ||||
| } | ||||
| 
 | ||||
| .xterm-screen .xterm-decoration-container .xterm-decoration { | ||||
| 	z-index: 6; | ||||
| 	position: absolute; | ||||
| } | ||||
| 
 | ||||
| .xterm-decoration-overview-ruler { | ||||
|     z-index: 7; | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|     right: 0; | ||||
|     pointer-events: none; | ||||
| } | ||||
| 
 | ||||
| .xterm-decoration-top { | ||||
|     z-index: 2; | ||||
|     position: relative; | ||||
| } | ||||
							
								
								
									
										26
									
								
								assets/xterm.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,26 @@ | ||||
| /* | ||||
| Copyright 2021 Erik Bremen | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any | ||||
| person obtaining a copy of this software and associated | ||||
| documentation files (the "Software"), to deal in the | ||||
| Software without restriction, including without | ||||
| limitation the rights to use, copy, modify, merge, | ||||
| publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software | ||||
| is furnished to do so, subject to the following | ||||
| conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice | ||||
| shall be included in all copies or substantial portions | ||||
| of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||||
| ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||
| TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||
| PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||||
| SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | ||||
| IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE.*/ | ||||
							
								
								
									
										15572
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,11 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "xterm": "^5.1.0", | ||||
|     "xterm-readline": "^1.1.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@webpack-cli/generators": "^3.0.1", | ||||
|     "ts-loader": "^9.4.2", | ||||
|     "workbox-webpack-plugin": "^6.5.4" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										158
									
								
								src/Logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,158 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <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:xlink="http://www.w3.org/1999/xlink" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="40mm" | ||||
|    height="40mm" | ||||
|    viewBox="0 0 40 40" | ||||
|    version="1.1" | ||||
|    id="svg8" | ||||
|    inkscape:version="1.0.2 (e86c870879, 2021-01-15)" | ||||
|    sodipodi:docname="Logo.svg"> | ||||
|   <defs | ||||
|      id="defs2"> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        id="linearGradient841"> | ||||
|       <stop | ||||
|          style="stop-color:#ff2f1b;stop-opacity:0.94338685" | ||||
|          offset="0" | ||||
|          id="stop837" /> | ||||
|       <stop | ||||
|          style="stop-color:#ff981b;stop-opacity:1" | ||||
|          offset="1" | ||||
|          id="stop839" /> | ||||
|     </linearGradient> | ||||
|     <linearGradient | ||||
|        inkscape:collect="always" | ||||
|        xlink:href="#linearGradient841" | ||||
|        id="linearGradient843" | ||||
|        x1="0.09372035" | ||||
|        y1="32.445991" | ||||
|        x2="40.099368" | ||||
|        y2="32.445991" | ||||
|        gradientUnits="userSpaceOnUse" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="3.959798" | ||||
|      inkscape:cx="33.612988" | ||||
|      inkscape:cy="79.88823" | ||||
|      inkscape:document-units="mm" | ||||
|      inkscape:current-layer="layer1" | ||||
|      inkscape:document-rotation="0" | ||||
|      showgrid="false" | ||||
|      units="mm" | ||||
|      width="10in" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1080" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="0" | ||||
|      inkscape:window-maximized="1" /> | ||||
|   <metadata | ||||
|      id="metadata5"> | ||||
|     <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></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <rect | ||||
|        style="opacity:0.996;fill:#bdbdbf;fill-opacity:1;stroke:none;stroke-width:3.26501" | ||||
|        id="rect845" | ||||
|        width="40.060905" | ||||
|        height="39.918461" | ||||
|        x="0.038461588" | ||||
|        y="0.040780049" /> | ||||
|     <path | ||||
|        style="fill:#000096;fill-rule:evenodd;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" | ||||
|        d="m 0.01924099,11.770051 c 0,0 4.23471871,-9.0904555 7.97328241,0.07001 3.7385636,9.160462 10.9886006,0.01079 10.9886006,0.01079 0,0 5.966783,-14.2485618 11.666,0.158241 5.699215,14.406802 9.288732,-1.270883 9.288732,-1.270883 L 40.044468,-0.00924326 0.03846159,0.04078005 Z" | ||||
|        id="path833" /> | ||||
|     <path | ||||
|        style="fill:url(#linearGradient843);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||
|        d="m 40.086823,30.112199 c 0,0 -4.210076,7.636771 -7.973427,-0.04911 -3.763352,-7.685876 -10.98857,0.0043 -10.98857,0.0043 0,0 -5.92816,11.969217 -11.6663624,-0.118701 -5.738201,-12.087915 -9.28523872,1.078198 -9.28523872,1.078198 l -0.07950453,9.022855 40.00564765,-0.0905 z" | ||||
|        id="path835" /> | ||||
|     <g | ||||
|        id="g893"> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 2.4325,0 V 40.079086" | ||||
|          id="path847" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 8.1530386,0 V 40.079086" | ||||
|          id="path849" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 13.873575,0 V 40.079086" | ||||
|          id="path851" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 19.594114,0 V 40.079086" | ||||
|          id="path853" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 25.314652,0 V 40.079086" | ||||
|          id="path855" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 31.035191,0 V 40.079086" | ||||
|          id="path857" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 36.755726,0 V 40.079086" | ||||
|          id="path859" /> | ||||
|     </g> | ||||
|     <g | ||||
|        id="g909" | ||||
|        transform="rotate(89.785681,20.14727,20.064174)"> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 2.4325,0 V 40.079086" | ||||
|          id="path895" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 8.1530386,0 V 40.079086" | ||||
|          id="path897" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 13.873575,0 V 40.079086" | ||||
|          id="path899" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 19.594114,0 V 40.079086" | ||||
|          id="path901" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 25.314652,0 V 40.079086" | ||||
|          id="path903" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 31.035191,0 V 40.079086" | ||||
|          id="path905" /> | ||||
|       <path | ||||
|          style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.865;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|          d="M 36.755726,0 V 40.079086" | ||||
|          id="path907" /> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 7.0 KiB | 
							
								
								
									
										63
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,63 @@ | ||||
| import {Terminal} from 'xterm'; | ||||
| import { Readline } from "xterm-readline"; | ||||
| 
 | ||||
| let isScreened = false, sendLessExplicit = false; | ||||
|      | ||||
| const term = new Terminal(); | ||||
| const rl = new Readline(); | ||||
| term.options.scrollback = 1000; | ||||
| term.loadAddon(rl); | ||||
| term.open(document.getElementById('console')); | ||||
| 
 | ||||
| let lineHandler = (l: string) => { console.log("Default handler", l); }; | ||||
| 
 | ||||
| async function readForever() { | ||||
|   while (true) { | ||||
|     const l = await rl.read(""); | ||||
|     lineHandler(l); | ||||
|   } | ||||
| } | ||||
| readForever(); | ||||
| 
 | ||||
| function connectTerm() { | ||||
|   lineHandler = () => {}; | ||||
|   term.writeln("\x1b[0mConnecting to server..."); | ||||
|   const wsurl = document.location.href.replace(/^https:\/\/(.*)\/game(.html)?(\?.*)?(\#.*)?/, 'wss:\/\/$1/wsgame'); | ||||
|   let webSocket = new WebSocket(wsurl); | ||||
|   webSocket.addEventListener('open', (event) => { | ||||
|     lineHandler = (l: string) => { console.log("Send handler", l); webSocket.send(l); } | ||||
|     term.writeln("\x1b[0mConnected"); | ||||
|   }); | ||||
|   webSocket.addEventListener('close', (event) => { | ||||
|     lineHandler = connectTerm; | ||||
|     term.writeln("\x1b[0mDisconnected; use r (followed by enter) to reconnect."); | ||||
|   }); | ||||
|   webSocket.addEventListener('error', (event) => { | ||||
|     term.writeln("\x1b[0mNetwork error with connection."); | ||||
|   }); | ||||
|   webSocket.addEventListener('message', (msg) => { | ||||
|     term.write(msg.data); | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| function over18() { | ||||
|   document.getElementById("over18").style.display = 'none'; | ||||
|   isScreened = true; | ||||
|   window.localStorage['over18'] = true; | ||||
|   term.focus(); | ||||
|   connectTerm(); | ||||
| } | ||||
|      | ||||
| if ('serviceWorker' in navigator) navigator.serviceWorker.register('service-worker.js'); | ||||
| const params: {[key:string]: string} = | ||||
|   location.search.substr(1).split('&') | ||||
|     .reduce((o, s) => { const [k, v] = s.split('='); o[k] = v; return o;}, | ||||
|             {} as {[key:string]: string}); | ||||
| if (params["source"] && params["source"] === "android") { | ||||
|   isScreened = true; | ||||
|   sendLessExplicit = true; | ||||
| } | ||||
| 
 | ||||
| if (isScreened || window.localStorage['over18']) { | ||||
|   over18(); | ||||
| } | ||||
							
								
								
									
										11
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,11 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "allowSyntheticDefaultImports": true, | ||||
|     "noImplicitAny": true, | ||||
|     "module": "es6", | ||||
|     "target": "es5", | ||||
|     "allowJs": true, | ||||
|     "moduleResolution": "node" | ||||
|   }, | ||||
|   "files": ["src/index.ts"] | ||||
| } | ||||
							
								
								
									
										4
									
								
								update-deps.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @ -0,0 +1,4 @@ | ||||
| #!/bin/bash | ||||
| 
 | ||||
| npx webpack | ||||
| cp dist/main.js ./assets/main.js | ||||
							
								
								
									
										50
									
								
								webpack.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,50 @@ | ||||
| // Generated using webpack-cli https://github.com/webpack/webpack-cli
 | ||||
| 
 | ||||
| const path = require('path'); | ||||
| const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); | ||||
| 
 | ||||
| const isProduction = process.env.NODE_ENV !== 'test'; | ||||
| 
 | ||||
| 
 | ||||
| const config = { | ||||
|     entry: './src/index.ts', | ||||
|     output: { | ||||
|         path: path.resolve(__dirname, 'dist'), | ||||
|     }, | ||||
|     plugins: [ | ||||
|         // Add your plugins here
 | ||||
|         // Learn more about plugins from https://webpack.js.org/configuration/plugins/
 | ||||
|     ], | ||||
|     module: { | ||||
|         rules: [ | ||||
|             { | ||||
|                 test: /\.(ts|tsx)$/i, | ||||
|                 loader: 'ts-loader', | ||||
|                 exclude: ['/node_modules/'], | ||||
|             }, | ||||
|             { | ||||
|                 test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i, | ||||
|                 type: 'asset', | ||||
|             }, | ||||
| 
 | ||||
|             // Add your rules for custom modules here
 | ||||
|             // Learn more about loaders from https://webpack.js.org/loaders/
 | ||||
|         ], | ||||
|     }, | ||||
|     resolve: { | ||||
|         extensions: ['.tsx', '.ts', '.jsx', '.js', '...'], | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| module.exports = () => { | ||||
|     if (isProduction) { | ||||
|         config.mode = 'production'; | ||||
|          | ||||
|          | ||||
|         config.plugins.push(new WorkboxWebpackPlugin.GenerateSW()); | ||||
|          | ||||
|     } else { | ||||
|         config.mode = 'development'; | ||||
|     } | ||||
|     return config; | ||||
| }; | ||||