301 Days

A year of gamedev experiments.

Day 68 - Protocol

| Comments

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.cslink
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.cslink
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.featurelink
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.rblink
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
1
2
3
37 scenarios (37 passed)
278 steps (278 passed)
6m58.251s

TODO/Refactor Every Other Day

features/config_file.featurelink
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.featurelink
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.rblink
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.rblink
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
1
2
3
38 scenarios (38 passed)
284 steps (284 passed)
7m8.792s

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


Useful Stuff


Day 68 code - tests

Comments