Skip to main content
  1. Posts/

Day 68 - Protocol

OldDays seitan-spin cucumber ruby

I wasn’t sure you’d get a Goldie Hahn reference.
I wasn’t sure you’d get a Goldie Hahn reference.

In which we learn the binary language of moisture vaporators.

Note: Due to a bit of a situation at work, I’m suddenly very busy again. Rather than lose what little momentum exists, I’ll be doing shorter posts.

Test Every Day
#

CLIENT_VERSION
#

Let’s keep striking away at that config file. One we skipped earlier is the CLIENT_VERSION. It appears to be used in only one place, where it is simply communicated to the client along with the APP_VERSION:

DragonsSpine/GameSystems/Network/Protocol.cs
1668
1669
1670
1671
1672
1673
1674
1675
public static void sendWorldVersion(Character ch)
{
  try
  {
    string message = Protocol.VERSION_SERVER + DragonsSpineMain.APP_VERSION + Protocol.VERSION_SERVER_END;
    message += Protocol.VERSION_CLIENT + DragonsSpineMain.CLIENT_VERSION + Protocol.VERSION_CLIENT_END;
    ch.Write(message);
  }

As might be clear, this is using a custom protocol rather than simple ANSI. So we’ll need to figure out how to connect using this protocol (you can see why I initially skipped this part). sendWorldVersion is called by PrintMainMenu if the character’s protocol is equal to APP_PROTOCOL (also from the config file, and defaulted to “Kesmai” in the original code repo).

So how is the character’s protocol determined? It defaults to “normal” and can be swapped between “normal” and “old-kesmai” at the menu, that’s easy enough to find. But the only place I see it being set to anything else is in Protocol.CheckMenuCommand:

DragonsSpine/GameSystems/Network/Protocol.cs
818
819
820
821
822
823
824
825
      #region Set Protocol
      if (command == SET_PROTOCOL)
      {
        ch.protocol = DragonsSpineMain.APP_PROTOCOL;
        Menu.PrintMainMenu(ch);
        return true;
      }
      #endregion

Earlier on, we see SET_PROTOCOL = (char)27 + "98" + (char)27, so it seems that this particular escape sequence being sent at any menu will do the trick. I’ll assume that a custom client application just knows to do this itself.

features/config_file.feature
49
50
51
52
53
54
55
Scenario: CLIENT_VERSION sent at main menu
  Given I use the "minimal" database as-is
  And I set "CLIENT_VERSION" in the config file to "25.6.2.4"
  And the server is started
  When I log on using a standard account
  And I send the protocol command "SET_PROTOCOL"
  Then I receive a CLIENT_VERSION of "25.6.2.4"
features/lib/protocol.rb
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
PROTOCOL_STRINGS = {
  SET_PROTOCOL: "\e98\e",
  VERSION_CLIENT: "\eV2\e",
  VERSION_CLIENT_END: "\eV3\e"
}

When(/^I send the protocol command "([^"]*)"$/) do |command|
  resp = telnet_command(@connection, PROTOCOL_STRINGS[command.to_sym], /.../)
end

Then(/^I receive a CLIENT_VERSION of "([^"]*)"$/) do |version|
  expectation = PROTOCOL_STRINGS[:VERSION_CLIENT] +
        version +
        PROTOCOL_STRINGS[:VERSION_CLIENT_END]
  expect(@last_resp).to include(expectation)
end
37 scenarios (37 passed)
278 steps (278 passed)
6m58.251s

TODO/Refactor Every Other Day
#

features/config_file.feature
172
# TODO: News message included in protocol WorldInformation.

There’s kind of an obvious one, since we just figured out how to trigger the WorldInformation block.

features/config_file.feature
172
173
174
175
176
177
178
Scenario: NEWS included in WorldInformation
  Given I use the "minimal" database as-is
  And I set "NEWS" in the config file to "This is a test, do not be alarmed."
  And the server is started
  When I log on using a standard account
  And I send the protocol command "SET_PROTOCOL"
  Then I receive a NEWS of "This is a test, do not be alarmed."
features/lib/protocol.rb
2
3
4
5
6
7
8
PROTOCOL_STRINGS = {
  SET_PROTOCOL: "\e98\e",
  VERSION_CLIENT: "\eV2\e",
  VERSION_CLIENT_END: "\eV3\e",
  NEWS: "\eM1\e",
  NEWS_END: "\eM2\e"
}
features/lib/protocol.rb
21
22
23
24
25
26
Then(/^I receive a NEWS of "([^"]*)"$/) do |news|
  expectation = PROTOCOL_STRINGS[:NEWS] +
        news +
        PROTOCOL_STRINGS[:NEWS_END]
  expect(@last_resp).to include(expectation)
end
38 scenarios (38 passed)
284 steps (284 passed)
7m8.792s

More fun to be had with the protocol stuff? Of course. Tomorrow.


Useful Stuff
#


More to come
More to come

Day 68 code - tests