Make sure watchers start with completely drawn screens.
TermSessions now buffer all data since the last screen clear, so new Watchers can start with complete screens.
This commit is contained in:
parent
67f187700c
commit
5f914901d1
1 changed files with 52 additions and 5 deletions
57
rlgwebd.js
57
rlgwebd.js
|
|
@ -28,25 +28,29 @@ var games = {
|
|||
"name": "Rogue V3",
|
||||
"uname": "rogue3",
|
||||
"suffix": ".r3sav",
|
||||
"path": "/bin/rogue3"
|
||||
"path": "/bin/rogue3",
|
||||
"clear": new Buffer([27, 91, 72, 27, 91, 50, 74]) // CSI H CSI 2J
|
||||
},
|
||||
"rogue4": {
|
||||
"name": "Rogue V4",
|
||||
"uname": "rogue4",
|
||||
"suffix": ".r4sav",
|
||||
"path": "/bin/rogue4"
|
||||
"path": "/bin/rogue4",
|
||||
"clear": new Buffer([27, 91, 72, 27, 91, 50, 74]) // CSI H CSI 2J
|
||||
},
|
||||
"rogue5": {
|
||||
"name": "Rogue V5",
|
||||
"uname": "rogue5",
|
||||
"suffix": ".r5sav",
|
||||
"path": "/bin/rogue5"
|
||||
"path": "/bin/rogue5",
|
||||
"clear": new Buffer([27, 91, 72, 27, 91, 50, 74]) // CSI H CSI 2J
|
||||
},
|
||||
"srogue": {
|
||||
"name": "Super-Rogue",
|
||||
"uname": "srogue",
|
||||
"suffix": ".srsav",
|
||||
"path": "/bin/srogue"
|
||||
"path": "/bin/srogue",
|
||||
"clear": new Buffer([27, 91, 72, 27, 91, 74]) // CSI H CSI J
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -118,6 +122,10 @@ function TermSession(game, lkey, dims, handlers) {
|
|||
var ttyrec = path.join("/dgldir/ttyrec", this.pname, this.game.uname,
|
||||
ts + ".ttyrec");
|
||||
this.record = fs.createWriteStream(ttyrec, { mode: 0664 });
|
||||
/* Holds the output since the last screen clear, so watchers can begin
|
||||
* with a complete screen. */
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
logins[lkey].sessions.push(this.sessid);
|
||||
tslog("%s playing %s (index %d, pid %d)", this.pname, this.game.uname,
|
||||
this.sessid, this.child.pid);
|
||||
|
|
@ -131,10 +139,30 @@ function TermSession(game, lkey, dims, handlers) {
|
|||
chunk.writeUInt32LE(buf.length, 8);
|
||||
buf.copy(chunk, 12);
|
||||
ss.record.write(chunk);
|
||||
ss.framepush(buf);
|
||||
ss.emit('data', buf);
|
||||
}
|
||||
this.child.stdout.on("data", ttyrec_chunk);
|
||||
this.child.stderr.on("data", ttyrec_chunk);
|
||||
this.framepush = function(chunk) {
|
||||
/* If this chunk resets the screen, discard what preceded it. */
|
||||
if (bufncmp(chunk, this.game.clear, this.game.clear.length)) {
|
||||
this.framebuf = new Buffer(1024);
|
||||
this.frameoff = 0;
|
||||
}
|
||||
/* Make sure there's space. */
|
||||
while (this.framebuf.length < chunk.length + this.frameoff) {
|
||||
var nbuf = new Buffer(this.framebuf.length * 2);
|
||||
this.framebuf.copy(nbuf, 0, 0, this.frameoff);
|
||||
this.framebuf = nbuf;
|
||||
if (this.framebuf.length > 65536) {
|
||||
tslog("Warning: Game %d frame buffer at %d bytes", this.sessid,
|
||||
this.framebuf.length);
|
||||
}
|
||||
}
|
||||
chunk.copy(this.framebuf, this.frameoff);
|
||||
this.frameoff += chunk.length;
|
||||
};
|
||||
this.write = function(data) {
|
||||
this.child.stdin.write(data);
|
||||
};
|
||||
|
|
@ -144,7 +172,7 @@ function TermSession(game, lkey, dims, handlers) {
|
|||
ss.emit('exit', code, signal);
|
||||
var id = ss.sessid;
|
||||
delete sessions[id];
|
||||
tslog("Session %s ended.", id);
|
||||
tslog("Game %s ended.", id);
|
||||
});
|
||||
this.close = function () {
|
||||
this.child.kill('SIGHUP');
|
||||
|
|
@ -165,6 +193,9 @@ function Watcher(session) {
|
|||
this.id = randkey(2);
|
||||
}
|
||||
clients[this.id] = this;
|
||||
/* Recreate the current screen state from the session's buffer. */
|
||||
this.sendQ.push({"t": "d", "n": this.nsend++,
|
||||
"d": session.framebuf.toString("hex", 0, session.frameoff)});
|
||||
function dataH(buf) {
|
||||
var reply = {};
|
||||
reply.t = "d";
|
||||
|
|
@ -388,6 +419,21 @@ function randkey(words) {
|
|||
return key;
|
||||
}
|
||||
|
||||
/* Compares two buffers, returns true for equality up to index n */
|
||||
function bufncmp(buf1, buf2, n) {
|
||||
if (!Buffer.isBuffer(buf1) || !Buffer.isBuffer(buf2))
|
||||
return false;
|
||||
for (var i = 0; i < n; i++) {
|
||||
if (i == buf1.length && i == buf2.length)
|
||||
return true;
|
||||
if (i == buf1.length || i == buf2.length)
|
||||
return false;
|
||||
if (buf1[i] != buf2[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function tslog() {
|
||||
arguments[0] = new Date().toISOString() + ": " + String(arguments[0]);
|
||||
console.log.apply(console, arguments);
|
||||
|
|
@ -839,6 +885,7 @@ function webHandler(req, res) {
|
|||
if (formdata.t == "q") {
|
||||
/* The client wants to terminate the process. */
|
||||
endgame(client, res);
|
||||
return; // endgame() calls readFeed() itself.
|
||||
}
|
||||
else if (formdata.t == "d" && typeof(formdata.d) == "string") {
|
||||
if (!(client instanceof Player)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue