Created
February 4, 2019 20:12
-
-
Save stenno/d6389c8e745ec06b87011ce1b4e96223 to your computer and use it in GitHub Desktop.
low level API for nethack in node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://nethackwiki.com/wiki/Vt_tiledata | |
const pty = require("node-pty"); | |
const AnsiTerminal = require("node-ansiterminal").AnsiTerminal; | |
const AnsiParser = require("node-ansiparser"); | |
const WAITING_DELAY = 100; // a short delay to capture all neccessary data | |
// we monkeypatch AnsiTerminal for vt_tiledata support | |
class TiledataTerminal extends AnsiTerminal { | |
constructor(cols, rows, scrollLength) { | |
super(cols, rows, scrollLength); | |
const old_inst_c = this.inst_c; | |
this.waiting = false; | |
this.current_window = 0; | |
this.inst_c = (collected, params, flag) => { | |
if (flag === "z") { | |
this.last_char = ''; // monkeypatching intensifies | |
this._rem_c = ''; | |
this.wrap = false; | |
this.TILE(params); | |
} else { | |
old_inst_c.bind(this)(collected, params, flag); | |
} | |
} | |
this.inst_c = this.inst_c.bind(this); | |
} | |
getWindow(number) { | |
return this.screen.buffer.reduce((acc, row) => [...acc, ...row.cells.filter(cell => cell.tiles_window === number)], []); | |
} | |
TILE([check, command, arg1, arg2]) { | |
// lazy here | |
const handlers = [ | |
this.handleStartGlyph, | |
this.handleEndGlyph, | |
this.handleSelectWindow, | |
this.handleWait | |
]; | |
handlers[command].bind(this)(arg1, arg2); | |
} | |
handleStartGlyph(number, effect) { | |
this.screen.buffer[this.cursor.row].cells[this.cursor.col].glyph = number; | |
this.screen.buffer[this.cursor.row].cells[this.cursor.col].effect = effect; | |
this.screen.buffer[this.cursor.row].cells[this.cursor.col].tiles_window = this.current_window; | |
} | |
handleEndGlyph(_) { | |
// TBI | |
} | |
handleSelectWindow(number) { | |
this.current_window = number; | |
} | |
handleWait() { | |
this.waiting = true; | |
} | |
resetWait() { | |
this.waiting = false; | |
} | |
} | |
const terminal = new TiledataTerminal(80, 24, 500); | |
const parser = new AnsiParser(terminal); | |
const shell = "bash"; | |
const ptyProcess = pty.spawn(shell, [], { | |
name: "xterm", | |
cols: 80, | |
rows: 24, | |
env: process.env | |
}); | |
const promisifiedOnce = async (emitter, event) => { | |
return new Promise((resolve, reject) => emitter.once(event, data => resolve(data))); | |
}; | |
// super nasty, pls don't kill me | |
// at some point i should figure out the window indices | |
const getAllWindows = () => [0,1,2,3,4,5,6, undefined].map(x => [x, terminal.getWindow(x)]); | |
ptyProcess.on("data", data => { | |
parser.parse(data); | |
console.log("data", data.length, terminal.waiting); | |
if (terminal.waiting) { | |
// we don't expect any more data here unless we send some more | |
terminal.current_window = 0; | |
terminal.waiting = false; | |
setTimeout(() => ptyProcess.emit("tiledata_waiting"), WAITING_DELAY); | |
} | |
}); | |
ptyProcess.once("tiledata_waiting", () => { | |
console.log("we are waiting for the first time now"); | |
doSomeThings().then(x => console.log("done...")).then(() => | |
console.log(getAllWindows().map(([idx, window]) => [idx, window.length])) | |
); | |
}); | |
const doSomeThings = async() => { | |
try { | |
await doInput(" "); | |
console.log(terminal.toString()); | |
await doInput(" "); | |
console.log(terminal.toString()); | |
await doInput("#version\n"); | |
console.log(terminal.toString()); | |
} catch (e) { | |
// yolo | |
} | |
}; | |
const doInput = async (input) => { | |
ptyProcess.write(input); | |
return promisifiedOnce(ptyProcess, "tiledata_waiting"); | |
}; | |
ptyProcess.write("ssh nethack@eu.hardfought.org\nlstenno\nnotmypassword\nv"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment