finally working!
parent
327b703201
commit
ac510b651e
|
|
@ -61,8 +61,11 @@ export class Game extends Frigid implements Tickable {
|
|||
this.inventory ??= new Inventory();
|
||||
this.inventory.validate();
|
||||
this.clock ??= new Time();
|
||||
this.clock.thing = this;
|
||||
this.clock.start();
|
||||
this.clock.start(this);
|
||||
this.pawns = [];
|
||||
if(this.pawns.length === 0) {
|
||||
for(let i = 0; i < 3; i ++) this.pawns.push(new Pawn());
|
||||
}
|
||||
ready(this.name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import chalk from 'chalk';
|
||||
import EventEmitter from 'events';
|
||||
import ipc from 'node-ipc';
|
||||
import {
|
||||
|
|
@ -9,27 +10,31 @@ import {
|
|||
} from './Constants.js';
|
||||
|
||||
let connected = false;
|
||||
const oldConsoleLog = console.log;
|
||||
|
||||
const patchLog = () => console.log = console.log.bind(console, chalk.cyan('[CLIENT]'));
|
||||
const restoreLog = () => console.log = oldConsoleLog;
|
||||
|
||||
// const log = (...args: any[]) => console.log(chalk.cyan('[CLIENT]'), ...args);
|
||||
|
||||
class ProcessManagerClass extends EventEmitter {
|
||||
quit() {
|
||||
if (connected) {
|
||||
console.log('client sending quit event')
|
||||
ipc.of[name].emit(IPC_QUIT_EVENT);
|
||||
this.emit('shutdown');
|
||||
process.exit(0);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
restart() {
|
||||
this.emit('shutdown');
|
||||
if (connected) {
|
||||
console.log('client emitting ipc restart')
|
||||
ipc.of[name].emit(IPC_RESTART_EVENT);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log('eh?! not connected to tower... closing')
|
||||
process.exit(0);
|
||||
}
|
||||
setTimeout(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return connected;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,11 +45,23 @@ ipc.config.appspace = IPC_CLIENT_APPSAPCE;
|
|||
ipc.config.silent = true;
|
||||
|
||||
ipc.connectTo(name, () => {
|
||||
ipc.of[name].on('connect', () => connected = true);
|
||||
ipc.of[name].on('disconnect', () => connected = false);
|
||||
ipc.of[name].on('connect', () => {
|
||||
connected = true;
|
||||
patchLog();
|
||||
});
|
||||
ipc.of[name].on('disconnect', () => {
|
||||
connected = false
|
||||
restoreLog();
|
||||
});
|
||||
ipc.of[name].on(IPC_REQUEST_RESTART, () => {
|
||||
console.log('received restart request');
|
||||
// ProcessManager.restart();
|
||||
ProcessManager.emit('reload');
|
||||
})
|
||||
});
|
||||
|
||||
/////////////
|
||||
process.on('SIGKILL', () => ProcessManager.quit());
|
||||
process.on('SIGTERM', () => ProcessManager.quit());
|
||||
process.on('SIGINT', () => ProcessManager.quit());
|
||||
|
||||
///
|
||||
81
src/Time.ts
81
src/Time.ts
|
|
@ -18,8 +18,9 @@ const months: AbbreviatedMonthName[] = [
|
|||
'Oct', 'Nov', 'Dec'
|
||||
]
|
||||
|
||||
// TODO split ticker util and calendar util...
|
||||
export default class Time extends Serializable {
|
||||
rate: number;
|
||||
targetTPS: number;
|
||||
paused = true;
|
||||
|
||||
thing: Tickable;
|
||||
|
|
@ -30,6 +31,12 @@ export default class Time extends Serializable {
|
|||
hour: number;
|
||||
minute: number;
|
||||
|
||||
ticksInSecond: number;
|
||||
lastTPSCheckpoint: number;
|
||||
tps: number;
|
||||
|
||||
_boundTick: Function;
|
||||
|
||||
constructor(timestamp: number = 0) {
|
||||
super();
|
||||
this.minute = timestamp;
|
||||
|
|
@ -67,16 +74,34 @@ export default class Time extends Serializable {
|
|||
}
|
||||
|
||||
toString() {
|
||||
return `${this.hour}:${Math.floor(this.minute).toString().padStart(2, '0')} ${months[this.month]} ${this.day + 1}, ${this.normalizedYear}`
|
||||
return `${
|
||||
this.hour
|
||||
}:${
|
||||
Math.floor(this.minute).toString().padStart(2, '0')
|
||||
} ${
|
||||
months[this.month]
|
||||
} ${
|
||||
this.day + 1
|
||||
}, ${
|
||||
this.normalizedYear
|
||||
} [${
|
||||
this.tps
|
||||
} / ${
|
||||
this.targetTPS
|
||||
}]`;
|
||||
}
|
||||
|
||||
ctor() {
|
||||
this.rate = 60;
|
||||
this.targetTPS = 2000;
|
||||
this.minute ??= 0;
|
||||
this.hour ??= 0;
|
||||
this.day ??= 0;
|
||||
this.month ??= 0;
|
||||
this.year ??= 0;
|
||||
this.tps ??= 0;
|
||||
this.lastTPSCheckpoint = ms4();
|
||||
this.ticksInSecond = 0;
|
||||
this._boundTick = this.doTick.bind(this);
|
||||
}
|
||||
|
||||
get second() {
|
||||
|
|
@ -112,7 +137,13 @@ export default class Time extends Serializable {
|
|||
this.paused = true;
|
||||
}
|
||||
|
||||
start() {
|
||||
resume() {
|
||||
this.paused = false;
|
||||
setTimeout(this.doTick.bind(this), 0);
|
||||
}
|
||||
|
||||
start(tickable: Tickable) {
|
||||
this.thing = tickable;
|
||||
this.paused = false;
|
||||
setTimeout(this.doTick.bind(this), 0);
|
||||
}
|
||||
|
|
@ -130,8 +161,6 @@ export default class Time extends Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
normalize() {
|
||||
// while(t)
|
||||
while(this.minute >= 60) {
|
||||
|
|
@ -173,20 +202,46 @@ export default class Time extends Serializable {
|
|||
}
|
||||
|
||||
async doTick() {
|
||||
|
||||
this.advanceTime(1);
|
||||
const timeout = 1000 / this.rate;
|
||||
const start = new Date().getTime();
|
||||
const timeout = 1000 / this.targetTPS;
|
||||
// const start = ms4()
|
||||
const start = ms4();
|
||||
if(this.thing) {
|
||||
await this.thing.tick();
|
||||
}
|
||||
const elapsed = new Date().getTime() - start;
|
||||
const wait = Math.max(timeout - elapsed, 0);
|
||||
if(this.paused) return;
|
||||
setTimeout(this.doTick.bind(this), wait)
|
||||
}
|
||||
const end = ms4()
|
||||
const elapsed = end - start;
|
||||
const wait = timeout - elapsed;
|
||||
const normalizedWait = Math.floor(Math.max(wait, 0));
|
||||
|
||||
// process.stdout.write(`tick took ${elapsed} waiting ${normalizedWait}\n`);
|
||||
|
||||
if(wait < 0) {
|
||||
const ticksOver = (-wait / timeout) + 1;
|
||||
console.log(chalk.yellow('Can\'t keep up! Tick took ' + ticksOver.toFixed(2) + ' ticks (' + (timeout - wait).toFixed(4) + 'ms)'));
|
||||
}
|
||||
|
||||
|
||||
this.ticksInSecond ++;
|
||||
|
||||
if(end > this.lastTPSCheckpoint + 1000) {
|
||||
this.lastTPSCheckpoint = end;
|
||||
this.tps = this.ticksInSecond;
|
||||
this.ticksInSecond = 0;
|
||||
}
|
||||
|
||||
if(this.paused) return;
|
||||
setTimeout(this._boundTick, normalizedWait)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export interface Tickable {
|
||||
tick: () => Promise<void>
|
||||
}
|
||||
|
||||
function ms4() {
|
||||
const a = process.hrtime()
|
||||
return a[0]*10e2 + a[1]/1000000;
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ import { parse, resolve } from 'path';
|
|||
import walkSync from 'walk-sync';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { APPLICATION_NAME } from './Constants.js';
|
||||
import chalk from 'chalk';
|
||||
|
||||
|
||||
export function osrsNumber(x: number): string {
|
||||
if(x < 10_000) return '' + x;
|
||||
|
|
@ -11,7 +13,7 @@ export function osrsNumber(x: number): string {
|
|||
}
|
||||
|
||||
export async function loadExtensions() {
|
||||
console.log(APPLICATION_NAME + ': Loading extensions');
|
||||
console.log('Loading extensions');
|
||||
const extensionsPath = resolve(parse(fileURLToPath(import.meta.url)).dir, '../content');
|
||||
|
||||
const extensions = walkSync(extensionsPath)
|
||||
|
|
@ -29,5 +31,3 @@ export async function loadExtensions() {
|
|||
|
||||
console.log('Setup Complete.');
|
||||
}
|
||||
|
||||
// export function
|
||||
100
src/hot-index.ts
100
src/hot-index.ts
|
|
@ -6,83 +6,85 @@ import {
|
|||
IPC_REQUEST_RESTART
|
||||
} from './Constants.js';
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
import watch from 'watch';
|
||||
import chokidar from 'chokidar';
|
||||
import chalk from 'chalk';
|
||||
ipc.config.silent = true;
|
||||
|
||||
// ipc.config.silent = true;
|
||||
|
||||
const exec = 'qode' + (process.platform === "win32" ? '.cmd' : '');
|
||||
// should be obtained from process spawn args, but whatever!
|
||||
const exec = 'qode' +
|
||||
(process.platform === "win32" ? '.cmd' : '');
|
||||
const args = [
|
||||
'bin/app.bundle.cjs'
|
||||
]
|
||||
];
|
||||
|
||||
ipc.serve(IPC_PATH, () => {
|
||||
ipc.server.on(IPC_QUIT_EVENT, async () => {
|
||||
await killProcess();
|
||||
ipc.server.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
ipc.server.on(IPC_RESTART_EVENT, restart)
|
||||
});
|
||||
|
||||
console.log('started ipc tower server!')
|
||||
ipc.server.start();
|
||||
const log = console.log.bind(console, chalk.green('[TOWER]'));
|
||||
|
||||
// varying state data
|
||||
let connected = 0;
|
||||
let proc: ChildProcess = null;
|
||||
let restartTimer: NodeJS.Timeout = null;
|
||||
|
||||
function ensureAlive() {
|
||||
if(proc) {
|
||||
return;
|
||||
}
|
||||
|
||||
function startProcess() {
|
||||
proc = spawn(exec, args, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
console.log(`[${proc.pid}] ${chalk.grey(`${exec} ${args.join(' ')}`)}`);
|
||||
proc.on('exit', () => {
|
||||
console.log('process died');
|
||||
proc.once('exit', () => {
|
||||
proc = null;
|
||||
})
|
||||
});
|
||||
log(`[${
|
||||
proc.pid
|
||||
}] ${
|
||||
chalk.grey(`${
|
||||
exec
|
||||
} ${
|
||||
args.join(' ')
|
||||
}`)
|
||||
}`);
|
||||
}
|
||||
|
||||
async function killProcess() {
|
||||
if(proc) {
|
||||
console.log('killing process...');
|
||||
const killedPromise = new Promise((res) => {
|
||||
proc.on('exit', (code, sig) => {
|
||||
res(code || sig);
|
||||
})
|
||||
})
|
||||
proc.kill();
|
||||
console.log('process died with code', await killedPromise);
|
||||
proc = null;
|
||||
console.log()
|
||||
async function ensureDead() {
|
||||
if(!proc) {
|
||||
return;
|
||||
}
|
||||
const killedPromise =
|
||||
new Promise(res => proc.once('exit', res));
|
||||
proc.kill(9);
|
||||
await killedPromise;
|
||||
proc = null;
|
||||
}
|
||||
|
||||
async function restart() {
|
||||
console.log('received restart event');
|
||||
await killProcess();
|
||||
console.log('')
|
||||
startProcess();
|
||||
await ensureDead();
|
||||
ensureAlive();
|
||||
}
|
||||
|
||||
startProcess();
|
||||
|
||||
let restartTimer: NodeJS.Timeout = null;
|
||||
|
||||
function fileChange() {
|
||||
// appendFileSync('log.log', evt + ' ' + path + '\n');
|
||||
// console.log(cluster.isMaster, evt, path);
|
||||
if(restartTimer) clearTimeout(restartTimer)
|
||||
restartTimer = setTimeout(() => {
|
||||
console.log('changes detected');
|
||||
if(proc) {
|
||||
ensureAlive();
|
||||
ipc.server.broadcast(IPC_REQUEST_RESTART);
|
||||
} else {
|
||||
startProcess();
|
||||
}
|
||||
restartTimer = null;
|
||||
}, 100);
|
||||
}
|
||||
chokidar.watch('./out').on('all', fileChange);
|
||||
// watch.watchTree('./bin', fileChange);
|
||||
|
||||
// start the server, connect events
|
||||
ipc.serve(IPC_PATH, () => {
|
||||
ipc.server.on(IPC_QUIT_EVENT, ensureDead);
|
||||
ipc.server.on(IPC_RESTART_EVENT, restart);
|
||||
ipc.server.on('connect', () => connected ++);
|
||||
ipc.server.on('disconnect', () => connected --);
|
||||
});
|
||||
ipc.server.start();
|
||||
|
||||
// open the process
|
||||
ensureAlive();
|
||||
|
||||
//begin watching for files, ignore changes on boot.
|
||||
chokidar.watch('./out', {
|
||||
ignoreInitial: true
|
||||
}).on('all', fileChange);
|
||||
29
src/index.ts
29
src/index.ts
|
|
@ -16,25 +16,25 @@ import ansi from 'sisteransi';
|
|||
import './../content/content.js';
|
||||
import { loadExtensions } from './Util.js';
|
||||
import { APPLICATION_NAME } from './Constants.js';
|
||||
import chalk from 'chalk';
|
||||
import { ProcessManager } from './ProcessManager.js';
|
||||
|
||||
// console.clear();
|
||||
|
||||
ProcessManager.on('shutdown', gracefulShutdown);
|
||||
|
||||
function gracefulShutdown() {
|
||||
if (isStarted()) {
|
||||
stop();
|
||||
}
|
||||
console.log('shutting down gracefully...');
|
||||
// if (isStarted()) {
|
||||
// stop();
|
||||
// }
|
||||
if (Game.current) {
|
||||
console.log('saving world...');
|
||||
console.log(chalk.cyan('Saving world...'));
|
||||
Game.current.sync();
|
||||
console.log(chalk.cyan('World Saved!'));
|
||||
}
|
||||
console.log('exitting');
|
||||
process.stdout.write(ansi.cursor.show);
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
process.on('exit', gracefulShutdown);
|
||||
// process.on('exit', gracefulShutdown);
|
||||
|
||||
const saveFile = process.argv[2] || 'data/world01.json';
|
||||
|
||||
|
|
@ -42,10 +42,11 @@ ensureDirSync(parse(saveFile).dir);
|
|||
|
||||
// loadExtensions();
|
||||
|
||||
for (let seconds = 0; seconds > 0; seconds --) {
|
||||
process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + seconds + '\r');
|
||||
}
|
||||
process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + 0 + '\n');
|
||||
// TODO replace with splash screen
|
||||
// for (let seconds = 0; seconds > 0; seconds --) {
|
||||
// process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + seconds + '\r');
|
||||
// }
|
||||
// process.stdout.write('Starting ' + APPLICATION_NAME + ' in ' + 0 + '\n');
|
||||
// console.clear();
|
||||
|
||||
// TODO move render logic into game, so that the ui doesnt exist until the game does...
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import * as uuid from 'uuid';
|
|||
import faker from 'faker';
|
||||
import chalk from 'chalk';
|
||||
import { Item } from '../registries/Items.js';
|
||||
import WebSocket from 'ws';
|
||||
import WebSocket, { EventEmitter } from 'ws';
|
||||
import { Popup } from '@ui';
|
||||
import { inspect } from 'util'
|
||||
import { Pawn } from '../Pawn.js';
|
||||
|
|
@ -18,11 +18,11 @@ const mdns = bonjour();
|
|||
const ID = uuid.v4();
|
||||
let devices: Player[] = [];
|
||||
|
||||
const network = {
|
||||
const network = new (class Network extends EventEmitter {
|
||||
get players() {
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
export type GiftMessage = {
|
||||
pawns: string[],
|
||||
|
|
@ -61,11 +61,13 @@ export async function ready(name: string) {
|
|||
mdns.find({
|
||||
type: MDNS_TYPE
|
||||
}, (service) => {
|
||||
network.emit('change');
|
||||
const p = new Player();
|
||||
p.name = service.name;
|
||||
p.host = service.host;
|
||||
p.port = service.port;
|
||||
devices.push(p);
|
||||
}).on("down", (service) => {
|
||||
network.emit('change');
|
||||
// TODO remove player from MP
|
||||
})
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
import { Game } from '@game';
|
||||
import { ItemState } from '@items';
|
||||
import {
|
||||
QLabel,
|
||||
QTabWidget,
|
||||
QWidget,
|
||||
QIcon,
|
||||
FlexLayout,
|
||||
QGridLayout,
|
||||
FocusPolicy,
|
||||
WidgetEventTypes,
|
||||
AlignmentFlag,
|
||||
QListView,
|
||||
QListWidget,
|
||||
QListWidgetItem
|
||||
QBoxLayout,
|
||||
Direction,
|
||||
QScrollArea,
|
||||
} from '@nodegui/nodegui';
|
||||
import network from '../multiplayer/mDNS.js';
|
||||
import { Player } from '../multiplayer/Player.js';
|
||||
import { Pawn } from '../Pawn.js';
|
||||
import { View } from './View.js';
|
||||
|
||||
|
|
@ -33,9 +34,6 @@ export class GameView extends View {
|
|||
|
||||
this.title.setText(this.game.name);
|
||||
|
||||
this.left.setInlineStyle('border: 1px solid white;')
|
||||
this.right.setInlineStyle('border: 1px solid white;')
|
||||
|
||||
this.layout.addWidget(this.title, 0, 0);
|
||||
this.layout.addWidget(this.timeLabel, 0, 1);
|
||||
this.layout.addWidget(this.left, 1, 0);
|
||||
|
|
@ -46,7 +44,8 @@ export class GameView extends View {
|
|||
this.layout.setColumnStretch(1, 2);
|
||||
|
||||
this.right.addTab(new PawnPageWidget(), new QIcon(), 'Pawns');
|
||||
this.right.addTab(new InventoryWidget(), new QIcon(), 'Inventory')
|
||||
this.right.addTab(new InventoryPageWidget(), new QIcon(), 'Inventory');
|
||||
this.right.addTab(new MultiplayerPageWidget(), new QIcon(), 'Multiplayer');
|
||||
}
|
||||
|
||||
constructor(game: Game) {
|
||||
|
|
@ -55,51 +54,153 @@ export class GameView extends View {
|
|||
}
|
||||
}
|
||||
|
||||
class PawnWidget extends QWidget {
|
||||
constructor(pawn: Pawn) {
|
||||
super();
|
||||
let layout: QGridLayout;
|
||||
this.setLayout(layout = new QGridLayout());
|
||||
// this.setInlineStyle(`
|
||||
// margin-bottom: 4px;
|
||||
// `);
|
||||
class GridItem extends QWidget {
|
||||
|
||||
const nameLabel = new QLabel();
|
||||
nameLabel.setText(pawn.name.first + ' ' + pawn.name.last);
|
||||
nameLabel.setAlignment(AlignmentFlag.AlignLeft | AlignmentFlag.AlignTop);
|
||||
rootLayout: QGridLayout;
|
||||
|
||||
const activityLabel = new QLabel();
|
||||
activityLabel.setText(pawn.status);
|
||||
activityLabel.setAlignment(AlignmentFlag.AlignRight | AlignmentFlag.AlignTop);
|
||||
|
||||
this.layout.addWidget(nameLabel, 0, 0, 1, 1);
|
||||
this.layout.addWidget(activityLabel, 0, 1, 1, 1);
|
||||
layout.setColumnStretch(0, 1);
|
||||
layout.setColumnStretch(1, 1);
|
||||
layout.setRowStretch(0, 1);
|
||||
// this.setFocusPolicy(FocusPolicy.ClickFocus);
|
||||
get layout(): QGridLayout {
|
||||
return this.rootLayout;
|
||||
}
|
||||
}
|
||||
|
||||
class PawnPageWidget extends QListWidget {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
// this.setLayout(new FlexLayout());
|
||||
this.setInlineStyle('background: purple;');
|
||||
// this.layout.addWidget(new PawnWidget(Game.current.pawns[0]));
|
||||
|
||||
this.rootLayout = new QGridLayout()
|
||||
this.setLayout(this.rootLayout);
|
||||
this.setInlineStyle(`
|
||||
width: \'100%\';
|
||||
background: coral;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
`);
|
||||
|
||||
this.setFocusPolicy(FocusPolicy.ClickFocus);
|
||||
}
|
||||
}
|
||||
|
||||
function addSplitText(layout: QGridLayout, left: string, right: string, row: number) {
|
||||
layout.setSpacing(0);
|
||||
|
||||
const nameLabel = new QLabel();
|
||||
nameLabel.setText(left);
|
||||
nameLabel.setAlignment(AlignmentFlag.AlignLeft | AlignmentFlag.AlignTop);
|
||||
const activityLabel = new QLabel();
|
||||
activityLabel.setText(right);
|
||||
activityLabel.setAlignment(AlignmentFlag.AlignRight | AlignmentFlag.AlignTop);
|
||||
|
||||
layout.addWidget(nameLabel, row, 0, 1, 1);
|
||||
layout.addWidget(activityLabel, row, 1, 1, 1);
|
||||
layout.setRowStretch(row, 1);
|
||||
|
||||
// in theory this is redundant, calling this
|
||||
// function on the same layout multiple times...
|
||||
layout.setColumnStretch(0, 1);
|
||||
layout.setColumnStretch(1, 1);
|
||||
}
|
||||
|
||||
class PawnWidget extends GridItem {
|
||||
constructor(pawn: Pawn) {
|
||||
super();
|
||||
|
||||
addSplitText(
|
||||
this.layout,
|
||||
pawn.name.first + ' ' + pawn.name.last,
|
||||
pawn.status,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemWidget extends GridItem {
|
||||
constructor(itemState: ItemState<unknown>) {
|
||||
super();
|
||||
|
||||
addSplitText(
|
||||
this.layout,
|
||||
itemState.name,
|
||||
'' + (itemState.qty),
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ScrollPanel extends QScrollArea {
|
||||
centralWidget: QWidget;
|
||||
vLayout: QBoxLayout;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.setInlineStyle(`
|
||||
background: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
`)
|
||||
this.centralWidget = new QWidget();
|
||||
this.centralWidget.setInlineStyle(`
|
||||
background: rgba(0, 0, 0, 0);
|
||||
`)
|
||||
// this.setVerticalScrollBarPolicy(ScrollBarPolicy.ScrollBarAlwaysOn);
|
||||
this.setWidgetResizable(true);
|
||||
this.setWidget(this.centralWidget);
|
||||
this.vLayout = new QBoxLayout(Direction.TopToBottom);
|
||||
this.centralWidget.setLayout(this.vLayout);
|
||||
|
||||
this.fill();
|
||||
|
||||
this.vLayout.addStretch(1);
|
||||
|
||||
// for(let i = 0; i < 100; i ++) {
|
||||
// const button = new QPushButton();
|
||||
// button.setText('' + i);
|
||||
// this.vLayout.addWidget(button);
|
||||
// }
|
||||
}
|
||||
|
||||
refill() {
|
||||
for(const a of this.nodeChildren) {
|
||||
console.log(a);
|
||||
}
|
||||
this.fill();
|
||||
}
|
||||
|
||||
addWidget(widget: QWidget) {
|
||||
this.vLayout.addWidget(widget);
|
||||
}
|
||||
|
||||
abstract fill(): void;
|
||||
}
|
||||
|
||||
class PawnPageWidget extends ScrollPanel {
|
||||
fill() {
|
||||
for(const pawn of Game.current.pawns) {
|
||||
// const label = new QLabel();
|
||||
// label.setText(pawn.name.first);
|
||||
// this.layout.addWidget(label);
|
||||
this.addWidget(new PawnWidget(pawn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// class PawnPageWidget extends QListWidget {
|
||||
// constructor() {
|
||||
// super();
|
||||
// for (const pawn of Game.current.pawns) {
|
||||
// const pawnWidget = new PawnWidget(pawn);
|
||||
// const item = new QListWidgetItem();
|
||||
// this.addItem(item);
|
||||
// this.setItemWidget(item, pawnWidget);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// class PawnPageWidget extends QWidget {
|
||||
|
||||
// constructor() {
|
||||
// super();
|
||||
// this.setLayout(new QBoxLayout(Direction.TopToBottom));
|
||||
// // this.setLayout(new FlexLayout());
|
||||
|
||||
// for(const pawn of Game.current.pawns) {
|
||||
// this.layout.addWidget(new PawnWidget(pawn));
|
||||
const item = new QListWidgetItem();
|
||||
this.addItem(item);
|
||||
this.setItemWidget(item, new PawnWidget(pawn));
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
class TimeWidget extends QLabel {
|
||||
|
||||
|
|
@ -112,6 +213,38 @@ class TimeWidget extends QLabel {
|
|||
}
|
||||
}
|
||||
|
||||
class InventoryWidget extends QWidget {
|
||||
|
||||
|
||||
class InventoryPageWidget extends ScrollPanel {
|
||||
fill() {
|
||||
for(const itemState of Game.current.inv.items) {
|
||||
this.addWidget(new ItemWidget(itemState))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MultiplayerPlayerWidget extends GridItem {
|
||||
constructor(player: Player) {
|
||||
super();
|
||||
addSplitText(
|
||||
this.layout,
|
||||
player.name,
|
||||
player.host + ':' + player.port,
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MultiplayerPageWidget extends ScrollPanel {
|
||||
constructor() {
|
||||
super();
|
||||
network.on('change', () => {
|
||||
this.refill();
|
||||
})
|
||||
}
|
||||
fill(): void {
|
||||
for(const player of network.players) {
|
||||
this.addWidget(new MultiplayerPlayerWidget(player))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,10 +20,14 @@ win.setWindowTitle(APPLICATION_NAME);
|
|||
win.show();
|
||||
(global as any).win = win;
|
||||
win.addEventListener(WidgetEventTypes.Paint, _ => _);
|
||||
win.addEventListener('customContextMenuRequested', console.log)
|
||||
win.addEventListener('objectNameChanged', console.log)
|
||||
win.addEventListener('windowIconChanged', console.log)
|
||||
win.addEventListener('windowTitleChanged', console.log)
|
||||
win.addEventListener('customContextMenuRequested', console.log);
|
||||
win.addEventListener('objectNameChanged', console.log);
|
||||
win.addEventListener('windowIconChanged', console.log);
|
||||
win.addEventListener('windowTitleChanged', console.log);
|
||||
win.addEventListener(
|
||||
WidgetEventTypes.Close,
|
||||
() => ProcessManager.quit()
|
||||
);
|
||||
|
||||
setView(new LoadingView());
|
||||
|
||||
|
|
@ -54,7 +58,6 @@ export function isStarted() {
|
|||
|
||||
ProcessManager.on('reload', () => {
|
||||
RequestReloadPopup.show();
|
||||
//
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -62,6 +65,6 @@ ProcessManager.on('reload', () => {
|
|||
function f() {
|
||||
win.repaint();
|
||||
win.update();
|
||||
setTimeout(f, 100);
|
||||
setTimeout(f, 0);
|
||||
}
|
||||
f();
|
||||
|
|
@ -36,7 +36,7 @@ export class Item<Data = any> {
|
|||
|
||||
register(force = true) {
|
||||
if((!this.id || !this.name) && !force) return;
|
||||
console.log('Added item', (this.name.singular ?? "[No Name]").padStart(20, ' '), `| (${this.id})`)
|
||||
// console.log('Added item', (this.name.singular ?? "[No Name]").padStart(20, ' '), `| (${this.id})`)
|
||||
items.set(this.id, this);
|
||||
return this;
|
||||
}
|
||||
|
|
@ -63,6 +63,10 @@ export class ItemState<Data> extends Serializable {
|
|||
return new ItemState<Data>(this.item, qty, this.data);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.qty === 1 ? this.item.name.singular : this.item.name.plural;
|
||||
}
|
||||
|
||||
get item() {
|
||||
if(!items.has(this.itemId))
|
||||
throw new Error('unknown item: ' + this.itemId);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ let currentTheme = backupTheme;
|
|||
const themes: Map<ThemeName, Theme> = new Map();
|
||||
|
||||
export function registerTheme(name: ThemeName, theme: Partial<Theme>) {
|
||||
console.log('Registered theme', name);
|
||||
// console.log('Registered theme', name);
|
||||
themes.set(name, merge(backupTheme, theme));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export class EscapeMenu {
|
|||
} else if (key.full === 'enter') {
|
||||
switch(this.selected) {
|
||||
case 0: {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
break;
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ export class EscapeMenu {
|
|||
}
|
||||
}
|
||||
} else if(key.full === 'escape') {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
}
|
||||
this.render();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class GiftPopup {
|
|||
if(key.full === 'enter') {
|
||||
this.send();
|
||||
} if(key.full === 'escape' || key.full === 'enter') {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
} else if (key.full === 'up') {
|
||||
this.selected --;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class PawnDetails {
|
|||
});
|
||||
this.box.on('keypress', (evt: {}, key: {full: string}) => {
|
||||
if(key.full === 'escape' || key.full === 'enter') {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
} else if (key.full === 'up') {
|
||||
// this.selected --;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class Popup {
|
|||
});
|
||||
this.box.on('keypress', (evt: {}, key: {full: string}) => {
|
||||
if(key.full === 'escape' || key.full === 'enter') {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export class SelectItem {
|
|||
}
|
||||
|
||||
private close() {
|
||||
Game.current.clock.start();
|
||||
Game.current.clock.resume();
|
||||
panels.screen.remove(this.box);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ export function start() {
|
|||
export function stop() {
|
||||
screen.destroy();
|
||||
// process.stdout.write('\x1b[?1049l');
|
||||
process.stdout.write(ansi.cursor.show);
|
||||
}
|
||||
|
||||
// move to some debugging shit, idk
|
||||
|
|
|
|||
Loading…
Reference in New Issue