Is GMCP still a thing?

Posted by Xinefus on Tue 28 Apr 2020 02:26 PM — 93 posts, 323,823 views.

#0
Ref: a. https://www.gammon.com.au/gmcp
b. http://www.aardwolf.com/wiki/index.php/Clients/MushclientGMCP

Good day everyone,

I'm getting very involved in some interesting things with respect to my most recent MUD adventures. Latest thing is I have found out that GCMP (and others) exists. How exactly does one implement this into their SMAUG?

If I'm the coder, what exactly would I be doing to get data flowing within these little GCMP 'tunnels/channels' and then what would I need to do on the client side (MUSH) to get it to be used?

I've looked at the Aardwolf client stuff a bit, and is there a way for me to implement this on a mud if it currently doesn't have GCMP on it.

I believe this is a huge endeavour, but hey there are times to sit back, and there are times to start digging in code, right? (I'm also just sitting at home lately and have some time to burn...).

Thank you again for your support!
USA Global Moderator #1
Quote:
I believe this is a huge endeavour

Honestly, it shouldn't be.

Quote:
If I'm the coder, what exactly would I be doing to get data flowing within these little GCMP 'tunnels/channels'

Very little. Negotiation of capability at connection startup aside, the basic nutshell is that instead of just sending text to the player, you name the kind of data that you're sending, then assemble a json object (see https://json.org), and then put the bytes 0xFF 0xFA 0xC9 at the front and the bytes 0xFF 0xF0 at the end before sending it.

Like if you want to send the character name and level, you could send

"\xFF\xFA\xC9Char.SomeStuff {\"name\": \"Albus\", \"level\": 20}\xFF\xF0"


Aside from the "Core" messages, I don't think there was ever agreement on what the standard names or json collections should be, so you can kinda do whatever you want with those.

Beyond that, the IAC WILL/WONT/DO/DONT/Supports negotiation stuff is just so that you can decide whether it's worth your bandwidth to bother sending certain details if the player's client doesn't indicate support for them. Honestly with bandwidth and stream compression being what they are these days, I don't think that part is very important and you can just send everything to everyone. The first and last bytes already protect non-GMCP clients from doing anything with those messages anyway.
Amended on Tue 28 Apr 2020 03:37 PM by Fiendish
#2
Thanks Fiendish! You are being optimistic and I like that.

This 'project' is a bit outside of my comfort zone as I don't quite understand all the coding aspects of it.

If we were to start really small: I want to implement just hp/sp. Can you walk me through how this would be implemented server-side?

I just need a start, and then I will hopefully be able to extrapolate for other mudstats.

Room info, object info.. stuff like that...

I know you said it shouldn't be a big problem, it's just a bit outside what I know!
USA Global Moderator #3
Quote:
Thanks Fiendish! You are being optimistic and I like that.

Honestly, for most programming, knowing what to do at a logical level based on practice thinking like a computer is much more difficult than knowing how to write the instruction syntax. The latter is just translation. So you don't need to understand all the coding aspects as long as we can get you to understand the philosophy.


For your benefit I'd like to approach this conversationally. It will take slightly longer but I think it will be worthwhile.

Let's start by asking how you would send a message to the player. Any message at all. Like "hello <playername>" for instance.
Amended on Tue 28 Apr 2020 05:21 PM by Fiendish
#4
Alright,

so in game, if the person is in the same room as me, I would send a say command.

So I would input:

say hello!

In the output I would see:

You say 'Hello!'
<prompt>

Prompt being whatever it is that I make it. hp/sp, or a few other limited tokens.

Is that what you were looking for?

I've been reading this: http://www.gammon.com.au/forum/?id=10043

But I just need to understand it a bit more.. Maybe I just need to read the whole thread from start to finish!
Amended on Tue 28 Apr 2020 05:23 PM by Xinefus
USA Global Moderator #5
That's definitely one perspective of how to send a message. But how does the server do it if the server wants to send you a message? Say for instance that the server wants to send you your prompt. At the very last step, after it has assembled the content of your prompt together from your stats, how does it finally transmit that information to you? Is there a function in the SMAUG code that does "send this message to player"?
Amended on Tue 28 Apr 2020 05:25 PM by Fiendish
#6
Sorry, you can tell I'm a bit on the flustered side of things.

I need to examine more of the mud files to actually get you that information, I don't have full access to everything with respect to the mud at this moment. I'm trying to get a testport created so that I don't break anything in the meantime.

Give me some time to collect an answer for you. Then I will come back and hopefully have more to give.
USA Global Moderator #7
Yup, no worries.
#8
Ok, so I'm going to get the trusty homelab running..

Let's do this from scratch and then I can understand it.

Similar to the codebase I want to use is LOP 1.46.

In the act_comm.c there is this:


act( AT_SAY, "$n says ' $t &D'", ch, sbuf, vch, TO_VICT );
      if( !is_npc( vch ) )
      {
         snprintf( buf, sizeof( buf ), "&[say]%s said ' %s &D&[say]'", capitalize( is_npc( ch ) ? ch->short_descr : ch->name ), sbuf );
         add_phistory( 1, vch, buf );


Is this what you are looking for?
USA Global Moderator #9
Is LOP the codebase you want to use or is it one more familiar to you?
#10
This is the one that is most similar to the one I am helping out with this.

I am familiar with it the most, yes. If familiar is a good way to put it.
USA Global Moderator #11
Ok great. So you're close but not quite right, but we can get to the right place from there. In LOP in the file you mentioned, you pointed to the line that says
act( blah blah blah )


That use of "act" with the parentheses and stuff is a call to a function defined in comm.c. It's the line that starts "void act". Looks like line 3378 in that file. In _that_ function is some more stuff, most of which you don't care about, but peppered throughout that function are some more function calls to things like "ch_printf" and "send_to_char". "send_to_char" definitely sounds promising and ch_printf probably stands for something like "print out this message to the character". Now those functions are defined in color.c. Do you see those functions in color.c?
Amended on Tue 28 Apr 2020 09:58 PM by Fiendish
USA Global Moderator #12
Now from there you should see that ch_printf itself calls send_to_char, so maybe we can ignore it. And from there you should see that send_to_char in turn calls send_to_desc, and that send_to_desc calls write_to_buffer with some colorization (which we don't care about). Now write_to_buffer is defined back in comm.c. Do you see write_to_buffer? At this point nothing else is being called, so that makes it our stopping point. I believe that write_to_buffer with the appropriate inputs will send a message to a client. Does your inspection of the code agree with that? Does it make sense based on how it's used elsewhere?
Amended on Tue 28 Apr 2020 09:57 PM by Fiendish
Australia Forum Administrator #13
I would look for an existing message, for example, from comm.c:


     if( sysdata.wizlock && !IS_IMMORTAL( ch ) )
      {
         write_to_buffer( d, "The game is wizlocked. Only immortals can connect now.\r\n", 0 );
         write_to_buffer( d, "Please try back later.\r\n", 0 );
         close_socket( d, FALSE );
         return;
      }



Basically the argument "d" there is the socket descriptor (the thing you write to). The descriptor is stored in the character data (ch->desc). So send_to_char extracts that for you:


void send_to_char( const char *txt, CHAR_DATA * ch )
{
   if( !ch )
   {
      bug( "%s: NULL ch!", __FUNCTION__ );
      return;
   }

   if( txt && ch->desc )
      send_to_desc_color( txt, ch->desc );
}


Usually in the code you know the character because that is what you are processing when a particular character is being processed.

ch_printf basically does a "printf" with the output sent to the descriptor.

Here are some examples:


skills.c:         ch_printf( ch, "Hitchar   : %s\r\n", skill->hit_char );
skills.c:         ch_printf( ch, "Hitvict   : %s\r\n", skill->hit_vict );
skills.c:         ch_printf( ch, "Hitroom   : %s\r\n", skill->hit_room );
skills.c:         ch_printf( ch, "Hitdest   : %s\r\n", skill->hit_dest );


So if you can show hit points like the above, then you can do what Fiendish suggested earlier and wrap the GMCP stuff around it.

I suggest reading up a bit on how to use "printf" to understand what you are looking at.

For example printf reference.
#14
I think I saw Alice on my way to write_to_buffer!

What is that stuff doing in color.c?? I suppose it wouldn't hurt to move it eventually... Another day another issue.


I was able to find the path you were tracking me down. Line 1236 of Comm.c

As my kids would say, are we there yet?

What I am able to get from that is write_to_buffer sets the string length and buffer size? defines copy..

but that certainly is the end of that chain.

Now we are at the very beginning?
Australia Forum Administrator #15
Levering off reply #1, something like this when the hitpoints change (or when you send a prompt, for example):



ch_printf (ch, "\xFF\xFA\xC9Char.Status {\"hp\": %d}\xFF\xF0", ch->hit);


Untested, but that would be the general idea.

For more readability, define those things in mud.h, eg.


#define IAC_SB_GMCP "\xFF\xFA\xC9"
#define IAC_SE "\xFF\xF0"


And then have your message look like this:



ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit);
Amended on Tue 28 Apr 2020 10:46 PM by Nick Gammon
#16
Ok, so I'm just wanting to confirm I'm on the right track.

Under player.c: line 1000


ch_printf( ch, "%sHP:    %s%d %sof %s%d\r\n", s1, s2, ch->hit, s1, s2, ch->max_hit );


This is what I can find that refers to HP. There is also one for mana, gold, and a list of stats, etc.

Is this where I should be starting to dig when I want to add the GMCP wrap?

And looking at Nick's last post:


ch_printf( ch, "\xFF\xFA\xC9Char.Status {\"%sHP:    %s%d %sof %s%d\r\n": %i}\xFF\xF0", s1, s2, ch->hit, s1, s2, ch->max_hit );


Char.Status being what would be used on a client side plugin as per #1 in http://www.gammon.com.au/forum/?id=10043.

I get pretty confused with all the diff namings, i think in the ref post it's tt vice Char.Status..

Am I going in the right direction?
Amended on Wed 29 Apr 2020 09:35 AM by Xinefus
Australia Forum Administrator #17
In the version of SMAUG I am looking at (which is probably different to yours) in the file comm.c there is a function "display_prompt".

This would appear to be a logical place to send character hitpoints via GMCP.


Quote:

Char.Status being what would be used on a client side plugin as per #1 in http://www.gammon.com.au/forum/?id=10043.

I get pretty confused with all the diff namings, i think in the ref post it's tt vice Char.Status..


Yes, well that post shows different ways of doing it. If you want to send:


hp=1234


Then you can. Then you make the client interpret that.

Or you can send it the JSON way:


Char.Status {"hp": 1234}


Now you make the client interpret that JSON string (which obviously isn't too hard, in that particular case). Using JSON has a bit more flexibility, if you want that, because you can add extra things, like mana, movement points, room number, etc. now or later if you want to.

For example:


Char.Status {"hp": 1234, "mana": 88, "move": 666, "room": 21000}
#18
Ok, so if I wanted to edit the prompt so that the client would receive hp JSON data through GMCP, I should start with the display_prompt?

This brings me around in a loop back to write_to_buffer..

But I don't know how to wrap a GMCP. I thought we were on a closer path when it came to the player data in my previous post?

Or do I need to add a line of

ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit); 


within the char display_prompt ?

Not saying exactly that, but something like that? for instance in display_prompt it shows

               case 'h':
                  pstat = ch->hit;
                  break;

               case 'H':
                  pstat = ch->max_hit;
                  break;


Would then the line I need to add at the bottom of display_prompt would be

ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %h, \"maxhp\": %H}" IAC_SE, ch->hit);


I think I'm starting to get this... maybe?
Amended on Wed 29 Apr 2020 09:36 AM by Xinefus
Australia Forum Administrator #19
Can you paste your whole (current) display_prompt function here, please, so we are both talking about the same thing?
Australia Forum Administrator #20
Quote:

But I don't know how to wrap a GCMP.


That was in the code I showed you. I don't understand what you mean when you say that.
Australia Forum Administrator #21

So we don’t confuse ourselves, and other readers, please refer to GMCP as that, and not start calling it GCMP, as you have done multiple times.

It’s “Generic MUD Communication Protocol”.

It isn’t “Generic Communication MUD Protocol”.

#22
So sorry about the acronym error. I really ought to know better. I'm in the military and we live for acronyms... I have updated my posts to reflect GMCP.

As for the comm.c default_prompt function ( I also said char default instead of void default in an earlier post, was reading the wrong line)

comm.c detault_prompt function:

Quote:

https://github.com/DBNU-Braska/GMCP-Learning/blob/master/comm.c.display_prompt
Amended on Wed 29 Apr 2020 10:14 AM by Xinefus
USA Global Moderator #23
Quote:
What is that stuff doing in color.c??

Interpreting inline color codes. The primary difference between send_to_desc and write_to_buffer is that send_to_desc first converts SMAUG color codes into a form that the client understands as colors.

Nick suggests using ch_printf because it lets you format your messages a particular comfortable way (if you know printf format). Just keep in mind that that will also interpret any color codes you include because it's higher in the chain than send_to_desc. If you don't want ampersands etc to get converted into colorized text in your GMCP messages, I think you'll need to bypass the colorization by calling write_to_buffer directly or do whatever SMAUG needs you to do to get them sent literally.
Amended on Wed 29 Apr 2020 02:41 PM by Fiendish
#24
Fiendish said:

I think you'll need to bypass the colorization by calling write_to_buffer directly or do whatever SMAUG needs you to do to get them sent literally.

There is no need for me to have the client get colour codes in this way. So you are suggesting that I use write_to_buffer instead of ch_printf? I'm just trying to see where to put this.

From the beginning, you read me before I even started asking questions! The logic is the important part - and this is where I have great difficulty.

i'm trying to track my way through the files so I can understand.

In write_to_buffer, it already has all the data from the prompt all packaged up. I'm not sure I know how something like hp would be written in or look like by this time. I can't follow it enough.
Amended on Wed 29 Apr 2020 06:14 PM by Xinefus
Australia Forum Administrator #25

If you don’t want ampersands etc to get converted into colorized text in your GMCP messages, I think you’ll need to bypass the colorization by calling write_to_buffer directly or do whatever SMAUG needs you to do to get them sent literally.

However there are no ampersands in:

Char.Status {"hp": 1234, "mana": 88, "move": 666, "room": 21000}

The last few lines of the function you linked are:

   }
   *pbuf = '\0';
   send_to_char( buf, ch );
}

So, you would output the GMCP stuff at the end:

   }
   *pbuf = '\0';
   send_to_char( buf, ch );
   ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit); 
}

Note that if they turn the prompt off, they wouldn’t get the GMCP either. You might want to find where display_prompt is called (there is an “if” test in front of it) and do the GMCP stuff there, regardless of whether they want the prompt or not.

However even doing it here should be enough for you to test it.


The reason I suggest doing it here or near where the prompt is displayed is because the prompt is usually updated when the HP changes, and that is what you are trying to send.

Amended on Wed 29 Apr 2020 08:40 PM by Nick Gammon
#26
Thank you Nick.


From reading up on GMCP on some of the other sites and reading some of the refs on your page about standards, it looks like I'm going to have to document a lot of this so I don't get mixed up the further I go.

I read in many places that things such as hp/sp/ep are Char.Vitals, whereas Char.Status is for stats such as int/dex/wealth/etc.

As you state in your guide, should I just take a standard and go with that? Is there one you recommend, more complete/less complete?

I am going to try and implement this, along with using the tools for MUSHclient you have written to see if I can't get something to work!

More to come, I'm sure.
USA Global Moderator #27
Quote:
However there are no ampersands in:
Char.Status {"hp": 1234, "mana": 88, "move": 666, "room": 21000}



Not in that, but the moment you decide to start sending more than just stats, things like room names and descriptions for easier script handling, then you're likely to start seeing some. So it's good to be aware of the differences between the different functions.
Amended on Wed 29 Apr 2020 10:54 PM by Fiendish
#28
You two are so good at this!

I am trying to read through the post: http://www.gammon.com.au/forum/bbshowpost.php?id=10043&page=9

It at least gives me some of the logic behind how this completely works.

I understand what

ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit); 

this means and how it works. But isn't there something I need to put before this to enable the telnet negotiations? I haven't got through the whole thread (as the link suggests) but I'm hoping it will outline a bit more on what other amendments I need to do to my codebase?

I did see on one of the pages some edits that @Nick made to a few of the files. I'm not sure I understand why all of them were made yet, and perhaps there will be more further on.

Thanks again for your support folks, I really appreciate this and am learning how to implement this.
USA Global Moderator #29
Xinefus said:

But isn't there something I need to put before this to enable the telnet negotiations?

Technically no. I'm pretty sure that negotiating activation is just a courtesy between the client and server. Any subnegotiation messages that you send that the client can't understand _should_ just be ignored. Though I guess I don't remember whether MUSHclient cares if you send it IAC SB 201 without ever first saying that you're going to be sending them.
Amended on Wed 29 Apr 2020 11:17 PM by Fiendish
#30
Ok, so I have confidently added the little snipped of code to comm.c and mud.h so that things should be sending GMCP data to the client.

I am trying to find any plugins here that I can adapt to see if it is working!

I downloaded the GMCP_handler_NJG plugin, and GMCP_message_receiver_test plugin.

I know that these are/were specific to other MUDs, but I had hoped to be able to understand it enough to implement.

I have been able to get my client to display

GMCP: Char.Status 

every time the prompt is refreshed... This is promising!

Now I just need to know how to get that JSON info turned into the actual hp! The info is definitely there..

Am I going in the right direction?
USA Global Moderator #31
If the message gets to the client and isn't immediately displayed but you can access it, then yes you're going the right direction.
#32
I have a strange suspicion that I am not getting quite what I'm looking for. In other words, I haven't set it up correctly to send me the right information.


*pbuf = '\0';
   send_to_char( buf, ch );
   ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit);  
   return;


The above is what I put at the end of display_prompt. Within display_prompt, the hp is stated as:

 case 'h':
                  pstat = ch->hit;
                  break;


It seems that ch_printf is given the right info, but i'm only getting


<38hp 106m 110mv> 
GMCP: Char.Status


from while using the above mentioned plugins. Without the plugins, nothing is seen.

How can I convert this Char.Status into the information that lays beneath? Essentially, how do I make it show 38?

Getting closer. :)
Australia Forum Administrator #33

I was about to suggest you do something like that. Yes, you are on the right track. When I tested by forcing through the packet by using the Game -> Test Trigger (Ctrl+Shift+F12) and entering:

\FF\FA\C9Char.Status {"hp": 42}\FF\F0

I got displayed, from the GMCP_handler_NJG plugin, and with gmcpdebug set to 2, the following:

Char.Status {"hp": 42}

Then I added the line of code you quoted into my SmaugFUSS comm.c file, compiled and tested. It also worked. In this case:

<24hp 145m 110mv> <#10300> 
Char.Status {"hp": 24}

You can see that it correctly showed the HP as being 24.

So, I don’t know what you have done. Did you copy and paste the exact code you put into the file? Did you get any compiler warnings?

Amended on Thu 30 Apr 2020 03:43 AM by Nick Gammon
#34
I got just what you did Nick!

If I were to read the GMCP_handler_NJG plugin notes correctly, I would know that there are more than just 0 and 1, but in fact 0,1,and 2 debug modes!

Alright, So the server is sending the correct information. The whole goal of this is to have it on a miniwindow such as all the examples here are so great at doing.

I have gone ahead and added this:

ch_printf (ch, IAC_SB_GMCP "Char.Status {\"cur_hp\": %d, \"max_hp\": %d, \"cur_mana\": %d, \"max_mana\": %d, \"cur_mv\": %d, \"max_mv\": %d}" IAC_SE, ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move, ch->max_move);


Ugly for now, I'll make it nice later...

But with that I was able to have the debug give me:

<38hp 106m 110mv> 
Char.Status {"cur_hp": 38, "max_hp": 38, "cur_mana": 106, "max_mana": 106, "cur_mv": 110, "max_mv": 110}


Now I'm having trouble understanding the Health_Bar_Miniwindow_Telnet. I have looked at reply 133 of http://www.gammon.com.au/forum/bbshowpost.php?id=10043 but I can't seem to find where the script is catching the information or it is missing some steps..
Amended on Thu 30 Apr 2020 09:28 AM by Xinefus
#35
As an aside, I have loaded smaugfuss194

https://smaugmuds.afkmods.com/files/smaugfuss-194-501/ 

Just to have the most up to date and bug free system. I've redone the changes and have the same results so far. Still investigating how to use the miniwindow plugins to capture that data.

Cheers,
Amended on Thu 30 Apr 2020 11:17 AM by Xinefus
Australia Forum Administrator #36
On this page is an example of handling the GMCP messages:

https://www.gammon.com.au/gmcp

The example plugin https://github.com/nickgammon/plugins/blob/master/GMCP_message_receiver_test.xml demonstrates how you might do it.

Basically, the plugin, which you installed, called GMCP_handler_NJG, detects the GMCP messages. It then does a BroadcastPlugin function call to send that message to any "listening" plugins.

GMCP_message_receiver_test is an example of such a plugin. It detects the message name (eg. "char.vitals") and then decodes the JSON which is the rest of the message into a Lua table.

It then calls a handler for that message type, for example for char.vitals:


function gotCharacterVitals (vitals)
  -- tprint (vitals)

 -- example:
 
  print ("HP is now:", tonumber (vitals.hp))
  
end  -- gotCharacterVitals


Now instead of doing a print, you could update a health bar.

That part would be like the standard health bar plugin, except getting the data from a trigger it gets it from the GMCP data.
#37
Thank you so much folks! Your help is setting me up to implement a whole lot of new tantalising features in my MUD!

I was having a bunch of problems with syntax, but I have successfully been able to get an infobox working with HP/SP!

I am still working on using a simple miniwindow perhaps as I want the ability to move them around..

I think there is the ability to just add that to an infobox? But I also want to learn how the miniwindows work in general so may go back to my other posts and get that going.
#38
Ok, I am trying to sit down and plan out my way forward so that I can make this project something manageable.

First I want to say that over the past couple weeks, I've been reading and searching the web - to the two main people that have helped me: I am so lucky to be able to get your help! Right now, to me, you are celebrities when it comes to MUD stuffs, server and client.

Thank YOU!

That aside, I am going to work towards having a similar concept to how Aardwolf modules. It seems fairly straight forward. ref: http://www.aardwolf.com/wiki/index.php/Clients/GMCP#aardmodules_room

What I am wondering, as I'm going to start with some char. modules, how would I go about efficiently putting the right lines of code into the codebase? Here for a start you've suggested in display_prompt, but in post 7 of
http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=10043
You have made a lot of other changes, e.g. show_status, fixup_lua_strings, want_telnet_info. I suppose to make GMCP work efficiently, there is a lot of optimisation that can be done; I don't think I'm in a position to do all that at this time.
I believe that most char. modules would be best positioned to be within display_prompt; would you suggest that victim/fighting be here as well?

I've also seen the use of snprintf(), whereas in this thread I have been suggested to use ch_printf() (essentially printf()). Is there a preference here?


Thanks again! Happy Friday/weekend.
USA Global Moderator #39
Quote:
I've also seen the use of snprintf(), whereas in this thread I have been suggested to use ch_printf() (essentially printf()). Is there a preference here?

printf and snprintf are part of a family of system-level functions in the C language that put data into a computer memory buffer. printf is for streams, sprintf is for character arrays, snprintf is like sprintf but safer because it won't write more bytes than you explicitly tell it to write (like if you're unsure how long your total text is and you don't want to overrun the finite space that has been preallocated for storing the result). Etc (there are more). They all use the same style of syntax with %-symbol format specifiers that are then replaced by the subsequent variable values according their meaning. We can call that style printf-family syntax.

ch_printf is a SMAUG function that uses printf-family syntax to send colorized messages to a character. ch_printf may use print/sprintf/snprintf internally, but is is not interchangeable with them.
Amended on Fri 01 May 2020 08:29 PM by Fiendish
#40
Ok, so I added that little bit of code the way that it was shown in my earlier post.

I got the strangest replies from a couple of the players... the ones using Gmud can actually see the text... Obviously from MUSHclient there was nothing to be seen, we tried Mudlet and nothing could be seen either. I didn't have access to c/zmud to test.

Is this something you know of? Is there a way to fix it?
Australia Forum Administrator #41
Yes, that is what the negotiation is all about. See: http://www.gammon.com.au/gmcp

The server should send (when connecting to the client, eg. after establishing the player name):


IAC WILL GMCP   (ie. 0xFF 0xFB 0xC9)


Then if you receive (sooner or later):


IAC DO GMCP    (ie. 0xFF 0xFD 0xC9)


Then you turn on a flag, which you use in your code to decide whether or not to send the GMCP messages. Obviously this flag has to be stored on a per-player basis, so it is part of the player struct (or possibly the descriptor struct).

And, if you receive:


IAC DONT GMCP  (ie. 0xFF 0xFE 0xC9)


Or, no response at all, then you set the flag to false (ie. that would be its default value) and don't send GMCP messages.
Amended on Sat 02 May 2020 05:06 AM by Nick Gammon
Australia Forum Administrator #42
You will need to add telnet negotiation code to the place where the server receives incoming data from the client, if it isn't there already. It might be.
USA Global Moderator #43
Quote:
the ones using Gmud

should change clients for their own good. Gmud is not compliant with the telnet specification. Nobody should use it. Gmud will just ignore your attempts to negotiate per KaVir's comment in this thread: http://www.mudbytes.net/forum/comment/51717/
Amended on Sat 02 May 2020 04:59 AM by Fiendish
Australia Forum Administrator #44
As per my suggestion though, if the client ignores the negotiation you can assume it doesn't support it. So you should really be waiting for "IAC DO GMCP" before sending GMCP stuff.
Australia Forum Administrator #45

One thing I encourage you to do is send the room number (vnum). This greatly improves the ability of the mapper to know where you are. Preferably also send known exits and where they lead. For example from https://www.ironrealms.com/gmcp-doc:

Room.Info {“num”: 12345, “name”: “On a hill”, “area”: “Barren hills”, “environment”: “Hills”, “coords”: “45,5,4,3”, “map”: “www.imperian.com/itex/maps/clientmap.php?map=45&level=3 5 4”, “exits”: { “n”: 12344, “se”: 12336 }, “details”: [ “shop”, “bank” ] }

This can be used to make the mapper work quite reliably. In particular the set_uid function can be used to tell the mapper which room you are in.

Amended on Sat 02 May 2020 05:27 AM by Nick Gammon
#46
Nick Gammon said:

As per my suggestion though, if the client ignores the negotiation you can assume it doesn't support it. So you should really be waiting for "IAC DO GMCP" before sending GMCP stuff.


This sounds like a plan that doesn't force a playerbase to do something they don't want to, even though they should!

I suppose I will go scouring the forum on how to implement this before I emerge in glorious defeat and come begging back here for more juicy knowledge.

Nick Gammon said:

One thing I encourage you to do is send the room number (vnum). This greatly improves the ability of the mapper to know where you are.


I certainly will be following all protocols and recommendations. I want this to enhance the playability, I dont want to move in the wrong direction!

Thank you again!
#47
As per what Nick has posted here: http://www.gammon.com.au/forum/?id=10043&reply=7#reply7.

Though this is one of the first posts done on brainstorming the gmcp protocol, is this still a valid way to implement the negotiation? I need to read it all to see if I understand everything it is doing. There are a few random edits that I'm not quite sure I get yet.

Checking if the ch is 'blind' is essentially what we are doing?
#48
Going through that bit of code changing I am wondering about the part about:

+char * fixup_lua_strings (const char * sce)


Is this a MUSH specific thing? If not implemented, does it cause issues? Or if it is, will it cause issues for other clients? Of course if you are aware.

I am certainly using MUSH and will be moving forward with using the wonderful plugins that gmcp can offer!
USA Global Moderator #49
That thread mixes a lot of things together. If all you want to do right now is discover whether the client accepts telnet subnegotiations, then most of that code is unrelated. Also it defines "MUD_SPECIFIC" as \x66 (102), but GMCP would be \xC9 (201), which means that that code predates GMCP.
Amended on Sat 02 May 2020 05:05 PM by Fiendish
#50
Yes, I realised that it was out of date.

From reading the gmcp page, I can see that I must get the GMCP telnet response added and get the server to ask for it from the client upon connection.

I haven't been able to find anything recent that helps to get that telnet negotiation in place.

I took at look at this thread: https://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=10189

But did not have any luck as I believe there is more to it than just those lines. It also would not compile in my version of SMAUGFUSS194 (as stated in an earlier post).


However, I do believe that it belongs within this space in the read_from_buffer similar to how MCCP is negotiated here (TELOPT_COMPRESS2)...


Should I create a new thread for this one, or is this still close enough to the same subject to keep going?
Amended on Sat 02 May 2020 07:25 PM by Xinefus
Australia Forum Administrator #51

The stuff in https://github.com/nickgammon/smaugfuss/blob/status_messages/src/comm.c seems to be relevant.

In particular, the read_from_buffer function, at line 1300 onwards. There is a state machine there that handles whether or not we are telnet negotiating.

#52
Thank you guys!

I gave this a shot.

First impression, I am getting an error when I login... For some reason the negotiation is not working correctly and I get an error:

Enter your character's name, or type new: 
admin
tt="version";version=1.0;
Illegal name, try another.
Name: 
admin
Password: 
Last connected from: 


The part in comm.c where we add:

extra MUD status' 
write_to_buffer( dnew, want_server_status, 0) 

seems to be adding to my first login attemp. If I just put the login twice, everything seems to work fine..

I am using Fiendish's handler he provided me in another thread and it is giving me all my data in JSON.

Is there any indication you can give me why it may be doing this? What could I show/share to help you with this?
USA Global Moderator #53
Quote:
I am using Fiendish's handler he provided me in another thread and it is giving me all my data in JSON.
Link for reference: https://mushclient.com/forum/?id=14680&reply=5#reply5



Quote:
tt="version";version=1.0;

I assume this is a debug message? It looks like it's coming from the server ( https://github.com/nickgammon/smaugfuss/blob/07b4d2af6cb7f2525508542a86143ef97317cef8/src/comm.c#L1452 )

Can you show what your current comm.c looks like? That MUD_SPECIFIC value in the link predates GMCP, so I'm a little concerned about it.
Amended on Sun 10 May 2020 06:32 PM by Fiendish
#54
My current comm.c can be found at: https://github.com/DBNU-Braska/SMAUG_GMCP/blob/master/comm.c

The MUD_SPECIFIC I have is:

#define  MUD_SPECIFIC       '\xC9'

The other items I have added (and maybe renamed so I can understand in my mind)

const char gmcp_enabled[] = { ( char )IAC, ( char )WILL, MUD_SPECIFIC, '\0' };
dnew->gmcp_enabled = false;
/*
 * extra MUD status
 */
 write_to_buffer( dnew, gmcp_enabled, 0 );
if( d->inbuf[i] == ( signed char )MUD_SPECIFIC )
         {
            if( d->inbuf[i - 1] == ( signed char )DO )
               d->gmcp_enabled = true;
            write_to_descriptor(d, "\xFF\xFA\xC9tt=\"version\";version=1.0;\xFF\xF0", 0); */
            else if( d->inbuf[i - 1] == ( signed char )DONT )
               d->gmcp_enabled = false;
         }

(Then there are the functions that actually print the GMCP data; char.vitals, char.stats and char.combat is what I have created so far)


These were all the additions within comm.c - not all in the same place of course! I hope that's enough to understand my implementation. It is a variation on what was originally done in the old thread: http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=10043&page=1
Amended on Sun 10 May 2020 09:36 PM by Fiendish
USA Global Moderator #55
I notice that you've commented out line 1416. https://github.com/DBNU-Braska/SMAUG_GMCP/blob/master/comm.c#L1416

Please delete that line entirely. That placement is dangerous because you don't have braces around the intended scope of your "if" statement. If you don't know what that means or why it's a problem, I can explain, but history is absolutely littered with avoidable catastrophic bugs because someone thought it would be ok to omit curly braces on single line ifs.

But with that line gone though you would not be seeing that funny version message in your output, so what happens now?
Amended on Sun 10 May 2020 09:36 PM by Fiendish
#56
I removed the commented line,

The error still persists. And, it only does so when I have the handler plugin enabled.

Of course if I commend out line 1090 the error goes away, so maybe that is just in the wrong place? If I comment that out, then the server doesn't send GMCP data.
Australia Forum Administrator #57
That code is very confusing, whether you wrote it or someone else did.

Can you rework it please? At lines 1396 to 1424 I would like a switch on IAC, eg.


switch (iac)
  {
  case 0:  
    // some stuff
    break;
  case 1:  
    // some stuff
    break;
  case 2:  
    // some stuff
    break;
  } // end of switch


Offhand it looks like certain conditions are going to affect that lengthy "if" statement with all its "else" clauses in a way you don't want.
Amended on Mon 11 May 2020 06:15 AM by Nick Gammon
#58
Thanks, I will work on this.

Do you believe this could be part of the reason I am getting the login error? it's sending the wrong info to buffer?

The code is the same as the base SMAUGFUSS 1.9 as seen here: https://github.com/nickgammon/smaugfuss/blob/master/src/comm.c#L1389

I have added the GMCP negotiation to be inline with how MCCP negotiation is done (TELOPT_COMPRESS2)

I'll have to work on making this case notation function correctly.
Amended on Mon 11 May 2020 11:32 AM by Xinefus
USA Global Moderator #59
Quote:
Do you believe this could be part of the reason I am getting the login error? it's sending the wrong info to buffer?

Without really thinking much about it, my first guess is that the error is caused by the the server doing the wrong thing when handler plugin sends the GMCP "hello" message.

But you've only shown us that _something_ didn't work. It would be more informative if you added debug logging to the server to show what it received that it didn't like.

Quote:
The code is the same as the base SMAUGFUSS 1.9 as seen here: https://github.com/nickgammon/smaugfuss/blob/master/src/comm.c#L1389

What if you use Nick's modified version from https://github.com/nickgammon/smaugfuss/blob/status_messages/src/comm.c#L1300-L1546
Amended on Mon 11 May 2020 01:26 PM by Fiendish
#60
I thought of using Nick's version, however there are a lot of changes involved in that one. I wasn't going to jump into that unless I had to. First off is the codebase i'm using doesn't have the std::string defined. So that would be a start I suppose.

I hadn't wanted to do a whole rewrite to a mud if I could help it.

Maybe it is something I should do however, but this is all just to help me get this working on a more heavily modified codebase that is 'like' SMAUGFUSS1.9. I don't want to change too much in a vanilla type just to see that it will be even more work on this more modified version. But maybe updating read from buffer won't change too much...
USA Global Moderator #61
Quote:
I thought of using Nick's version, however there are a lot of changes involved in that one.
You're right. But I guess I don't know if Nick's original commit actually worked before his refactor.

Nick, do you remember the context for https://github.com/nickgammon/smaugfuss/commit/45b5f0491f9197aa6c413cb8483e8983c4483ba2 and whether the comm.c in that commit worked as is?


Xinefus,
Why does https://github.com/DBNU-Braska/SMAUG_GMCP/blob/master/comm.c#L1412 remove the else vs https://github.com/nickgammon/smaugfuss/blob/45b5f0491f9197aa6c413cb8483e8983c4483ba2/src/comm.c#L1414 ?

I still would like to see what the server is actually receiving that it doesn't like.
Amended on Mon 11 May 2020 05:02 PM by Fiendish
Australia Forum Administrator #62
Fiendish said:

Nick, do you remember the context for https://github.com/nickgammon/smaugfuss/commit/45b5f0491f9197aa6c413cb8483e8983c4483ba2 and whether the comm.c in that commit worked as is?


I think so, I normally test stuff before committing it. What part looks doubtful?
USA Global Moderator #63
Quote:
What part looks doubtful?

No part. Just checking for possible reasons for the noted error in the absence of concrete information about why the server is complaining.
#64
Thanks for sharing that commit, I hadn't found that one and it is effectively what I did to my version.

Just to go over the changes that I have done, I have changed the read_from_buffer to enable negotiation for the MUD_SPECIFIC items, and I have put in the fixup_lua_strings so that I can get name/victim names to work in MUSHclient.

What exactly do you want me to do to help debug. I'm not very good at knowing where/what to slip in there to enable the server to spit out the errors it is getting. I've never used gdb before so I'm trying to read some tutorials on this but would like some assistance if possible.

note, you can see my complete source on my git. Perhaps you can replicate the problem I am having.
#65
I'm really going down a rabbit hole here...

Where should I be setting a break for gdb to catch this?



Thanks.
Amended on Tue 12 May 2020 12:47 AM by Xinefus
USA Global Moderator #66
You said you're getting "Illegal name, try another."
When the server sends that, what exactly was the name that it thinks it got? Ideally I would like to see a printout of every single message coming into the server from the client at the time that occurs.
Amended on Tue 12 May 2020 05:55 AM by Fiendish
Australia Forum Administrator #67
You haven't made the changes I suggested in reply #57.

The "illegal name" thing sounds like you have put into the input buffer some of the IAC stuff, which suggests that the telnet negotiation stuff isn't working, which you already know anyway.
USA Global Moderator #68
Xinefus said:
it is effectively what I did to my version


Except that you're missing an else.
#69
I have (maybe it wasn't completely up to date on Git) c/p the read_from_buffer from https://github.com/nickgammon/smaugfuss/blob/master/src/comm.c to mine. I do still get the error.

I'm looking at trying to do what is done in the 'status messages' commit.

As I've been doing these changes, I am getting a bit more comfortable in how navigate the mud. I do like the case format a lot better, it just looks really nice and it probably runs a heck of a lot smoother.

If I am trying to implement this in to a modified MUD based off SMAUGFUSS1.9 and I wanted to begin the process of updating parts to the 'status_messages' (https://github.com/nickgammon/smaugfuss/tree/status_messages), where would you suggest I actually start? Looking at the commits from Git, it doesn't 'look' like all files have been modified within /src but is there a way to be able to iteratively get this started?
Australia Forum Administrator #70
Your code looks completely different to my code at:


https://github.com/nickgammon/smaugfuss/blob/status_messages/src/comm.c#L1300

Notice the extensive use of switch statements, rather than a lot of nested "if"s.
Australia Forum Administrator #71
Xinefus said:

I thought of using Nick's version, however there are a lot of changes involved in that one. I wasn't going to jump into that unless I had to. First off is the codebase i'm using doesn't have the std::string defined. So that would be a start I suppose.


I think you compile with g++ rather than gcc to fix that.
USA Global Moderator #72
Quote:
I have (maybe it wasn't completely up to date on Git) c/p the read_from_buffer from https://github.com/nickgammon/smaugfuss/blob/master/src/comm.c to mine.

The master branch in that repository does not include the necessary updates. You want the status_messages branch.


https://github.com/nickgammon/smaugfuss/blob/master/src/comm.c
and
https://github.com/nickgammon/smaugfuss/blob/status_messages/src/comm.c
are not the same
Amended on Wed 13 May 2020 12:54 PM by Fiendish
USA Global Moderator #73
Nick Gammon said:
I think you compile with g++ rather than gcc to fix that.

It's a little weird to switch a C project to C++ to bring in string.h, lol.
Amended on Wed 13 May 2020 12:58 PM by Fiendish
#74
Thanks for the support guys.

I'm working on getting a test-copy of the actual mud I want to be doing this implementation on. I am getting discouraged doing all these changes just on a blank slate and it doesn't mean it will work on the production MUD.


I'm going to take a few days to get setup. I'll be back soon!

Suuupper thank you! I am learning so much. My wife has also pulled out some of her old books and is super interested in this. She doesn't like gaming, but the coding part has sparked her interest.

Cheers!
#75
Just to further my ability to write some more plugins for MUSH, I downloaded the entire https://github.com/nickgammon/smaugfuss/tree/status_messages .

Had a few compile errors, will work them out another time.
Amended on Wed 13 May 2020 08:19 PM by Xinefus
Australia Forum Administrator #76
Fiendish said:

Nick Gammon said:
I think you compile with g++ rather than gcc to fix that.

It's a little weird to switch a C project to C++ to bring in string.h, lol.


You mean <string> not <string.h>.


The STL has some nice features, I don't see why we can't use them. Some of the string handling in straight C is rather tedious.
USA Global Moderator #77
The file behind <string> is string.h

Quote:
The STL has some nice features, I don't see why we can't use them. Some of the string handling in straight C is rather tedious.

That's true. It just requires switching languages is all. :)
Amended on Wed 13 May 2020 11:11 PM by Fiendish
#78
Nick Gammon said:

I think you compile with g++ rather than gcc to fix that.


I'm not sure to laugh or cry at this one. Hehe.

Happy June everyone!

I have been able to get the https://github.com/nickgammon/smaugfuss/tree/status_messages MUD running and playing around with it. But it is going to be a bit until I will use what I'm learning in there in the actual MUD I'm working on.

Right now, I am a bit stuck between a rock and a hard place. I have requested to become a coder for a specific MUD, but they have given me a task to prove myself and it is a bit of a movement backwards. Backwards meaning that the task is to get an old version of a mud working, it's based on SMAUG 1.4, it compiles only in gcc-3.4 and try and implement gmcp to prove how I would do it. With this, I can then get access to the actual MUD codebase.

So what I have tried to do is implement gmcp with the info in http://www.gammon.com.au/forum/?id=10043&reply=7#reply7 (also using \xC9 btw vice \x66).

Like a previous post here, when I get those code snippets implemented I end up with a login error wherein I have to put in the name twice (in MUSHClient) before it will work. It also seems that GMCP is always enabled, even for a client that has no telnet negotiation capability (I'm thinking of GMUD in this case). I was hoping that by default it would be off, and that if someone was using an old client such as gmud (we try to tell them not to) they wouldn't see the code. But so far it still shows up.

So it boils down to the fact that I have it working but there are still a few bugs to iron out and I would like a bit of guidance. Not sure if this forum is the right place to do so, but you guys seem at least active and responsive so I thought I would try here.

How can I get this working on a very old codebase (I can share it if needed as I just downloaded it from afkmuds and can post it to git for ease of collaboration).

Once I can get this shown to work (without the negotiation error) I will then be able to implement it on a MUD that is compiled in g++, and hopefully will be able to use more of the snippets from the github link stated above.
USA Global Moderator #79
I have enough of my own projects that I don't really want to "collaborate" on this, but I can answer specific questions and give guidance about how to debug code. Though if you want to be a coder for that MUD, these are the kinds of things that you're going to need to be able to figure out.

Quote:
I end up with a login error wherein I have to put in the name twice

Add print statements in the server code that display everything being received and sent, so that you can see everything that goes back and forth in the order that it is sent and received. You can't fix what you don't see.

Quote:
It also seems that GMCP is always enabled, even for a client that has no telnet negotiation capability (I'm thinking of GMUD in this case). I was hoping that by default it would be off

It should be. Maybe you didn't apply the changes correctly.
Amended on Thu 04 Jun 2020 02:47 AM by Fiendish
Australia Forum Administrator #80
Quote:

... when I get those code snippets implemented I end up with a login error wherein I have to put in the name twice (in MUSHClient) before it will work



This was a thing in the past, and it was because the server wasn't processing IAC ... message properly. For example, the client might be sending some sort of subnegotiation query. Now if you login with your name, and the query response has been automatically sent by the client, and the server hasn't processed it and stripped it out then the IAC stuff becomes part of the player name and it is rejected.
#81
Good morning (least where I am),

Is there a way to implement (enable/disable) GMCP through similar method through config such as how ANSI or TELNET_GA is turned on and off?

Right now, I'm not savvy enough in C to convert update the whole of read_from_buffer so that IAC will work correctly with MCCP and GMCP simultaneously.

I've been trying to look within act_info and create the link between a gmcp toggle and the ability to enable the messages. Any recommendations on this way ahead?

Would this remove the requirement for auto-telnet-negotiation, or am I just making more work for myself before I get this working correctly?
Amended on Thu 04 Jun 2020 11:36 AM by Xinefus
#82
Alright, so I want to explain how/what I have done and because I do not have a lot of experience with the do's and don'ts of MUDs I hope that you can tell me if I have done a grave error or not.

What I opted for doing at this time due to my limited knowledge in C is to create a GMCP toggle (such as the ANSI/RIP toggle) under the config command.

Here was my process:

Within mud.h:

#define IAC_SB_GMCP        "\xFF\xFA\xC9"
#define IAC_SE             "\xFF\xF0"

...

typedef enum
{
PLR_GMCP // under act bit/flag 
} player_flags;

...

bool    is_gmcp         args( ( CHAR_DATA *ch ) );

Within player.c:

bool is_gmcp( CHAR_DATA *ch )
{
    if( xIS_SET(ch->act, PLR_GMCP ) )
      return TRUE;

    return FALSE;
}

Within act_info.c

in void do_config()

...

send_to_char( "\n\r\n\rMisc:      ", ch );
set_char_color( AT_GREY, ch );
ch_printf( ch, "%-12s   %-12s   %-12s   %-12s  
 %-12s\n\r",
   xIS_SET(ch->act, PLR_GMCP ) ? "[+] GMCP"
  : "[-] gmcp" );

...

else if ( !str_prefix( arg + 1, "gmcp"	) )
  bit = PLR_GMCP;

Within comm.c

/* GMCP */
#define  MUD_SPECIFIC       '\xC9'

...

display_prompt()

...

send_to_char( buf, ch );
  if( is_gmcp(ch) )
  {
  	ch_printf (ch, IAC_SB_GMCP "Char.Status {\"hp\": %d}" IAC_SE, ch->hit);
  }
  return;
} // end display_prompt

Now I do understand that this does not work if prompt is turned off. But all I would have to do in this case is declare a void show_status( CHAR_DATA *ch ); and append the right info inside of it.

Does this sound/look like a good way forward?
Amended on Thu 04 Jun 2020 06:40 PM by Xinefus
USA Global Moderator #83
If possible, please put your code up on github somewhere and then reference code sections by permalinking multiline selections so that we can see all of the context. ( https://help.github.com/en/github/managing-your-work-on-github/creating-a-permanent-link-to-a-code-snippet )

Or maybe just show more context.

Quote:
Alright, so I want to explain how/what I have done and because I do not have a lot of experience with the do's and don'ts of MUDs I hope that you can tell me if I have done a grave error or not.

Honestly when it comes to MUDs (servers anyway) I'm an extreme novice. I'm a rather good programmer, though, so maybe I'll be able to follow.

Quote:
What I opted for doing at this time due to my limited knowledge in C is to create a GMCP toggle (such as the ANSI/RIP toggle) under the config command.

I'm sure you understand why that's not ideal, but for now if it works then ok.

Quote:
typedef enum
{
PLR_GMCP // under act bit/flag
} player_flags;

I assume that it doesn't actually look exactly like this and that this is merely a condensed view of the player_flags enum with all the other values hidden away?

Quote:
bool is_gmcp args( ( CHAR_DATA *ch ) );

What is args here? A typical function declaration does not say "args".

Quote:
#define MUD_SPECIFIC '\xC9'

Are you using this?

Quote:
Does this sound/look like a good way forward?

It sounds like it should work as long as the client doesn't care whether you've negotiated. It's obviously not as good as negotiating with the client automatically.

Does it work?
Amended on Thu 04 Jun 2020 10:26 PM by Fiendish
Australia Forum Administrator #84

What is args here? A typical function declaration does not say “args”.

It’s some sort of #define that Smaug uses to handle old C-style argument lists.

You can probably assume it evaluates to its arguments.

i.e.

bool is_gmcp args( ( CHAR_DATA *ch ) );

Would be the same as:

bool is_gmcp ( CHAR_DATA *ch );
#85
Well...


After all that work, a few months of discussions - I have found out that the mud I am looking to code for has a protocol snippet by Kavir installed. Included in that snippet is (as the readme states):
https://github.com/Xavious/MSDP_Protocol_Handler
  • Out-of-band communication between mud and client (MSDP);
  • Extended colours (xterm);
  • Client detection;
  • Clickable links;
  • Unicode support;
  • MSSP; and
  • Sound support

Once I showed the snippet of GMCP that I added as an example, he wanted to know if it would conflict with Kavir's snipped. After looking into the snippet, if most certainly would.
When I asked him why he didn't just tell me he added this snippet, he said he didn't know about MSDP and only added the snippet to get xterm colour support! Haha.

So, I've cobbled together a handler and am trying to find out all the diff items I am able to receive from the MUD.

I have learned so much! Not even a waste of time and I wan to thank all of you for it.

I believe I will let this discussion end here for now as my next step I will be towards jumping into MUSHclient plugins.

Thank you!
Amended on Fri 05 Jun 2020 10:40 AM by Xinefus
Australia Forum Administrator #86

I just want to point out that GMCP and MSDP do not have to clash at all. They are both telnet subnegotiation protocols, and the messages will be distinguished by the protocol number. That is, you could have:

IAC SB MSDP ... some stuff ... IAC SE

And then:

IAC SB GMCP ... some stuff ... IAC SE

The client will parse them separately and hand them off to the appropriate plugin, if any.

USA Global Moderator #87
Just adding to what Nick said...

If the MSDP handling is implemented sanely, it would make adding GMCP easier not harder.
#88
I agree that they should work very well alongside eachother and even should be able to complement each other.

The implementation of MSDP,as I have been told, followed the SMAUG readme as per: https://github.com/Xavious/MSDP_Protocol_Handler?files=1

I didn't go into the code as I pretty much wanted to start writing plugins since it had a lot of data already available. However, I did see that somewhere in there it said that it currently was not compatible with GMCP as currently, MSDP strips out any other AIC SB...
USA Global Moderator #89
Negotiating GMCP activation would be trivial with that code. You just have to add a case for the GMCP identifier byte to PerformHandshake.
Australia Forum Administrator #90
Xinefus said:

... as currently, MSDP strips out any other AIC SB...


IAC SB ... you mean?

That's crazy for MSDP to strip out all other protocols. What about screen size negotiation, client name, etc. etc.?
USA Global Moderator #91
Quote:
That's crazy for MSDP to strip out all other protocols

Don't worry, it doesn't.
Australia Forum Administrator #92
Well, that's a relief. :)