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;
|
||||||
|
};
|