12 Mar, 2009, Scandum wrote in the 81st comment:
Votes: 0
Nick Gammon said:
Despite my misgivings about telnet protocols, that isn't hard to do. Already it supports plugin callbacks for the Aardwolf telnet negotiation, so adding a different one is no big deal. Basically then, a plugin could just get all the stuff inside the IAC SB .. whatever .. IAC SE as a string. Of course with imbedded NULs that won't be helpful for most script languages, although Lua could handle it. I might have to break the resulting string down into a table at the NULs for the other script languages. Sigh. You sure you don't want to use another obscure character like ETX (0x03) (or TAB)? Then at least every language can handle it, and clients that don't handle 0x00 well will cope too.

It would be a lot easier to use MSSP syntax, using ctrl-A (0x01) for variables and ctrl-B (0x02) for values. You'd grab a free telopt and assume that the client will deal with whatever it is that is transmitted. Like with MSSP you could define a list of default variables and define their behavior, so scripts could be created that would work for several mud servers. Could call it MSDP (Mud Server Data Protocol).

ZMP is a little too strictly defined to work well for a more open ended approach I think.
12 Mar, 2009, elanthis wrote in the 82nd comment:
Votes: 0
Scandum said:
ZMP is a little too strictly defined to work well for a more open ended approach I think.


That is an absolutely absurd statement.

The ZMP framing is in all ways identical to the MSSP framing, except ZMP expects one "variable" per subrequest instead of allowing many. Which really makes absolutely no different at all. Oh, and ZMP is actually easier to implement in C than MSSP, as the example code I posted above proves: MSSP requires more logic to decode. It doesn't even make sense IMO to try to parse the ZMP requires in a script language: DO IT IN THE TELNET HANDLER. 12 lines of code, which I already posted above for you to happily cut-n-paste into your project. Voila.

This NUL paranoia is making very little sense to me. If your TELNET code chokes on NUL bytes then you have other problems. Servers would choke on NAWS (surprise! it has *two* NUL bytes in every request!) while clients will choke on MCCP2 (which results in raw binary data being transmitted over the wire). Seriously, just 12 lines of code to add ZMP parsing to any existing code that handles TELNET (which MSSP also requires) that works just fine with whatever script language you could possibly want.

I could easily replace the entirety of MSSP's custom syntax with a single ZMP command and totally remove the need to support two separate protocols, for that matter:

mssp.var (variable, value) - server only

Sets a status variable (name given by first parameter) to the value provided (given by second variable). The list of defined variables and their allowed values is identical to that given in the MSSP spec.

You can consider that an semi-official package spec for all I care.
12 Mar, 2009, Tyche wrote in the 83rd comment:
Votes: 0
I can't for the life figure out why NUL is some sort of problem. It leads me to believe some are using string functions on network buffers, when they ought not.
12 Mar, 2009, elanthis wrote in the 84th comment:
Votes: 0
Also, to reiterate: ZMP is already implemented in several clients and servers. Debating the merits of NUL – which in retrospect I would have done differently if for no other reason than to avoid this pedantry – is moot at this point.
12 Mar, 2009, David Haley wrote in the 85th comment:
Votes: 0
Wait, I'm also curious about where the NUL byte is coming into play.

If the C code splits the string at NUL, the scripting language never sees it. If the scripting language has an array of characters (not a string in its literal sense, but an array, like a network buffer) you can still split on NUL.

Where exactly are NULs coming into play? I can understand why they'd be a problem if – as Tyche said – somebody is using string functions, but is there an impossibility issue here or an impracticality issue?
12 Mar, 2009, David Haley wrote in the 86th comment:
Votes: 0
Oh, and if we're going to force MSSP into a subneg protocol (which I still disagree with) I'm all for making it a ZMP package…
12 Mar, 2009, Vassi wrote in the 87th comment:
Votes: 0
I'm going to branch my current client so I can use it to prototype these early packages. It should be fun.

I think I'm going to call it Boots =D
12 Mar, 2009, elanthis wrote in the 88th comment:
Votes: 0
Tyche said:
I can't for the life figure out why NUL is some sort of problem. It leads me to believe some are using string functions on network buffers, when they ought not.


Apparently people are trying to pass the raw TELNET subrequest buffers into a script language as a text string for further processing, and some script languages (it has not been stated which, but I'm assuming they're homegrown engines) are implemented using the C string routines for string data types.

That is, if they have a buffer they put the subrequest data into, they're trying to do something like:

push_script_string_length(buffer, buffer_length)
script_invoke_function("process_subrequest")


I don't really understand why you'd do that. For whatever reason, all it takes to "fix" is:

if buffer[0] == ZMP then
parse_zmp // tiny itsy bitsy handful of code

script_invoke_function_argv("process_zmp", argc, argv)
else
push_script_string_length(buffer, buffer_length)
script_invoke_function("process_subrequest")
end if


Heck, if you're using Lua for your script language, the parsing code actually gets _smaller_ because you don't need the argv array – you just push the string as you parse them:

/* assumes buffer does not include the ZMP byte – adjust by +1 in two places accordingly if it does */
int argc;
const char *c = buffer /* +1 */;

if (buffer_length == 0 /* +1 */ || buffer[buffer_length - 1] != 0)
return error; /* empty/invalid ZMP command buffer */

lua_getglobal(lua_state, "do_zmp");

for (argc = 0; c != buffer + buffer_length + 1; ++argc) {
lua_pushstring(lua_state, c);
c += strlen© + 1;
}

if (lua_pcall(lua_state, argc, 0, 0) != 0)
error(lua_state, "zmp handler failed: %s", lua_tostring(lua_state, -1));


That's 11 lines of code including the complete code for invoking the Lua ZMP handling routines. Talk about simple!
13 Mar, 2009, Scandum wrote in the 89th comment:
Votes: 0
elanthis said:
Scandum said:
ZMP is a little too strictly defined to work well for a more open ended approach I think.


That is an absolutely absurd statement.

The ZMP framing is in all ways identical to the MSSP framing, except ZMP expects one "variable" per subrequest instead of allowing many.

ZMP needs to be negotiated twice as well, once for zmp, and again for the package. Next there's the need to constantly stuff in mssp.var, as well as that it doesn't work well for chaining data. It adds a lot of overhead for something of limited need.

Some kind of event handler could be created to deal with NUL so the script gets to deal with the data pre-parsed, even then it's still going to be a pain in the ass because the zmp.support response needs to contain a NUL byte, so a client developer would have to add more than just a generic event handler.

elanthis said:
I could easily replace the entirety of MSSP's custom syntax with a single ZMP command and totally remove the need to support two separate protocols, for that matter:

mssp.var (variable, value) - server only

You'd still have the same problems, zmp sounds nice in theory, but it's a swiss army knife when all you need is a fork and a spoon. You'd have an extra 15 byte overhead per variable, so you'll be dealing with more wrapping than data. Especially for large muds that's just not feasible when you have to transfer a complex interface to potentially over a hundred players, and as has been pointed out, even for languages that can deal with NULs it is often still a pain in the ass.
13 Mar, 2009, quixadhal wrote in the 90th comment:
Votes: 0
Scandum said:
Especially for large muds that's just not feasible when you have to transfer a complex interface to potentially over a hundred players

Which is why we argued against making it a telnet negotiation in the first place, since of the hundred players, 99 of them don't care and will ignore the data, while the 1 "player" who is the crawler could have just executed a "status" command to get the data at the login prompt.

Water under the bridge.
13 Mar, 2009, Scandum wrote in the 91st comment:
Votes: 0
quixadhal said:
Which is why we argued against making it a telnet negotiation in the first place, since of the hundred players, 99 of them don't care and will ignore the data, while the 1 "player" who is the crawler could have just executed a "status" command to get the data at the login prompt.

Water under the bridge.

With MSSP players only get 3 bytes worth of spam. But I wasn't referring to MSSP, but to a MSSP like implementation vs ZMP for a data transfer protocol that would send continuous interface updates.
13 Mar, 2009, Tyche wrote in the 92nd comment:
Votes: 0
Scandum said:
With MSSP players only get 3 bytes worth of spam. But I wasn't referring to MSSP, but to a MSSP like implementation vs ZMP for a data transfer protocol that would send continuous interface updates.


I read Elanthis "proposal" as an off the cuff comment to illustrate how trivial it is to add one's own commands and packages. Given half a thought I came up with..

Quote
x-zmp-proposed.environment

The x-zmp-proposed.environment command communicates important environment variables to the server or client.
This command contains an arbitrary number of variable name value pairs. Once support for the command is established the server or client is free to send the command as often as it thinks necessary, normally when a change in environment occurs.

IAC SB ZMP "x-zmp-proposed.environment" NUL "variable-1" NUL "value-1" NUL … "variable-n" NUL "value-n" NUL IAC SE


If the negotiation seems tedious, perhaps instead of playing guess the command with a series of zmp.check's, an optional inversion of the negotiation mechanism might be better.

Quote
x-zmp-proposed.checkall

The x-zmp-proposed.checkall command request that all supported ZMP commands be sent to the requestor. The available commands must not change after the ZMP session has begun. The x-zmp-proposed.checkall command should only be sent once per ZMP session.

IAC SB ZMP "x-zmp-proposed.checkall" NUL IAC SE

x-zmp-proposed.supportedcommands

The x-zmp-proposed.supportedcommands command is used only as a response to the zmp.checkall request. The available commands must not change after the ZMP session has begun.

IAC SB ZMP "x-zmp-proposed.supportedcommands" NUL "command-1" NUL "command-2" NUL … "command-n" NUL IAC SE
13 Mar, 2009, Vassi wrote in the 93rd comment:
Votes: 0
There are many options for command checking.

You could have it work like the telnet Terminal and have the server ask the client to report what commands it supports. It should be able to figure out from there what the client is or is not capable of. You can also have the check command ask for more than one, i.e.

IAC SB ZMP zmp.check subwindow | compass | style

and then the client can echo back only the ones it supports.

IAC SB ZMP zmp.support subwindow | style

Quote
MSSP you could define a list of default variables and define their behavior, so scripts could be created that would work for several mud servers. Could call it MSDP (Mud Server Data Protocol).

ZMP is a little too strictly defined to work well for a more open ended approach I think.


ZMP is too strictly defined…so let's define a strict list of variables? -blink- Huh?

ZMP commands imply specific action, they aren't just passing variables back and forth. While certainly there needs to be a list of default commands and their arguments I don't see why they should be restricted just to be useful. As for a ZMP "byte tax", I don't see how it can possibly be considered onerous. Let's compare:

IAC SB MSDP 1 "HP" 2 "100" 1 "FP" 2 "100" 1 "PP" 2 "100" IAC SE - 21 bytes inside the sub.
IAC SB ZMP zmp.prompt | 100 | 100 | 100 | IAC SE - 23 bytes, inside the sub. In addition, there is little chance of collision with other variables or prompts that might use HP, FP, or PP as names. I'll pay the 2 byte tax. It's not a big deal. Besides, if you had to do max\current values (which you'd need to draw a gauge) MSDP becomes more verbose than ZMP at that point.



If you're worried about bandwidth on the server side, don't enable it, just like those who worry enable MCCP. Those few extra bytes could mean the difference between a richer visual display, which could allow you to introduce more complex gameplay since conveying information is easier, and a plain MUD.

I'll be completely honest, I don't give a rat's A if anything like this is backported to existing codebases. They are what they are, and whats available has worked just fine for them. I see this as a compelling option for any codebases made to take advantage of it from the get-go. David is looking at it for that reason (I think) and so are elanthis and I. While it would be cool if older codebases could at least enable prompt (gauge and roundtime) widgets, compasses and the like, I see that as the least of what ZMP has to offer.

Tactical row (or any other kind of tactical up to the minute) displays, map displays, inventory, quest logging, image maps, party info, target info, and any number of other things someone will think of - those are more interesting and can drastically help people absorb information and enjoy themselves more.
13 Mar, 2009, elanthis wrote in the 94th comment:
Votes: 0
Scandum said:
You'd still have the same problems, zmp sounds nice in theory, but it's a swiss army knife when all you need is a fork and a spoon. You'd have an extra 15 byte overhead per variable, so you'll be dealing with more wrapping than data. Especially for large muds that's just not feasible when you have to transfer a complex interface to potentially over a hundred players, and as has been pointed out, even for languages that can deal with NULs it is often still a pain in the ass.


I live in one of the most heavily lagging countries for broadband penetration and yet I get 8MBPS down for $25/mo. I can stream HD-quality movies in real time without a hitch. I really, really, REALLY don't care about an extra 15 bytes here and there. Especially if you just enable MCCP2.

Nobody has proven that it's a pain in the ass to deal with NULs in languages that can deal with it – quite the contrary. In most script languages it would be as easy as args = buffer.split('\0'). Tada! I've implemented ZMP in four different script languages without any difficulties at all. Implementing HTTP (a line-based protocol, no NULs) was harder to do than ZMP, and HTTP is easy!

I really would change the NUL byte thing if it would honestly make things easier for some of you (I still think you're just blowing smoke, though), but the ZMP core spec has been published for a very long time (first release was June 12th, 2003) and it is, at this point, very much a done deal. We're talking about the packages specifically because there are already MUDs and clients that have managed to implement it just fine, and at this point it is those packages and not the protocol that is lacking.
13 Mar, 2009, elanthis wrote in the 95th comment:
Votes: 0
Tyche said:
If the negotiation seems tedious, perhaps instead of playing guess the command with a series of zmp.check's, an optional inversion of the negotiation mechanism might be better.


That's a clear possibility. I'd just note that sending all the supported commands as arguments of a single response command might not be the best idea, especially for C implementations where it's far more likely that a fixed-size argv array is in use (because dynamically allocating and growing arrays in C is a pain in the butt).

I do still need to update the spec with your recommendations about minimum limits. (I believe you mentioned the idea of negotiating limits, but that still seems WAY too complex to me.) A minimum 8KB buffer size and a minimum 16 arguments (including command name itself) seems more than sufficient to me. Thoughts?
13 Mar, 2009, Vassi wrote in the 96th comment:
Votes: 0
elanthis said:
That's a clear possibility. I'd just note that sending all the supported commands as arguments of a single response command might not be the best idea, especially for C implementations where it's far more likely that a fixed-size argv array is in use (because dynamically allocating and growing arrays in C is a pain in the butt).

I do still need to update the spec with your recommendations about minimum limits. (I believe you mentioned the idea of negotiating limits, but that still seems WAY too complex to me.) A minimum 8KB buffer size and a minimum 16 arguments (including command name itself) seems more than sufficient to me. Thoughts?


Do you mean maximum 16 arguments?

I don't think any of that should be an issue. 8kb seems more than generous. I've been meaning to ask this for a while now, too, but how do we feel about optional arguments at the end of required arguments?

Purely for illustrative purposes, for instance, I could setup a subwindow with the following arguments: "chat 100, 100" or "chat 100, 100, no-close" or "chat, 100, 100, no-close, input" with the presence of no-close and input meaning "true" but their lack meaning "false'. It's not strictly necessary, of course, but it seems cleaner than having a string of "false"s. (Again, I'm just using the example, I'm not trying to argue for extra settings on subwindows)
13 Mar, 2009, elanthis wrote in the 97th comment:
Votes: 0
Vassi said:
Do you mean maximum 16 arguments?


I mean that an implementation must be able to accept at least 16 arguments. So in turn a command should use only a maximum of 16 arguments, as you put it. :) (Again, that includes the command name.)

Quote
I've been meaning to ask this for a while now, too, but how do we feel about optional arguments at the end of required arguments?


There is nothing fundamentally wrong with them from my perspective. If your command makes use of a large number of optional arguments, I might suggest either splitting it into multiple commands, simplifying the command's behavior, or (if you really really need it the way it is) consider "naming" the parameters by passing one or more arguments of the form "name:value". I really don't recommend going that last route though unless you're doing something really off the wall; a complex GUI package might just necessitate that, or even necessitate sending XML or JSON in one of the argument, I suppose. 99% of commands shouldn't need anything like that, I think.
13 Mar, 2009, Scandum wrote in the 98th comment:
Votes: 0
Tyche said:
If the negotiation seems tedious, perhaps instead of playing guess the command with a series of zmp.check's, an optional inversion of the negotiation mechanism might be better.

It'd be an improvement, but subsequently more bloat and more hassle to support zmp.


Vassi said:
ZMP is too strictly defined…so let's define a strict list of variables? -blink- Huh?

MSSP needs a strict list of variables to work. MSDP wouldn't, but it'd be helpful for cross server interface implementations.

Vassi said:
IAC SB MSDP 1 "HP" 2 "100" 1 "FP" 2 "100" 1 "PP" 2 "100" IAC SE - 21 bytes inside the sub.
IAC SB ZMP zmp.prompt | 100 | 100 | 100 | IAC SE - 23 bytes, inside the sub.

MSDP would allow: IAC SB MSDP 1 "PROMPT" 2 "100" 2 "100" 2 "100" IAC SE

However, if a HP FP PP approach was to be used, the server could remember the last submitted values, and if HP and FP remain the same, it could simply send: IAC SB MSSDP 1 "PP" 2 "100" IAC SE and the client would assume it should just reprint the previously reported values for HP and FP. This way a very complex interface could be send over with minimal bandwidth usage.

ZMP due its setup would better work as a master than a slave protocol that strictly defines how things are displayed, like VT100 does.
13 Mar, 2009, elanthis wrote in the 99th comment:
Votes: 0
(I wonder when the point for splitting these into separate threads has been reached…)

Somebody above asked about authentication with ZMP, and after posting on the MSSP thread about the MUDs using SSH, I thought: why not make a SASL package for ZMP?

Anyone interested in using such a package? A package with five commands should cover it: sasl.advertise (advertise SASL methods), sasl.select (begin a SASL method), sasl.challenge (server challenge), sasl.response (client response), and sasl.result (server result code: success or failure).
13 Mar, 2009, elanthis wrote in the 100th comment:
Votes: 0
Quote
ZMP due its setup would better work as a master than a slave protocol that strictly defines how things are displayed, like VT100 does.


You weren't much for critical thinking problems in grade school, were you?

Give me one reason why ZMP forces you to do anything differently than what you just proposed for MDSP?

"prompt.var" "100" "100" "100" (positional vars if you want to force the status types down players' throats)
"prompt.var" "" "" "100" (defaulted positional vars)
"prompt.var" "hp" "100" "fp" "100" "mp" "100" (named vars)
"prompt.var" "fp" "100" (omitted named vars)

Whatever you want.

I would just use one command per variable. Simpler to implement, the bandwidth *does not matter*, and has the exact same result. Possibly more of a result, because you might want to do something more complex:

"prompt.bar" "HP" "50" "1000" // display a percentage-filled bar-style prompt indicator, with the given current and maximum values
"prompt.bar" "MP" "10" "15" // same as above
"prompt.set" "Gold" "5456" // just display the value with no percentage or maximum
"prompt.pie" "Round" "7" "10" // display a percentage-filled pie-style prompt indicator, like cooldown timers in many modern games, very user friendly for time-based values

Seriously, there is NOTHING that MSDP possibly allows that ZMP does not. You are on pure crack.
80.0/108