Pull to refresh

Пишем утилиту для Settlers Online

Reading time4 min
Views7.4K
image
Несколько дней назад на Хабре появилась отлична новость: Settlers теперь и в онлайне!
Игра написана на flex, следовательно, работать будет практически на любой современной платформе. Но beta-версия игры накладывает свой отпечаток — многое ещё не доработано, а кое-что просто нестабильно. Интерфейс абсолютно удобным тоже назвать нельзя.

Ни одна экономическая стратегия не обходится без торговли. В перспективе возможно создавать моно-посёлки, добывающие один вид ресурса, обменивая остальные через рынок. Для небольшого упрощения торговли, а также как proof of concept я решил написать максимально простую утилиту.

Так как же клиент узнаёт об ассортименте на рынке?
Простейший способ узнать это — поставить сниффер и посмотреть, что происходит между клиентом и сервером. После испытания нескольких платных, но абсолютно не оправдывающих свою стоимость программ, я вернулся к проверенному бесплатному Wireshark. Он позволит увидеть то, что скрыто.

Установка Wireshark проблем не вызывает, приступим сразу к сниффингу. Для этого достаточно выбрать в настройках интерфейс, через который и происходит общение. Для этого можно воспользоваться комбинацией Ctrl+I, либо пунктом меню Capture -> Interfaces.

image

Никаких дополнительных настроек на данном этапе делать не нужно, нажимаем Start напротив активного интерфейса.
В главном окне появится что-то вроде этого:

image

Разумеется, большая часть данной информации нам абсолютно не нужна, так как здесь отображается активность торрентов, даунлоадеров и прочей живности. Отфильтруем пакеты, в которых ip совпадает с ip xmpp-сервера игры (на этом протоколе, с некоторыми изменениями, основан как чат, так и торговля):

image

Из всех пакетов нас интересуют HTTP/XML, из которых Wireshark позволяет сразу вытянуть информацию, заодно уберём исходящие пакеты, в которых в данном случае никакой интересной информации для нас не содержится. Для этого изменим фильтр на «ip.src == 87.119.203.13 and xml»:

image

Теперь, просмотрев любой из этих пакетов, мы увидим что-то вроде (скобки изменены для правильного отображения):

eXtensible Markup Language
[body xmlns='http://jabber.org/protocol/httpbind']
[message xmlns="jabber:client" to="dim0n@87.119.203.13/xiff-bosh" id="m_3115" type="groupchat" from="trade@conference.87.119.203.13/pimo"]
[body]Coin|1|Stone|200[/body]
[bbmsg xmlns="bbmsg" playername="Pimo" playerid="85153"/]
[/message]
[/body]

Из данного сообщения видно, что за 1 монету (Coin|1) игрок хочет получить 200 камня (Stone|200). Не самая выгодная сделка, но не суть. В данном формате передаются все торговые сообщения. В общем случае их можно описать регулярным выражением \w+\|\w+\|\w+\|\w+.

Итак, мы почти на финишной прямой. Мы научились получать торговые сообщения и можем их красиво отобразить. Но любая информация хороша тогда, когда она актуальна. В программный комплекс Wireshark входит утилита dumpcap.exe. Она позволит нам записывать нужные пакеты без, собственно, запуска самого Wireshark. Не буду описывать аргументы для запуска, о них можно узнать из хелпа, у меня же получилась строка -i \Device\NPF_{4DC422B9-3A2E-4899-9775-2DD89AF02FDD} -f «host 87.119.203.13» -w C:\Users\Dim0N\Desktop\323232my. Пакеты будут складываться в файл 323232my (нет, обоснования названия у меня нет).

Обрабатывать полученную информацию я буду в C#. Для этого создадим в форме DataGridView с колонками «Покупка», «Цена покупки», «Продажа», «Цена продажи». По таймеру раз в 5 секунд проверяем новые пакеты из файла.

public Form1()
    {
      InitializeComponent();
      timer1.Start();
      timer1.Interval = 5000;
      Process.Start(@"C:\Users\Dim0N\Desktop\2\WiresharkPortable\App\Wireshark\dumpcap.exe",
                       "-i \\Device\\NPF_{4DC422B9-3A2E-4899-9775-2DD89AF02FDD} -f \"host 87.119.203.13\" -w C:\\Users\\Dim0N\\Desktop\\323232my"); // Запускаем dumpcap с заранее составленной строкой аргументов.
    }


* This source code was highlighted with Source Code Highlighter.


Раз в 5 секунд выполняется следующий код:

private void timer1_Tick(object sender, EventArgs e)
    {
      File.Copy(@"C:\Users\Dim0N\Desktop\323232my", @"C:\Users\Dim0N\Desktop\323232mycopy", true); //Копируем файл, так как считать файл, открытый в dumpcamp невозможно
      var streamReader = new StreamReader(@"C:\Users\Dim0N\Desktop\323232mycopy");
      string str = streamReader.ReadToEnd(); // считываем файл
      streamReader.Close();
      int i = 0;
      dataGridView1.Rows.Clear(); // особо не задаваясь вопросом удаления дублей, я просто очищаю датагрид
      foreach (var match in Regex.Matches(str, @"\w+\|\w+\|\w+\|\w+")) // находим все совпадения с нашим регулярным выражением
      {
        string matchstr = match.ToString(); // конвертируем в строку
        dataGridView1.Rows.Add(matchstr.Split('|')[0], matchstr.Split('|')[1], matchstr.Split('|')[2], matchstr.Split('|')[3]); // делим строку на части, заносим в таблицу
        if ((matchstr.Split('|')[0] == matchstr.Split('|')[2]) && (Convert.ToInt32(matchstr.Split('|')[1]) < Convert.ToInt32(matchstr.Split('|')[3]))) // в игре бывают случае, когда ресурс продаётся за этот же ресурс, но стоит дешевле (например 100 камня за 10 камня)
        {
          dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Red; // помечаем такие строки красным
        }
        i += 1;
      }


* This source code was highlighted with Source Code Highlighter.


В итоге имеем такую таблицу, которая позволяет нам сортировать, отбирать наиболее выгодные предложения и обрабатывать информацию как нам захочется:

image
Tags:
Hubs:
Total votes 52: ↑43 and ↓9+34
Comments26

Articles