wm 1.1.1, fixes and improventments
This commit is contained in:
parent
fda61ff4eb
commit
65e9329a56
15 changed files with 179 additions and 51 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -92,6 +92,7 @@ out
|
|||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
nfdist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
"name": "neofunkin-1",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"main": "nfdist/index.js",
|
||||
"build": {
|
||||
"appId": "asper.games.neofunkin",
|
||||
"productName": "NeoFunkin [EARLY ALPHA]",
|
||||
"productName": "NeoFunkin",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
"nfdist/**/*"
|
||||
],
|
||||
"win": {
|
||||
"target": "portable"
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"build": "tsc && node scripts/finalizeBuild.js",
|
||||
"electron": "electron dist",
|
||||
"electron": "electron nfdist",
|
||||
"bundle": "electron-builder"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
|
@ -2,7 +2,7 @@ const fs = require('fs-extra');
|
|||
const path = require('path');
|
||||
|
||||
const srcDir = path.join(process.cwd(), 'src');
|
||||
const destDir = path.join(process.cwd(), 'dist');
|
||||
const destDir = path.join(process.cwd(), 'nfdist');
|
||||
|
||||
const copyAssets = async () => {
|
||||
try {
|
||||
|
|
57
src/index.ts
57
src/index.ts
|
@ -5,7 +5,14 @@ import path from 'path';
|
|||
import { createServer } from 'http';
|
||||
import WebSocket from 'ws';
|
||||
import { displayMainMenu } from './screens/mainmenu';
|
||||
import { start } from 'repl';
|
||||
import { displayOptions } from './screens/options';
|
||||
import { displayPlayMenu } from './screens/play';
|
||||
import EventDispatcher from './lib/nfevents';
|
||||
import { wdata } from './lib/windowManager';
|
||||
import { screenSize, wait } from './lib/utils';
|
||||
|
||||
const eventDispatcher = new EventDispatcher();
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Process {
|
||||
|
@ -30,16 +37,21 @@ async function startWebRoot() {
|
|||
|
||||
app.use(express.static(path.join(__dirname, 'webroot')));
|
||||
|
||||
app.get('/eval', (req: express.Request, res: express.Response): any => {
|
||||
app.get('/debug', (req: express.Request, res: express.Response): any => {
|
||||
console.log(screenSize());
|
||||
res.status(200).send('OK');
|
||||
});
|
||||
|
||||
app.get('/eval', async (req: express.Request, res: express.Response): Promise<any> => {
|
||||
const code = req.headers['x-code'] as string;
|
||||
|
||||
if (!code) return res.status(400).send('No code provided');
|
||||
|
||||
try {
|
||||
const result = (function(require) {
|
||||
return eval(code);
|
||||
const result = (async function(require) {
|
||||
return await eval(decodeURIComponent(code));
|
||||
})(require);
|
||||
res.status(200).send(result as string);
|
||||
res.status(200).send(await result as string);
|
||||
} catch (error: any) {
|
||||
res.status(500).send(error.message as string);
|
||||
}
|
||||
|
@ -47,16 +59,19 @@ async function startWebRoot() {
|
|||
|
||||
wss.on('connection', (ws: WebSocket) => {
|
||||
console.log('[ws] client++');
|
||||
eventDispatcher.dispatch('nf_ws_connection', 'open');
|
||||
|
||||
ws.on('message', (message) => {
|
||||
const msg = JSON.parse(message.toString());
|
||||
if (!msg.ch) msg.ch = 'public'
|
||||
console.log('[ws]', msg.ch, '-', msg.m);
|
||||
ws.send(JSON.stringify(msg));
|
||||
console.log('[ws]', msg.ch, '-', msg.m);
|
||||
eventDispatcher.dispatch('nf_ws_message', msg);
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log('[ws] client--');
|
||||
eventDispatcher.dispatch('nf_ws_connection', 'close');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -67,6 +82,36 @@ app.on('ready', async () => {
|
|||
try {
|
||||
startWebRoot();
|
||||
displayMainMenu();
|
||||
eventDispatcher.on('nf_ws_message', async (message) => {
|
||||
// screenManager
|
||||
if (message.m.startsWith('OPENSCREEN')) {
|
||||
const screen = message.m.split(':')[1];
|
||||
console.log('[screenManager] Trying to dispatch screen', screen)
|
||||
const bwdata = { ...wdata };
|
||||
switch (screen) {
|
||||
case 'Options':
|
||||
displayOptions();
|
||||
break;
|
||||
case 'Play':
|
||||
displayPlayMenu();
|
||||
break;
|
||||
case 'MainMenu':
|
||||
displayMainMenu();
|
||||
break;
|
||||
default:
|
||||
console.error('[screenManager] Unknown screen:', screen);
|
||||
displayCrashScreen();
|
||||
};
|
||||
await wait(200);
|
||||
Object.keys(bwdata).forEach(async (id) => {
|
||||
bwdata[id].win.destroy();
|
||||
delete bwdata[id]; // Cleanup
|
||||
});
|
||||
console.log('[screenManager] Cleaned old windows');
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
process.nfenv.crash(e.message);
|
||||
|
|
|
@ -15,9 +15,8 @@ export default async function displayCrashScreen() {
|
|||
customProps: { maximizable: false }
|
||||
});
|
||||
const button = wm.create({
|
||||
w: 10,
|
||||
h: 5,
|
||||
whp: true,
|
||||
w: Math.round(toP(sw, 10)),
|
||||
h: Math.round(toP(sh, 5)),
|
||||
noBorder: true,
|
||||
noBackground: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/buttons/exit.html?code=1`) },
|
||||
|
|
26
src/lib/nfevents.ts
Normal file
26
src/lib/nfevents.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
type Listener<T> = (data: T) => void;
|
||||
|
||||
export default class EventDispatcher<T = any> {
|
||||
private listeners: { [event: string]: Listener<T>[] } = {};
|
||||
|
||||
on(event: string, listener: Listener<T>): void {
|
||||
if (!this.listeners[event]) {
|
||||
this.listeners[event] = [];
|
||||
}
|
||||
this.listeners[event].push(listener);
|
||||
}
|
||||
|
||||
off(event: string, listener: Listener<T>): void {
|
||||
if (!this.listeners[event]) return;
|
||||
|
||||
this.listeners[event] = this.listeners[event].filter(l => l !== listener);
|
||||
}
|
||||
|
||||
dispatch(event: string, data: T): void {
|
||||
if (!this.listeners[event]) return;
|
||||
|
||||
this.listeners[event].forEach(listener => {
|
||||
listener(data);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -16,16 +16,17 @@ const wm = {
|
|||
create: function (c: wm_create_conf) {
|
||||
let wid = Array.from({ length: 32 }, () => '0123456789abcdef'[Math.floor(Math.random() * 16)]).join('');
|
||||
while (wdata[wid]) {
|
||||
console.warn('[wm] create: got a wid duplicate');
|
||||
wid = Array.from({ length: 32 }, () => '0123456789abcdef'[Math.floor(Math.random() * 16)]).join('');
|
||||
}
|
||||
const { width: sw, height: sh } = screenSize();
|
||||
console.log('[wm] create', wid);
|
||||
const { width: sw, height: sh } = screenSize();
|
||||
const win = new BrowserWindow({
|
||||
...c.customProps,
|
||||
width: c.whp ? toP(sw, c.w!) : c.w,
|
||||
height: c.whp ? toP(sh, c.h!) : c.h,
|
||||
x: c.xyp ? toP(sw, c.x!) : c.x,
|
||||
y: c.xyp ? toP(sh, c.y!) : c.y,
|
||||
width: Math.round(c.whp ? toP(sw, c.w) : c.w),
|
||||
height: Math.round(c.whp ? toP(sh, c.h) : c.h),
|
||||
x: c.x ? Math.round(c.xyp ? toP(sw, c.x) : c.x) : undefined,
|
||||
y: c.y ? Math.round(c.xyp ? toP(sh, c.y) : c.y) : undefined,
|
||||
frame: !c.noBorder,
|
||||
transparent: c.noBackground,
|
||||
webPreferences: {
|
||||
|
@ -56,7 +57,7 @@ const wm = {
|
|||
if (!wdata[id]) return
|
||||
console.log('[wm] destroy', id);
|
||||
const win = wdata[id];
|
||||
if (typeof win.conf.onDestroy === 'function') await win.conf.onDestroy!(win.win);
|
||||
if (typeof win.conf.onDestroy === 'function') await win.conf.onDestroy!(win);
|
||||
win.win.destroy();
|
||||
delete wdata[id];
|
||||
},
|
||||
|
@ -70,19 +71,19 @@ const wm = {
|
|||
|
||||
const sX = wb.x;
|
||||
const sY = wb.y;
|
||||
c.x = c.x === undefined ? sX : c.x;
|
||||
c.y = c.y === undefined ? sY : c.y;
|
||||
c.x = c.x === undefined ? sX : Math.round(c.x);
|
||||
c.y = c.y === undefined ? sY : Math.round(c.y);
|
||||
|
||||
const duration = c.duration || 500;
|
||||
const tick = c.tick || 1000 / 30;
|
||||
const totalSteps = Math.floor(duration / tick);
|
||||
|
||||
// is relative? add current window's x, y
|
||||
// | relative | | absolute
|
||||
// | | is %? | | | is %?
|
||||
// | | | % | px | | | % px
|
||||
let targetX = c.r ? c.p ? toP(sw, c.x) + cwx : c.x + cwx : c.p ? toP(sw, c.x) : c.x;
|
||||
let targetY = c.r ? c.p ? toP(sh, c.y) + cwy : c.y + cwy : c.p ? toP(sh, c.y) : c.y;
|
||||
// is relative? add current window's x/y
|
||||
// | relative | | absolute
|
||||
// | | is %? | | | is %?
|
||||
// | | | % | px | | | % px
|
||||
let targetX = Math.round(c.r ? c.p ? toP(sw, c.x) + cwx : c.x + cwx : c.p ? toP(sw, c.x) : c.x);
|
||||
let targetY = Math.round(c.r ? c.p ? toP(sh, c.y) + cwy : c.y + cwy : c.p ? toP(sh, c.y) : c.y);
|
||||
|
||||
if (c.fromCenter) {
|
||||
wb = win.win.getBounds();
|
||||
|
@ -131,17 +132,17 @@ const wm = {
|
|||
}
|
||||
const wb = win.win.getBounds();
|
||||
const sW = wb.width, sH = wb.height;
|
||||
c.w = c.w === undefined ? sW : c.w;
|
||||
c.h = c.h === undefined ? sH : c.h;
|
||||
c.w = c.w === undefined ? sW : Math.round(c.w);
|
||||
c.h = c.h === undefined ? sH : Math.round(c.h);
|
||||
const duration = c.duration || 500;
|
||||
const tick = c.tick || 1000 / 30;
|
||||
const totalSteps = Math.floor(duration / tick);
|
||||
const { width: sw, height: sh } = screenSize();
|
||||
const targetW = toP(c.p ? sw : 1, c.w);
|
||||
const targetH = toP(c.p ? sh : 1, c.h);
|
||||
const targetW = Math.round(toP(c.p ? sw : 1, c.w));
|
||||
const targetH = Math.round(toP(c.p ? sh : 1, c.h));
|
||||
|
||||
const centerX = wb.x + wb.width / 2;
|
||||
const centerY = wb.y + wb.height / 2;
|
||||
const centerX = Math.round(wb.x + wb.width / 2);
|
||||
const centerY = Math.round(wb.y + wb.height / 2);
|
||||
|
||||
const getAnchoredPosition = (curWidth: number, curHeight: number) => {
|
||||
let newX = wb.x;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { app } from "electron";
|
||||
import { easeOutCirc, easeOutQuart, easeOutQuint } from "../lib/animations";
|
||||
import { easeOutQuart } from "../lib/animations";
|
||||
import { screenSize, toP, wait } from "../lib/utils";
|
||||
import wm, {WindowData, wdata} from "../lib/windowManager";
|
||||
|
||||
|
@ -20,9 +20,8 @@ export async function displayMainMenu() {
|
|||
const { height: sh, width: sw } = screenSize();
|
||||
|
||||
const pb = wm.create({
|
||||
w: 10,
|
||||
h: 5,
|
||||
whp: true,
|
||||
w: Math.round(toP(sw, 10)),
|
||||
h: Math.round(toP(sh, 5)),
|
||||
noBorder: true,
|
||||
noBackground: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/buttons/openscreen.html?screen=Play`) },
|
||||
|
@ -34,9 +33,8 @@ export async function displayMainMenu() {
|
|||
wm.follow.start(pb, mw);
|
||||
|
||||
const eb = wm.create({
|
||||
w: 10,
|
||||
h: 5,
|
||||
whp: true,
|
||||
w: Math.round(toP(sw, 10)),
|
||||
h: Math.round(toP(sh, 5)),
|
||||
noBorder: true,
|
||||
noBackground: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/buttons/exit.html`) },
|
||||
|
@ -48,9 +46,8 @@ export async function displayMainMenu() {
|
|||
wm.follow.start(eb, mw);
|
||||
|
||||
const ob = wm.create({
|
||||
w: 10,
|
||||
h: 5,
|
||||
whp: true,
|
||||
w: Math.round(toP(sw, 10)),
|
||||
h: Math.round(toP(sh, 5)),
|
||||
noBorder: true,
|
||||
noBackground: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/buttons/openscreen.html?screen=Options`) },
|
||||
|
|
19
src/screens/options.ts
Normal file
19
src/screens/options.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { app } from "electron";
|
||||
import { easeOutQuart } from "../lib/animations";
|
||||
import { wait } from "../lib/utils";
|
||||
import wm, {WindowData, wdata} from "../lib/windowManager";
|
||||
|
||||
export async function displayOptions() {
|
||||
await app.whenReady();
|
||||
const mw = wm.create({
|
||||
w: 20,
|
||||
h: 20,
|
||||
whp: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/screens/options/`) },
|
||||
onClose: () => { process.exit(0) }
|
||||
});
|
||||
wm.move({ id: mw, x: 50, y: 50, p: true, fromCenter: true });
|
||||
await wait(500);
|
||||
wm.resize({ id: mw, w: 40, h: 40, smooth: true, p: true, ease: easeOutQuart });
|
||||
await wait(500);
|
||||
};
|
19
src/screens/play.ts
Normal file
19
src/screens/play.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { app } from "electron";
|
||||
import { easeOutQuart } from "../lib/animations";
|
||||
import { wait } from "../lib/utils";
|
||||
import wm, {WindowData, wdata} from "../lib/windowManager";
|
||||
|
||||
export async function displayPlayMenu() {
|
||||
await app.whenReady();
|
||||
const mw = wm.create({
|
||||
w: 20,
|
||||
h: 20,
|
||||
whp: true,
|
||||
onCreate: (win: WindowData) => { win.win.loadURL(`http://localhost:${process.nfenv.serverPort}/screens/play/`) },
|
||||
onClose: () => { process.exit(0) }
|
||||
});
|
||||
wm.move({ id: mw, x: 50, y: 50, p: true, fromCenter: true });
|
||||
await wait(500);
|
||||
wm.resize({ id: mw, w: 40, h: 40, smooth: true, p: true, ease: easeOutQuart });
|
||||
await wait(500);
|
||||
};
|
|
@ -15,7 +15,7 @@ export type wm_create_conf = {
|
|||
onUnfocus?: Function; // USER unfocused on the window
|
||||
onFocus?: Function; // USER focused on the window
|
||||
onClose?: Function; // USER pressed 'x'
|
||||
onDestroy?: Function; // USER pressed 'x' OR wm.destroy(...)
|
||||
onDestroy?: Function; // wm.destroy(...)
|
||||
onMove?: Function; // Window moves
|
||||
onResize?: Function; // Window resizes
|
||||
customProps?: object; // for example for setting maximizable to false
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
<body>
|
||||
<button style="width: 100vw; height: 100vh; margin: 0;">Loading</button>
|
||||
<script>
|
||||
const screen = new URL(window.location.href).searchParams.get('screen');
|
||||
document.querySelector('button').textContent = screen || 'USE ?screen=...';
|
||||
const url = new URL(window.location.href);
|
||||
const screen = url.searchParams.get('screen');
|
||||
const display = url.searchParams.get('display') ?? screen;
|
||||
document.querySelector('button').textContent = display || 'USE ?screen=...&display=...';
|
||||
document.querySelector('button').addEventListener('click', () => {
|
||||
const socket = new WebSocket(`ws://${window.location.host}/`);
|
||||
socket.onopen = function() {
|
||||
socket.send(JSON.stringify({ m: `OPENSCREEN_${screen || 'UNDEFINED'}` }))
|
||||
socket.send(JSON.stringify({ m: `OPENSCREEN:${screen || 'UNDEFINED'}` }))
|
||||
};
|
||||
socket.onmessage = function(event) { window.close() };
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
10
src/webroot/screens/options/index.html
Normal file
10
src/webroot/screens/options/index.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>NeoFunkin</title>
|
||||
</head>
|
||||
<body>
|
||||
OPTIONS
|
||||
<iframe src="/buttons/openscreen.html?screen=MainMenu&display=Back"></iframe>
|
||||
</body>
|
||||
</html>
|
10
src/webroot/screens/play/index.html
Normal file
10
src/webroot/screens/play/index.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>NeoFunkin</title>
|
||||
</head>
|
||||
<body>
|
||||
PLAY
|
||||
<iframe src="/buttons/openscreen.html?screen=MainMenu&display=Back"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -6,7 +6,7 @@
|
|||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"outDir": "./dist",
|
||||
"outDir": "./nfdist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
|
|
Loading…
Add table
Reference in a new issue