07 Jul, 2011, Scandum wrote in the 1st comment:
Votes: 0
I was thinkering with the concept of sending MSDP data over GMCP. ATCP isn't a good alternative as it doesn't support nesting or arrays.

I think server side easiest is to have the server listen for a single MSDP module. So to have variables reported the client would send:

IAC SB GMCP 'MSDP { "REPORT" : "HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX" }' IAC SE

The server would translate this to MSDP data (which is fairly straightforward) and process it as is.

In response the server can either send a single MSDP module, or break down each variable into a module of its own. The downside of using a single module is that clients won't generate events for the nested variables, and users will have to copy the data to a safe location. It would look like:

IAC SB GMCP 'MSDP { "HEALTH" : "10", "HEALTH_MAX" : "30", "MANA" : "17", "MANA_MAX" : "42" }' IAC SE

While less efficient, the other alternative is sending each variable as it's own module, which would look like:

IAC SB GMCP 'MSDP.HEALTH "10"' IAC SE
IAC SB GMCP 'MSDP.HEALTH_MAX "30"' IAC SE
IAC SB GMCP 'MSDP.MANA "17"' IAC SE
IAC SB GMCP 'MSDP.MANA_MAX "42"' IAC SE

The second approach is probably the way to go as MCCP should compress most of the overhead.

Internally, it would be an option to use JSON, and have this translated to either MSDP or GMCP. This would fix readability issues, though not by a whole lot, and escaping problems would be introduced. For people who don't care (you can write MSDP arguments in octal notation) it's about as involved to translate MSDP to GMCP.

Feedback and suggestions welcome.
07 Jul, 2011, Twisol wrote in the 2nd comment:
Votes: 0
I notice you wrap the GMCP subnegotiation data in single quotes. Are those meant to be there, or are you just notating that the content is literal text (unlike IAC, SB, etc.)?

Also, you're sending a message that's not in a package ("MDSP"). According to the closest thing we have to a spec, a message needs to conform to Package[.SubPackages].Message. That makes it possible to have pluggable components that the core GMCP handler can divert whole packages to. I'd suggest something more like the following:

IAC SB GMCP MDSP.Report ["HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX"] IAC SE
IAC SB GMCP MDSP.Values {"HEALTH": "10", "HEALTH_MAX": "30", "MANA": "17", "MANA_MAX", "42"} IAC SE

I'm not sure I see a need for the "expanded" form you suggest. If I were writing an MDSP module in MUSHclient I could just iterate over the items in the JSON object and emit an event for each one.
07 Jul, 2011, KaVir wrote in the 3rd comment:
Votes: 0
Scandum said:
I was thinkering with the concept of sending MSDP data over GMCP. ATCP isn't a good alternative as it doesn't support nesting or arrays.

ATCP can support whatever you like, it's just not an explicit part of the specification. It's up to you to define your own packages, but that's exactly what you'd be doing in this case anyway.

On the other hand, GMCP is supposed to use JSON, which means you couldn't just sent your MSDP data as a GMCP package - you'd have to change the format as well.

PHudBase supports ATCP but not GMCP. Mudlet supports both, but ATCP is enabled by default while GMCP has to be manually switched on. I don't know of any clients that support GMCP and not ATCP.

Also, my snippet uses ATCP as a fallback option for clients that don't support MSDP, so there are already about a dozen muds that send MSDP data over ATCP.
08 Jul, 2011, Scandum wrote in the 4th comment:
Votes: 0
Twisol said:
I notice you wrap the GMCP subnegotiation data in single quotes. Are those meant to be there, or are you just notating that the content is literal text (unlike IAC, SB, etc.)?

Just to note it's literal text.

Twisol said:
Also, you're sending a message that's not in a package ("MDSP"). According to the closest thing we have to a spec, a message needs to conform to Package[.SubPackages].Message. That makes it possible to have pluggable components that the core GMCP handler can divert whole packages to. I'd suggest something more like the following:

IAC SB GMCP MDSP.Report ["HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX"] IAC SE
IAC SB GMCP MDSP.Values {"HEALTH": "10", "HEALTH_MAX": "30", "MANA": "17", "MANA_MAX", "42"} IAC SE

It's MSDP, not MDSP. That's not compatible with MSDP notation however as you're defining a JSON array while the MSDP REPORT uses a method that's closer (easiest to illustrate in C) to: int c = 10 = 12 = 14;

Twisol said:
I'm not sure I see a need for the "expanded" form you suggest. If I were writing an MDSP module in MUSHclient I could just iterate over the items in the JSON object and emit an event for each one.


I guess someone could just as easily parse unmodified MSDP in that case, with less trouble, as it's linear, typeless, and doesn't need to be escaped. The biggest downside is readability.

KaVir said:
ATCP can support whatever you like, it's just not an explicit part of the specification. It's up to you to define your own packages, but that's exactly what you'd be doing in this case anyway.

In that case I'd rather send the data unmodified in bulk and require a client side MSDP parser.

KaVir said:
On the other hand, GMCP is supposed to use JSON, which means you couldn't just sent your MSDP data as a GMCP package - you'd have to change the format as well.

The idea would be to translate MSDP to GMCP, which with the latest update to the MSDP specification is relatively easy. The big downside is added complexity.

KaVir said:
PHudBase supports ATCP but not GMCP. Mudlet supports both, but ATCP is enabled by default while GMCP has to be manually switched on. I don't know of any clients that support GMCP and not ATCP.

Never heard of PHudBase.

KaVir said:
Also, my snippet uses ATCP as a fallback option for clients that don't support MSDP, so there are already about a dozen muds that send MSDP data over ATCP.

There are various ways to go about it however, and unlike when using GMCP your method won't work out of the box as ATCP doesn't support arrays and tables. You'd be forced to either send simple data, create a custom more primitive data format, or send full blown MSDP which would require a relatively complex parser.
08 Jul, 2011, Twisol wrote in the 5th comment:
Votes: 0
Scandum said:
It's MSDP, not MDSP. That's not compatible with MSDP notation however as you're defining a JSON array while the MSDP REPORT uses a method that's closer (easiest to illustrate in C) to: int c = 10 = 12 = 14;

The original thing you pasted isn't JSON at all though:
IAC SB GMCP 'MSDP { "REPORT" :  "HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX" }' IAC SE
It looks like a list of strings, which is exactly what I translated it to.
08 Jul, 2011, Scandum wrote in the 6th comment:
Votes: 0
Twisol said:
Scandum said:
It's MSDP, not MDSP. That's not compatible with MSDP notation however as you're defining a JSON array while the MSDP REPORT uses a method that's closer (easiest to illustrate in C) to: int c = 10 = 12 = 14;

The original thing you pasted isn't JSON at all though:
IAC SB GMCP 'MSDP { "REPORT" :  "HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX" }' IAC SE
It looks like a list of strings, which is exactly what I translated it to.

It's valid JSON as far as I can tell, and if parsed correctly should result in REPORT being set to MANA_MAX. An MSDP parser would treat each item as a command, and raise an event for each while parsing. Were an array to be used the parser would capture the full array before raising an event.

Having given it some more thought I'm kind of iffy about supporting clients that refuse to implement a generic telnet handler or an msdp handler, especially as ATCP support might be dropped the second IRE drops it.
08 Jul, 2011, KaVir wrote in the 7th comment:
Votes: 0
Scandum said:
Having given it some more thought I'm kind of iffy about supporting clients that refuse to implement a generic telnet handler or an msdp handler, especially as ATCP support might be dropped the second IRE drops it.

There are now 14 muds that support MSDP, with (I believe) 11 of them using the ATCP fallback option, so I'd be surprised to see ATCP dropped (unless the client already supports both GMCP and MSDP). As far as I'm aware Mudlet has no plans to drop ATCP, and Heiko has actually been extending ATCP s... so that Mudlet users connecting to my mud will automatically install my GUI.

Once Realms of Despair goes live with my snippet installed, it'll further cement the legitimacy of the two protocols. Not only is it one of the biggest muds around, it's also another of the games recommended by Mudlet, and some of the RoD staff have already expressed an interest in offering a custom Mudlet GUI. As the SMAUG flagship, I believe it'll also draw more attention to the snippet from other muds.

Kind of ironic that ATCP is becoming more generic than GMCP.
09 Jul, 2011, Twisol wrote in the 8th comment:
Votes: 0
Scandum said:
It's valid JSON as far as I can tell, and if parsed correctly should result in REPORT being set to MANA_MAX.

That is incorrect. JSON has two composite types: objects and arrays. An object is defined with { and }, and it contains "key": value pairs: {"k1": 42, "k2": 100}. An array is defined with [], and contains only values: ["el1", "el2", 600]. What you have is neither of these.
09 Jul, 2011, Scandum wrote in the 9th comment:
Votes: 0
Twisol said:
Scandum said:
It's valid JSON as far as I can tell, and if parsed correctly should result in REPORT being set to MANA_MAX.

That is incorrect. JSON has two composite types: objects and arrays. An object is defined with { and }, and it contains "key": value pairs: {"k1": 42, "k2": 100}. An array is defined with [], and contains only values: ["el1", "el2", 600]. What you have is neither of these.

Not quite, according to RFC 4627: A JSON parser transforms a JSON text into another representation. A JSON parser MUST accept all texts that conform to the JSON grammar. A JSON parser MAY accept non-JSON forms or extensions.

There's nothing in the RFC forbidding redefinitions of values. It's pointless in most cases, unless events are being raised as the definition happens.


KaVir said:
Once Realms of Despair goes live with my snippet installed, it'll further cement the legitimacy of the two protocols. Not only is it one of the biggest muds around, it's also another of the games recommended by Mudlet, and some of the RoD staff have already expressed an interest in offering a custom Mudlet GUI. As the SMAUG flagship, I believe it'll also draw more attention to the snippet from other muds.

That may indeed improve the situation.
09 Jul, 2011, Twisol wrote in the 10th comment:
Votes: 0
From the official JSON website:



It's entirely syntactically invalid. If you don't understand that by now, there's nothing else I can do here.
09 Jul, 2011, Runter wrote in the 11th comment:
Votes: 0
Not valid json. Out of curiosity, what do you think this supposed json will represent once parsed?
09 Jul, 2011, Scandum wrote in the 12th comment:
Votes: 0
Twisol said:
It's entirely syntactically invalid. If you don't understand that by now, there's nothing else I can do here.

Reading back that should have been:
IAC SB GMCP 'MSDP { "REPORT" :  "HEALTH" : "HEALTH_MAX" : "MANA" : "MANA_MAX" }' IAC SE

I wouldn't call that entirely syntactically invalid, but definitely not proper JSON. GMCP isn't proper JSON either so I'm not too concerned when it comes to that.

While at it, does anyone have suggestions for making the following code more human readable without switching to something like JSON?

if (ch->desc->msdp_data)
{
char exits[MAX_INPUT_LENGTH];
int exit;

sprintf(exits, "%c", MSDP_OPEN);

for (exit = 0 ; exit < 6 ; exit++)
{
if (is_valid_exit(ch, ch->in_room, exit))
{
cat_sprintf(exits, "\001%s\002%d", dir_name_short[exit], ch->in_room->exit[exit]->to_room);
}
}
cat_sprintf(exits, "%c", MSDP_CLOSE);

msdp_update_var_instant(ch->desc, "ROOM", "%c\001%s\002%d\001%s\002%s\001%s\002%s\001%s\002%s\001%s\002%s%c",
MSDP_OPEN,
"VNUM", ch->in_room->vnum,
"NAME", ch->in_room->name,
"AREA", ch->in_room->area->name,
"TERRAIN", sector_table[ch->in_room->sector_type].sector_name,
"EXITS", exits,
MSDP_CLOSE);

}

\001 is the octal value to indicate the start of an msdp variable, and \002 for the start of an msdp value.
09 Jul, 2011, Twisol wrote in the 13th comment:
Votes: 0
Scandum said:
GMCP isn't proper JSON either so I'm not too concerned when it comes to that.

The only place it departs from JSON is where it doesn't require an object or an array as the root value. Most parsers I've used support that extension, and it's trivial to work around where it's not (wrap in [], parse, get the 0th element).

Your extension, however, severely departs from both syntax and semantics, and I don't understand your goal. What does your abomination do that arrays don't? …What is your abomination even supposed to do, anyways? I can't make heads or tails of it.

Scandum said:
While at it, does anyone have suggestions for making the following code more human readable without switching to something like JSON?

It seems pretty readable. What issue do you have with it?
09 Jul, 2011, Runter wrote in the 14th comment:
Votes: 0
Is this the json it's supposed to represent?

{ "REPORT" :  ["HEALTH" , "HEALTH_MAX" , "MANA" , "MANA_MAX"] }
09 Jul, 2011, kiasyn wrote in the 15th comment:
Votes: 0
when i code in my spare time i like to
import 'json'
instead of spend an hour parsing some stupid text that i dont care much about.
09 Jul, 2011, Scandum wrote in the 16th comment:
Votes: 0
Twisol said:
Your extension, however, severely departs from both syntax and semantics, and I don't understand your goal.

The goal is to mimic MSDP behavior. I could specifically require MSDP to use an array, but that'd break KaVir's implementation.

If one was to put it in valid JSON (also valid for MSDP) one would use:

{ "REPORT" :  "HEALTH", "REPORT" : "HEALTH_MAX" , "REPORT" : "MANA" , "REPORT" : "MANA_MAX" }



Twisol said:
It seems pretty readable. What issue do you have with it?

Particularly when I use \003 and \004 for OBJECT_OPEN and OBJECT_CLOSE it's tricky to see the opening and closing of nests. \005 and \006 are ARRAY_OPEN and ARRAY_CLOSE, more examples:

descriptor_printf(d, "\001%s\002\003\001%s\002%s\001%s\002%s\001%s\002%s\004", "NESTED_ARRAYS", "A", "\005\002111\002222\002333\006", "B", "\005\002444\002555\002666\006", "C", "\005\002777\002888\002999\006");

descriptor_printf(d, "\001%s\002\005\002%s\002%s\002%s\006", "ARRAYED_ARRAYS", "\005\002A\002B\002C\006", "\005\002D\002E\002F\006", "\005\002G\002H\002I\006");
09 Jul, 2011, Twisol wrote in the 17th comment:
Votes: 0
Scandum said:
The goal is to mimic MSDP behavior. I could specifically require MSDP to use an array, but that'd break KaVir's implementation.

The thing is, GMCP requires its content to be valid JSON. You have to use valid JSON. If you have to pass raw MSDP data through GMCP you can pass it as a string, thus tunneling MSDP through GMCP.

Scandum said:
If one was to put it in valid JSON (also valid for MSDP) one would use:

{ "REPORT" :  "HEALTH", "REPORT" : "HEALTH_MAX" , "REPORT" : "MANA" , "REPORT" : "MANA_MAX" }

Every JSON parser I've used deserializes that to {"REPORT" => "MANA_MAX"}, meaning you lose the earlier definitions of "REPORT". It's allowed according to the JSON RFC, but it says you "SHOULDN'T" do it.

If you're planning on writing a custom parser that emits events as it traverses the JSON document - like SAX does for XML - then you're not going to have much adoption. By and large, JSON parsers completely deserialize the data and return the finished product. While a SAX-style parser is possible, it basically makes GMCP much more difficult to handle. For example, my GMCP plugin for MUSHclient receives a message, deserializes the content, and emits an event for a message. JSON is an implementation detail, and I emit the native analog. Requiring a SAX-style parser would mean I can no longer provide the same unified interface.

I still believe what you really want is this:
MSDP.Report ["HEALTH", "HEALTH_MAX", "MANA", "MANA_MAX"]

Or if you'd rather tunnel instead of transpose:
MSDP.Report "normal MSDP goes here, though you'd better use a JSON library so it can escape anything that needs to be escaped."

The latter approach has the benefit of letting you pass the data straight to an already-existing MSDP parser

Scandum said:
Particularly when I use \003 and \004 for OBJECT_OPEN and OBJECT_CLOSE it's tricky to see the opening and closing of nests. \005 and \006 are ARRAY_OPEN and ARRAY_CLOSE

Use compile-time string concatenation. If you have two bare strings next to eachother - "lol" "wat" - the compiler knows to turn that into "lolwat".
#define OBJECT_OPEN "\003"
#define OBJECT_CLOSE "\004"
#define ARRAY_OPEN "\005"
#define ARRAY_CLOSE "\006"

descriptor_printf(d,
"\001%s\002"
OBJECT_OPEN
"\001%s\002%s\001%s\002%s\001%s\002%s"
OBJECT_CLOSE,
"NESTED_ARRAYS",
"A", ARRAY_OPEN "\002111\002222\002333" ARRAY_CLOSE,
"B", ARRAY_OPEN "\002444\002555\002666" ARRAY_CLOSE,
"C", ARRAY_OPEN "\002777\002888\002999" ARRAY_CLOSE
);
09 Jul, 2011, Scandum wrote in the 18th comment:
Votes: 0
Twisol said:
The thing is, GMCP requires its content to be valid JSON. You have to use valid JSON. If you have to pass raw MSDP data through GMCP you can pass it as a string, thus tunneling MSDP through GMCP.

This would only be from client to server, I've modified the MSDP specification to have servers use array notation when sending lists to a client.

Twisol said:
If you're planning on writing a custom parser that emits events as it traverses the JSON document - like SAX does for XML - then you're not going to have much adoption.

The parser (server side) would translate GMCP to MSDP, then send it through the MSDP parser.

Twisol said:
MSDP.Report "normal MSDP goes here, though you'd better use a JSON library so it can escape anything that needs to be escaped."

The latter approach has the benefit of letting you pass the data straight to an already-existing MSDP parser

I guess ATCP remains the easiest alternative in that case as you only need to avoid newlines.

Twisol said:
Use compile-time string concatenation.

That's definitely an improvement. I'll keep that in mind.
09 Jul, 2011, Twisol wrote in the 19th comment:
Votes: 0
Scandum said:
This would only be from client to server, I've modified the MSDP specification to have servers use array notation when sending lists to a client.

I still don't understand - this just limits adoption on the server side instead of the client side. The same exact mechanism I described applies to handling GMCP on the server, and it's easier to use an existing JSON library than to roll your own or use another mechanism based simply on what the message is.

Scandum said:
I guess ATCP remains the easiest alternative in that case as you only need to avoid newlines.

The easiest approach is to stick with what you have now: MSDP as its own protocol. If you're going to shoehorn one protocol into another it's not going to go very well for you. GMCP has different expectations, and you need to respect them.
09 Jul, 2011, Scandum wrote in the 20th comment:
Votes: 0
I'm not trying to create a protocol here, I'm working on an actual implementation. Even in the case of ATCP it's still a bit of a hack job to tunnel MSDP data through it.

Probably wisest to go for the cleanest possible implementation and avoid ending up with a game of trivia for all the parties involved.
0.0/24