В поисках оригинала

На протяжении многих лет промышленники EVEOnline страдали от невозможности быстро найти оригиналы ценных чертежей среди многочисленных копий.

Эта статья посвящена тому, как нам удалось исправить положение.

Начнем сначала: почему копии и оригиналы вообще выглядели одинаково?

Проблема заключалась в способе указания идентификаторов типа (typeID) в нашей системе учета объектов: чертеж, например, чертеж «Ogre» или «Thorax» обладал определенным идентификатором типа вне зависимости от того, являлся ли он оригиналом (BPO) или копией (BPC) ― и этот идентификатор задавал производимый с помощью этого чертежа предмет. Идентификаторы типа входят в таблицу учета предметов в игре (и каждый предмет обладает своим идентификатором) ― но характеристики данного типа предметов хранятся в отдельных таблицах (в случае чертежей ― в таблице «ScienceandIndustry»).

Когда игровой клиент запрашивает список объектов у системы учета, он получает лишь базовый перечень характеристик предметов, а не информацию из упомянутых выше таблиц. Базовые характеристики (в частности, идентификаторы) оригиналов и копий чертежей одинаковы, и поэтому для того, чтобы узнать, с чем именно игрок имеет дело, клиенту приходилось еще один раз обращаться к серверу (к таблице «ScienceandIndustry»). Именно это и происходило при выполнении команды «Показать информацию» для чертежа.

При этом совершать дополнительный запрос каждый раз, когда игрок открывает ангар с чертежами, было бы просто жестоко по отношению к серверу ― ведь в большинстве случаев эта информация избыточна. Это, мягко скажем, не очень хорошо и с точки зрения работы с базой данных.

Так как же нам удалось решить эту проблему без отрицательных последствий для базы данных и сервера?

Первый шаг был сделан с выходом обновления Tyrannis1.2 в конце прошлого года (дополнительная информация ― в статье «64 bitsshouldbeenoughforeverybody» ). Хотя основная часть работы была посвящена переходу на 64-битные идентификаторы в системе учета предметов, мы этим не ограничились. Мы изменили структуру таблицы объектов, увеличили количество битов в идентификаторах и других элементах таблицы, удалили один устаревший атрибут и объединили еще два. Последний момент особенно важен в контексте данной статьи. Раньше в базе данных существовало поле “singleton” («одиночка») типа «бит»; оно указывало, что данный объект не является частью группы предметов, и что его идентификатор может использоваться в других таблицах. Второе поле, «количество», определяло количество находящихся в группе предметов. Легко видеть, что значения этих полей взаимоисключающи. Объекты-«одиночки» должны входить в группу, состоящую только из одного предмета, а группа из более чем одного объекта не может являться «одиночкой» (при этом стоит отметить, что группа из одного предмета не обязательно является «одиночкой»).

Чтобы сохранить место в базе данных (и обеспечить быстродействие игры), эти поля были объединены в новое поле типа «integer» (целое число) ― при этом объекты, для которых значение этого поля является отрицательным, считаются «одиночками». Чтобы перейти от старой системы к новой, достаточно было заменить все значения «singleton==1» на «quantity=-1».

Следующий шаг мы сделали, выпустив обновление Incursion1.3 (дополнительная информация – в статье «Inventorycorificationpart2 - creationofCARBONInventory». Мы продолжили начатую в ходе предыдущего этапа работу, ввели ряд мер, направленных на борьбу с читерами, упростили внутренний интерфейс для работы с системой объектов ― А ТАКЖЕ добавили поле «одиночка» в структуру данных DBRow, но на этот раз в качестве виртуального поля. С точки зрения программирования виртуальное поле выглядит точно так же, как и обычное, но обращение к нему происходит с помощью специальной функции (которая в нашем случае принимает в качестве исходных данных и значение поля «количество»).

В результате этих изменений мы получили 30-битный диапазон (для отрицательного значения этого поля), где можно хранить различную информацию в зависимости от типа объекта, а также единый способ доступа к ней. Если говорить о чертежах, то для оригиналов значение поля «качество» стало равным -1, а для копий ― -2.

Итак, теперь в том случае, если объект является чертежом, игровой клиент может проверять значение виртуального поля «одиночка» и отображать соответствующую иконку в зависимости от того, оригинал ли это или копия. При этом не осуществляются дополнительные запросы к серверу и не создается лишняя нагрузка на базу данных.

Изящно, не так ли?

Но, к сожалению, этого недостаточно.

Данный метод хорошо работает при отображении оригиналов и копий чертежей в вашем ангаре ― ведь мы знаем значение флага «одиночка». Но что делать, если объекта еще не существует (как, например, в случае с чертежами в магазине наград)? Ведь если предмета физически нет в игре, то и данные в соответствующих дополнительных таблицах отсутствуют. В данном случае проблема решается просто: мы знаем, что в магазине наград продаются только копии чертежей, а необходимая информация (количество партий и качество) хранится в структуре конкретного предложения. Эту информацию мы и передаем игровому клиенту, когда вы запрашиваете информацию о еще несуществующем чертеже.

Итак, о чем это я?

Так как теперь у нас в игре есть тип объекта, который может существовать в двух различных формах, с разными иконками и различными метаданными, нам пришлось начать обрабатывать множество граничных случаев для этого типа. Практически во всех случаях, когда эти иконки появляются в игре, мы отдельно обрабатываем информацию, необходимую не только для их отображения, но и для открытия окна «Показать информацию». Но при этом этот код исполняется клиентом игры и не создает дополнительную нагрузку на сервер.

Результат этой работы вы можете наблюдать в игре после выхода обновления Incursion1.5.

В работе над этим нововведением участвовало множество людей, его выход потребовал трех обновлений игры ― но теперь вы наконец можете на глаз отличить оригинал чертежа от его копии.

А благодаря этой статье вы знаете, как именно мы этого добились.

Источник:

eveonline.com/ru/