From d3143550c67df78ca1a0d95500a17b5d23a0f2cc Mon Sep 17 00:00:00 2001 From: Daniel Maixner Date: Mon, 17 Oct 2022 11:22:42 +0200 Subject: [PATCH] Wip --- .gitignore | 1 + electron/main.js | 22 +++++++++ electron/package.json | 9 ++++ src/Net/Server.php | 4 +- www/assets/js/UdpSocketConnector.js | 69 +++++++++++++++++++++++++++++ www/assets/js/WebSocketConnector.js | 2 +- www/assets/js/start.js | 21 +++++++-- 7 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 electron/main.js create mode 100644 electron/package.json create mode 100644 www/assets/js/UdpSocketConnector.js diff --git a/.gitignore b/.gitignore index 57872d0..fafc599 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /vendor/ +/electron/node_modules/ diff --git a/electron/main.js b/electron/main.js new file mode 100644 index 0000000..e4ce99b --- /dev/null +++ b/electron/main.js @@ -0,0 +1,22 @@ +const {app, BrowserWindow, protocol} = require('electron') +const url = require('url') + +app.whenReady().then(() => { + + protocol.interceptFileProtocol('file', function (request, callback) { // todo migrate www/ files to relative links and remove this + const filePath = url.fileURLToPath('file://' + __dirname + '/../www' + request.url.slice('file://'.length)) + callback(filePath) + }) + + const win = new BrowserWindow({ + autoHideMenuBar: true, + width: 800, + height: 600, + webPreferences: { // todo do it properly with isolation + nodeIntegration: true, + contextIsolation: false + } + }) + + win.loadFile('/index.html') +}) diff --git a/electron/package.json b/electron/package.json new file mode 100644 index 0000000..7647127 --- /dev/null +++ b/electron/package.json @@ -0,0 +1,9 @@ +{ + "main": "main.js", + "scripts": { + "start": "electron --no-sandbox ." + }, + "devDependencies": { + "electron": "^21.1.1" + } +} diff --git a/src/Net/Server.php b/src/Net/Server.php index 77be445..ddfcd2c 100644 --- a/src/Net/Server.php +++ b/src/Net/Server.php @@ -121,9 +121,7 @@ class Server $nsLast = $nsCurrent + $sleepTimeNs; time_nanosleep(0, $sleepTimeNs); } else { - if ($this->serverLag === 0) { - $this->log('First Server tick lag detected on tick ' . ($tickId - 1), LogLevel::WARNING); - } + $this->log('Server lag detected on tick ' . ($tickId - 1), LogLevel::WARNING); $this->serverLag++; $nsLast = $nsCurrent; } diff --git a/www/assets/js/UdpSocketConnector.js b/www/assets/js/UdpSocketConnector.js new file mode 100644 index 0000000..7393335 --- /dev/null +++ b/www/assets/js/UdpSocketConnector.js @@ -0,0 +1,69 @@ +const dgram = require('dgram'); + +export class UdpSocketConnector { + #game; + #socket; + sendIntervalId; + + constructor(game) { + this.#game = game + } + + close() { + this.#socket.close() + } + + connect(ip, port, loginCode) { + let logged = false; + + const socket = dgram.createSocket('udp4'); + this.#socket = socket + + const connector = this + const game = this.#game + socket.on('close', function () { + clearInterval(connector.sendIntervalId) + console.log("UdpSocket closed") + }); + socket.on('error', function (error) { + alert(`Cannot connect to '${ip}:${port}'`) + console.log("UdpSocket error: " + error.message) + }); + socket.on('connect', function () { + console.log("UdpSocket connection established.") + if (!logged) { + console.log("Sending login code to server.") + socket.send("login " + loginCode) + logged = true + } + }); + socket.on('message', function (msg) { + let state + try { + state = JSON.parse(msg.toString()) + } catch (err) { + game.end("Message parse error! " + err.message) + return + } + game.tick(state) + }); + + socket.connect(port, ip) + } + + startLoop(control, tickMs) { + const game = this.#game + const socket = this.#socket + + this.sendIntervalId = setInterval(function () { + if (!game.isPlaying() || !game.meIsAlive()) { + return; + } + + let data = control.getTickAction() + if (data !== '') { + socket.send(data) + } + }, tickMs) + } +} diff --git a/www/assets/js/WebSocketConnector.js b/www/assets/js/WebSocketConnector.js index 00ab03a..c5f8130 100644 --- a/www/assets/js/WebSocketConnector.js +++ b/www/assets/js/WebSocketConnector.js @@ -61,6 +61,6 @@ export class WebSocketConnector { socket.send('') // ping - }, tickMs - 1) + }, tickMs) } } diff --git a/www/assets/js/start.js b/www/assets/js/start.js index 1d1a0ed..e5dcd9d 100644 --- a/www/assets/js/start.js +++ b/www/assets/js/start.js @@ -2,7 +2,6 @@ import {Game} from "./Game.js"; import {HUD} from "./Hud.js"; import {Control} from "./Control.js"; import {World} from "./World.js"; -import {WebSocketConnector} from "./WebSocketConnector.js"; import Stats from "./Stats.js"; let launchGame @@ -26,6 +25,7 @@ let launchGame throw new Error("Game already launched") } + let connector initialized = true const canvas = await world.init(setting.map, setting.world) hud.createHud(elementHud) @@ -37,9 +37,8 @@ let launchGame control.requestLock() }, {capture: true}) canvasParent.appendChild(canvas) - canvasParent.appendChild(stats.dom); + canvasParent.appendChild(stats.dom) - let connector = new WebSocketConnector(game) game.onEnd(function (msg) { connector.close() alert("Game ended: " + msg) @@ -48,7 +47,21 @@ let launchGame game.onReady(function (options) { connector.startLoop(control, options.tickMs) }) - connector.connect(setting.url, setting.code) + + const url = new URL(setting.url) + if (url.protocol === 'ws:') { + const ns = await import("./WebSocketConnector.js") + connector = new ns.WebSocketConnector(game) + connector.connect(setting.url, setting.code) + } else if (url.protocol === 'udp:') { + const ns = await import("./UdpSocketConnector.js") + connector = new ns.UdpSocketConnector(game) + let url = new URL(setting.url.replace('udp://', 'http://')) // URL do not parse udp parts well, so do http instead + connector.connect(url.hostname, url.port, setting.code) + } else { + alert('Unknown protocol given') + return + } } })()