I noticed this when playing a Rapture-based MUD -- that's Iron Realms' codebase, used at Achaea, Aetolia and Imperian. (I was using Aetolia, at aetolia.com:23, but also saw it on another game using the same codebase.) When sending shop lists, the game sometimes sends backspaces (^H) to format the list of items, but MUSHclient renders the backspaces as an inverse space with a dot in the middle (well, at least when using Fixedsys as the font) instead of actually backspacing. This makes it very hard to look at WARES lists in these games...
Backspace bug...
Posted by Atholbrose on Tue 01 Jun 2004 08:23 PM — 14 posts, 57,709 views.
I'll look into it, but I think it is weird for a server to backspace its descriptions.
Backspacing is primarily provided for humans to correct typing errors. For a server to send something like:
(where XXX is the backspace), so that you eventually see:
is a bit weird in my view. Can't the server get its descriptions right in the first place? Can't it do the backspacing before sending? It's not like there is a human sitting there making mistakes.
Backspacing is primarily provided for humans to correct typing errors. For a server to send something like:
You are carrying a catXXXdog
(where XXX is the backspace), so that you eventually see:
You are carrying a dog
is a bit weird in my view. Can't the server get its descriptions right in the first place? Can't it do the backspacing before sending? It's not like there is a human sitting there making mistakes.
Maybe it's a low tech mud, those things have humans typing the roomdescs real time...
I can try to make MUSHclient do local backspace processing, eg.
You see a cat\x08\x08\x08dog
However what happens if you get this?
You are killed\n
(and in the next packet)
\x08\x08\x08\x08\x08\x08\x08slightly wounded\n
(where \x08 is backspace, and \n is newline).
By backspacing over the newline you have altered the meaning of the incoming text. MUSHclient (and other clients, I am sure) will process triggers when a newline is received, however a trigger that matches "You are killed" should now (somehow) be discarded and the trigger that matches "You are slighly wounded" used instead.
But, you can't retrospectivly discard triggers. The "You are killed" trigger may have you drink a potion, that is the wrong potion if you are only wounded. Too late, the response has been sent to the MUD. Maybe you should send some backspaces to the MUD as well? Try to get the mud to "undo" the "drink red potion" command?
The whole thing is getting ridiculous.
Here is another potential problem ...
Say the MUD sends you this:
\x1B[31m
That is the ANSI code to set the text colour to red. Now what happens if it follows that by 5 backspaces? eg.
\x1B[31m\x08\x08\x08\x08\x08
Does the text go to red or not?
I can make MUSHclient take backspaces in a single packet to "undo" the previous character, before submitting for the main processing, that is not much work. However I still think the idea of MUD servers sending backspaces is strange.
You see a cat\x08\x08\x08dog
However what happens if you get this?
You are killed\n
(and in the next packet)
\x08\x08\x08\x08\x08\x08\x08slightly wounded\n
(where \x08 is backspace, and \n is newline).
By backspacing over the newline you have altered the meaning of the incoming text. MUSHclient (and other clients, I am sure) will process triggers when a newline is received, however a trigger that matches "You are killed" should now (somehow) be discarded and the trigger that matches "You are slighly wounded" used instead.
But, you can't retrospectivly discard triggers. The "You are killed" trigger may have you drink a potion, that is the wrong potion if you are only wounded. Too late, the response has been sent to the MUD. Maybe you should send some backspaces to the MUD as well? Try to get the mud to "undo" the "drink red potion" command?
The whole thing is getting ridiculous.
Here is another potential problem ...
Say the MUD sends you this:
\x1B[31m
That is the ANSI code to set the text colour to red. Now what happens if it follows that by 5 backspaces? eg.
\x1B[31m\x08\x08\x08\x08\x08
Does the text go to red or not?
I can make MUSHclient take backspaces in a single packet to "undo" the previous character, before submitting for the main processing, that is not much work. However I still think the idea of MUD servers sending backspaces is strange.
Believe me, I kind of think it's weird too. AFAIK, the muds are built on an LPC driver, and it shouldn't be hard to create a string-truncation function if that's what's needed. The whole backspace thing seems to be a very hacky work-around for it.
The shop listings are in a four-column table, but if the long description of the item is longer than the description column, instead of being truncated, the whole string is printed, some backspaces are sent, and the price (next column) is printed. "Hey, it works in telnet," is the thinking, I suppose.
This is also the only place the MUD ever seems to use backspaces.
As far as how to process them? You bring up good things about ANSI codes, but I think it's pretty clear you shouldn't be able to backspace over a newline.
Even if you end up not wanting to implement the actual backspacing, for whatever reason, I think the client probably shouldn't actually print characters < ASCII 32. (Even given extended ASCII, would a MUD *ever* expect ASCII 8 to result in a printed character?) If the \x08s were simply not printed it'd look a lot less messy than it does right now.
The shop listings are in a four-column table, but if the long description of the item is longer than the description column, instead of being truncated, the whole string is printed, some backspaces are sent, and the price (next column) is printed. "Hey, it works in telnet," is the thinking, I suppose.
This is also the only place the MUD ever seems to use backspaces.
As far as how to process them? You bring up good things about ANSI codes, but I think it's pretty clear you shouldn't be able to backspace over a newline.
Even if you end up not wanting to implement the actual backspacing, for whatever reason, I think the client probably shouldn't actually print characters < ASCII 32. (Even given extended ASCII, would a MUD *ever* expect ASCII 8 to result in a printed character?) If the \x08s were simply not printed it'd look a lot less messy than it does right now.
EMOTE hacks a knife into virgin's chest "With bloody sacrifice I'm calling to the power of Evil Gods and bringing this thread back to life! MUAHAHA!!!"
Seriously, can we please get server-side backspace implemented? I like your client very much, but on "The Void" backspace is used in pretty reasonable way:
Phase a) "> " prompt is sent to the player inviting him to type command.
Phase b) if user sends command, it is echoed on the same line with prompt.
Phase c) if something happens before user sends his command, server sends backspaces to wipe out "> " prompt and informs user on thus cleared line.
Without backspace implemented, any asynchronous output on this MUSH starts with "> ##" (I type # instead of BSP symbol here). This is a bit annoying. In my humble opinion, backspace can be implemented as purely "rendering" feature - instead of putting its symbol on cursor position and moving cursor forward, it can put space on position previous to cursor and move cursor backward. No interaction with newline, no special meaning in terms of ANSI codes or triggers - just final touch on screen buffer.
Anyway, thank you for great work!
Seriously, can we please get server-side backspace implemented? I like your client very much, but on "The Void" backspace is used in pretty reasonable way:
Phase a) "> " prompt is sent to the player inviting him to type command.
Phase b) if user sends command, it is echoed on the same line with prompt.
Phase c) if something happens before user sends his command, server sends backspaces to wipe out "> " prompt and informs user on thus cleared line.
Without backspace implemented, any asynchronous output on this MUSH starts with "> ##" (I type # instead of BSP symbol here). This is a bit annoying. In my humble opinion, backspace can be implemented as purely "rendering" feature - instead of putting its symbol on cursor position and moving cursor forward, it can put space on position previous to cursor and move cursor backward. No interaction with newline, no special meaning in terms of ANSI codes or triggers - just final touch on screen buffer.
Anyway, thank you for great work!
The client currently respects carriage-return (as an option). You could make a small plugin that converts backspace to carriage-return, enable that option, and you should get that effect (in the situation you describe).
I have tried your idea and it almost worked. I made a regexp trigger that matches on strings starting with this "> ##" stuff and sends rest of string to output while omitting original:
Trigger: ^\> \x08\x08 \x08\x08(.*?)$
Send: \r%1
Send to: Output
Checked Omit from output
Checked Regular expression
And this would look like perfect solution if this way I wasn't loosing any ANSI colors that was in original string. Is there any way to make trigger send modified string back to output keeping its colors?
Trigger: ^\> \x08\x08 \x08\x08(.*?)$
Send: \r%1
Send to: Output
Checked Omit from output
Checked Regular expression
And this would look like perfect solution if this way I wasn't loosing any ANSI colors that was in original string. Is there any way to make trigger send modified string back to output keeping its colors?
local styles = TriggerStyleRuns[#TriggerStyleRuns]
Tell("\r")
NoteStyle(styles.style)
ColourTell(styles.textcolour, styles.backcolour, "%1")Give this a try, with "Send to" set to "Send to Script (after omit)". (This does assume you have Lua chosen as your script language.)
Diagoras said:
I have tried your idea and it almost worked. I made a regexp trigger that matches on strings starting with this "> ##" stuff and sends rest of string to output while omitting original:
I have tried your idea and it almost worked. I made a regexp trigger that matches on strings starting with this "> ##" stuff and sends rest of string to output while omitting original:
I meant in a plugin, because you can get at the original packet there. Look for the backspace character and change it to the carriage-return character.
Nick Gammon said:
I meant in a plugin, because you can get at the original packet there. Look for the backspace character and change it to the carriage-return character.
I meant in a plugin, because you can get at the original packet there. Look for the backspace character and change it to the carriage-return character.
Works like charm - thank you!
And for sake of future generations I'll leave this here:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on âîñêðåñåíüå, Ñåíòÿáðü 02, 2012, 3:20 -->
<!-- MuClient version 4.81 -->
<!-- Plugin "void_bsp" generated by Plugin Wizard -->
<muclient>
<plugin
name="void_bsp"
id="e60c923a196c042e291bb825"
language="Lua"
date_written="2012-09-02 03:18:48"
requires="4.73"
version="1.0"
>
</plugin>
<!-- Get our standard constants -->
<include name="constants.lua"/>
<!-- Script -->
<script>
<![CDATA[
function OnPluginPacketReceived(sText)
res = string.gsub(sText, "\b\b", "\r")
return res
end
]]>
</script>
</muclient>
Good work, thanks for posting.
You can remove the standard constants line.
You can remove the standard constants line.
Strictly speaking, due to the way information was passed via telnet, there was no such thing as "backspacing over a newline". A newline didn't add a newline character to the buffer, it simply moved the cursor position. This is also what causes so many issues with other things, you keep thinking in terms of a "document", when it comes to storing the actual data of what transpired. A telnet client, even when you where lucky enough to have a display with some mad number of characters possible, like 160x43, had the display work like:
160 characters + color coding
160 characters + color coding
...
160 characters + color coding
It wasn't:
30 characters + newline
12 characters + newline
...
So, no, a backspace not only shouldn't erase a newline, in telnet, it should land the cursor, for all following data, at the "last possible" character position of the display, on the prior line. Logically, the newline shouldn't even exist, at all, once the characters for a line are stored, except maybe in the back buffer, and then, its purely treated as a marker, designating where *that* line ends (in fact, it isn't even needed in the buffer, since, if the client wraps at X characters, like 80, then **every line** will have 80 characters, to finding which line you are on is purely a matter of counting how many groups of 80 characters you have. If someone changes it to be 100, or 60 characters, you "backfill/rewrap/truncate" the buffers lines, to make it 100 characters per line. In any case, you never treat the line content as an arbitrary number of characters, its always what ever the wrap point is in size, even if only two characters where ever placed there.
I hadn't thought about it, but I think this is one of the hangups with working out text positioning. You seem to assume that such positioning works over the entire buffer, the whole thing needs to be recorded, and that scrolling back should replay it. Nope.. The only extra character that should *ever* be in the buffer, technically, would be a page break, and only for convenience, since you do what to be able to "replay" back to individual pages, maybe. All other positioning, changes, become "fixed" once they get buffered, and, strictly speaking, that means everything more than 23 lines (43, assuming your telnet negotiation, or something, can tell you have that many to work with, but since like 1% of PCs could do that, and telnet didn't support it exactly...). So, while trying to move "down" 23 lines would add 23 blank lines, moving "up" 24 lines would only get you 22 lines from where you are now (since you can't scroll "past" the "top of the display", which has to be a set size.
Yes, clients can now disobey those things, and have as many lines on the display as can fit, but the "positioning" functions all assume a "known" number of lines, and columns, with "no" special characters stored (or, at least not backspaces, newlines, carriage returns, etc.) As far as those functions are concerned, your "display" is still a fixed size, 80x23 grid, and everything else that went on is completely irrelevant to what is "on" that display. As such, using backspace to position makes perfect sense, and was probably how some systems implemented positioning, using backspace, forward, up, and newline, instead of having a machine language method of directly controlling the cursor position (or, at least that would be my guess).
160 characters + color coding
160 characters + color coding
...
160 characters + color coding
It wasn't:
30 characters + newline
12 characters + newline
...
So, no, a backspace not only shouldn't erase a newline, in telnet, it should land the cursor, for all following data, at the "last possible" character position of the display, on the prior line. Logically, the newline shouldn't even exist, at all, once the characters for a line are stored, except maybe in the back buffer, and then, its purely treated as a marker, designating where *that* line ends (in fact, it isn't even needed in the buffer, since, if the client wraps at X characters, like 80, then **every line** will have 80 characters, to finding which line you are on is purely a matter of counting how many groups of 80 characters you have. If someone changes it to be 100, or 60 characters, you "backfill/rewrap/truncate" the buffers lines, to make it 100 characters per line. In any case, you never treat the line content as an arbitrary number of characters, its always what ever the wrap point is in size, even if only two characters where ever placed there.
I hadn't thought about it, but I think this is one of the hangups with working out text positioning. You seem to assume that such positioning works over the entire buffer, the whole thing needs to be recorded, and that scrolling back should replay it. Nope.. The only extra character that should *ever* be in the buffer, technically, would be a page break, and only for convenience, since you do what to be able to "replay" back to individual pages, maybe. All other positioning, changes, become "fixed" once they get buffered, and, strictly speaking, that means everything more than 23 lines (43, assuming your telnet negotiation, or something, can tell you have that many to work with, but since like 1% of PCs could do that, and telnet didn't support it exactly...). So, while trying to move "down" 23 lines would add 23 blank lines, moving "up" 24 lines would only get you 22 lines from where you are now (since you can't scroll "past" the "top of the display", which has to be a set size.
Yes, clients can now disobey those things, and have as many lines on the display as can fit, but the "positioning" functions all assume a "known" number of lines, and columns, with "no" special characters stored (or, at least not backspaces, newlines, carriage returns, etc.) As far as those functions are concerned, your "display" is still a fixed size, 80x23 grid, and everything else that went on is completely irrelevant to what is "on" that display. As such, using backspace to position makes perfect sense, and was probably how some systems implemented positioning, using backspace, forward, up, and newline, instead of having a machine language method of directly controlling the cursor position (or, at least that would be my guess).