Все записи автора Квиринг Алексей

Собираем логи

Закончили систему сбора и просмотра логов. Проблема анализа логов была очень актуальной, так как у нас несколько типов серверов — игровой, ресурсный, генератор.Тем более на этапе тестирования сообщения от клиентов также потребуют обработки.

Архитектура

Сервер логгирования основан на OSGI платформе. Получение логов по RMI с использованием авторизации JAAS (для Log4j был написан appender). Сохранение логов с помощью Hibernate в базу данных PostgreSQL. Для просмотра логов были написаны плагины к Eclipse. Основные возможности — фильтрация логов по различным критериям и сохранение произвольного количества фильтров для последующего изучения.

Пользуясь случаем, поздравляем Волкова с днем рождения. Превед!

Результаты интеграции

Закончена большая часть работы по интеграции: готовы редакторы 3D мира, пользователи бегают и общаются, участки мира догружаются и выгружаются, сделана система воздействия на предметы.

Дальнейшая интеграция будет после разработки 3D-движка 5.0.

Полноразмерные скриншоты:

Результаты интеграции Результаты интеграции Результаты интеграции

Тестирование и логирование — азы программирования

Тесты и нормально организованная трассировка — основные принципы создания больших программных систем. Но чаще всего в них не верят: тратят кучу времени на поиск незначительных ошибок и читают километровые тексты из консолей. Такое встречается даже у программистов с опытом работы несколько лет.
Continue reading Тестирование и логирование — азы программирования

Ассемблер для Flash — ускорение приложений

http://haxe.org/hxasm
Библиотека может динамически генерировать массив байтов ByteArray, представляющий SWF-файл со скомплированными методами ассемблера. Затем этот код может быть выполнен при помощи метода flash.display.Loader.loadBytes.

Насколько библиотека hxASM может ускорить выполнение Flash9-приложений?

В качестве примера — вычисление ряда Фибоначчи. Ускорение достигает 30%.

// fib takes an integer argument and returns an integer
var m = ctx.beginMethod(“fib”,[tint],tint);
// we will have up to 3 values on the stack
m.maxStack = 3;
ctx.ops([
OReg(1),      // register 1 = first argument
OSmallInt(1), // the integer 1
OJump(JGt,3), // jump 3 bytes if reg1 > 1
OInt(1),
ORet,         //   return 1
ODecrIReg(1), // decrement register 1
OThis,
OReg(1),
// call this.fib(reg1) with 1 argument
OCallProperty(ctx.property(“fib”),1),
ODecrIReg(1), // decrement register 1
OThis,
OReg(1),
// call this.fib(reg1) with 1 argument
OCallProperty(ctx.property(“fib”),1),
OOp(OpIAdd),  // add the two values
ORet,         // returns
]);

Хранение картинок, звуков и других ресурсов

Сложно представить игру без картинок, музыки и других видов ресурсов.
Более того, типичная игра потребует достаточно большое количество разнообразных ресурсов, да и еще и в разных форматах.

Для примера возьмем простой ресурс — изображение. С одной стороны дизайнерам удобно рисовать в PhotoShop-е, а с другой — Flash не умеет читать и показывать такие файлы. Да и для оптимизации трафика лучше из PSD формировать две картинки JPG для изображения и GIF для хранения карты прозрачности. Если такую задачу возложить на дизайнеров, то большая часть их рабочего времени будет уходить на конвертирование файлов. А после конвертирования файлы еще надо скопировать в папку, доступную серверу по протоколу FTP.

Continue reading Хранение картинок, звуков и других ресурсов

Разреженные массивы

В программировании часто встречаются задачи хранения объектов и быстрый поиск их по числовым идентификаторам. Такая задача у нас возникла при работе с трехмерными точками на сервере.

Постановка задачи

Для каждого объекта есть набор точек, каждая точка представляет собой идентификатор (Int) и координаты X, Y, Z. Точек может быть достаточно много — несколько тысяч. Идентификаторы не обязательно последовательные, но последовательность нарушается достаточно редко. С точками определены следующие операции: добавить, удалить и получить все точки для математических операций. Требуется быстрая структура для хранения, создания и редактирования точек. Самый простой способ использовать Map<Int,Vertex>, но потребление памяти и скорость нас не устроила. Сервер должен обрабатывать несколько миллионов точек в секунду и чем больше, тем лучше.
Continue reading Разреженные массивы

Выбор архитектуры сервера

Итак, у нас задача написать сервер для многопользовательской онлайн игры. Вот тут нам повезло, никто не говорил на чем писать и что использовать, был только набор требований и идей. Требования были такие — много людей бегают по миру, общаются, живут. Клиент обязательно на Flash. Вот и всё.

Язык программирования

JAVA — простой и логичный язык, удобная среда разработки, стабильная и достаточно быстрая среда исполнения. К тому же большой набор готовых библиотек. В качестве аналога рассматривали C#. Возможности почти такие же, но менее логичный синтаксис. Только одна среда программирования и одна операционная система. Нет нормальных решений в области серверов приложений, ORM-ов и так далее. Например, попробуйте найти встроенный WEB сервер для приложения на C#. А вот для JAVA существует несколько подобных решений.

База данных

В процессе создания прототипа базы данных было решено использовать базу данных на основе разработок от BerkeleyDB. Получили достаточную скорость работы с данными, но были большие сомнения в масштабируемости и надежности такого решения. В дальнейшем перешли на SQL базу и в качестве объектной прослойки выбрали ORM Hibernate. Скорость работы упала на два порядка, но теперь у нас есть надежда на масштабируемость и надежность, а также появилось право выбора MySQL или Oracle, PostgreSQL или DB2. Первой базой была MySQL, но через месяц работы перешли на PostgreSQL, на том и остались. Вопрос о смене базы данных поднимем после альфа/бета тестирования.

Сервер приложений

Для JAVA есть выбор между JBOSS, Spring и их коммерческими аналогами. Но в итоге мы решили не использовать стандартные подходы, так как для нас они слишком громоздкие и не подходят для нашей идеологии Моделей поведения. Все же игра это не бизнес приложение и подходы здесь совсем другие. С другой стороны программировать сервер как одно большое монолитное приложение не было бы оптимальным решением. Остановились на решении использовать OSGI ядро, тоже самое, что используется в Eclipse. Такой подход позволил нам части игрового сервера оформить в виде отдельных независимых модулей. Плюсы данного подхода — разграничение прав доступа, четкое API для обмена информацией между модулями, возможность менять модули без остановки сервера. К тому же модули можно запускать на нескольких машинах, что даст нам возможность наращивать вычислительную мощность без существенных переделок программного кода.

Выбор среды программирования — Eclipse, так как с OSGI она работает лучше, чем другие IDE.

Обмен данными между сервером и клиентом

Самой первой задачей в далеком 2006 году, когда игра казалась маленьким проектом и работали вечерами после основной работы, возникла первая задача — как же обмениваться данными между сервером и клиентом. Напоминаю, сервер на Java, клиент — на Flash.

Для начала рассмотрим стандартные возможности флеша по передаче данных — XML и AMF. Первый вариант отпадает практически сразу, так как текстовый формат тяжел для парсинга и не оптимальный по размеру.

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

Неделя ушла на создание первого прототипа. Сделали поддержку стандартных типов (byte, short, int, long, double), бонусом получили возможность достаточно просто добавлять другие примитивные типы. Далее задумались, как передавать структурные типы (List, Map, Array и String). В итоге пришли к решению передавать размер структуры как byte, short или int — в зависимости от размера. И в заключении ввели рекурсию, то есть можно в List положить Map в Map Array и так далее.

Разработка окончательного варианта на JAVA заняла две недели, включая JUNIT тесты. А далее самое интересное — разработка сетевой библиотеки на Flash.

Сразу скажу, что Flash в то время я не знал. Только-только вышел AS3 в бете, редактор ужасный, язык странный. Так что разработка заняла еще три недели. В результате сетевая библиотека работает до сих пор, особых ошибок не замечено и скорость вполне устраивает. Тесты с пинг-понгом прошли успешно.

Итог работы — быстрая, асинхронная (и на Java, и на Flash), надежная сетевая библиотека, с широкой поддержкой разных типов данных. Работает быстрее чем AMF и экономнее расходует сетевой трафик.

Великий и ужасный Flash…

По роду своей деятельности приходилось программировать на разных языках и платформах, включая промышленные контроллеры ScadaPack. Казалось бы, привык к различным подходам программирования. Но тут мне попался Flash. Задача стояла портировать сетевую библиотеку с JAVA. И началось… Бедные флешеры, как вы вообще программируете на таком языке? Я понимаю, что раньше было еще хуже, но и сейчас ситуация очень далека от идеальной, а точнее от удобной.

Полное отсутствие типов — byte, short, long. Вряд ли их поддержка усложнила бы виртуальную машину. Но еще хуже то, что нет нормальных коллекций, а есть универсальный супер комбайн Array и неплохой Dictionary. Я допускаю, что Array ввели для флешеров старой закалки, но могли же добавить и нормальные коллекции. Из-за Array флеш-программист чаще всего не понимает разницы между примитивным массивом, ассоциативным и сетом. Если уж AS3 был скопирован с JAVA, то почему не скопировали самое главное — структуру коллекций? Даже если бы дали доступ только к примитивным массивам, то можно было бы реализовывать нормальные List, Map, Set. Какой был бы простор для повышения быстродействия.

Убогая и тормозная оболочка программирования. И нет тут вины Eclipse, вина только разработчиков Flex, которые в спешки не подумали о скорости и удобстве работы. Сколько времени и сил было потрачено на борьбу с глюками и зависаниями, сейчас только надежда на разработки третьих лиц. Ждем с нетерпением!

И в заключении — FLASH жив только своей виртуальной машиной, как язык он из себя мало что представляет. И хотя графические возможности поражают, но над языком надо работать и работать.

Парсер PSD-формата

Photoshop в настоящее время стандарт де-факто для дизайнеров. Но для игры, кроме, собственно, изображения, нужна дополнительная информация. Например, точки привязки, разбивка на спрайты и так далее. Было принято решение, для удобства дизайнеров, задавать дополнительную информацию используя возможности Photoshop-а. То есть точки привязки — в отдельном слое, деление на спрайты — слайсами и так далее. Для обработки сервером этой информации нам потребовался парсер PSD-формата. Стали искать готовые парсеры, нашли, но довольно убогие, например, нет поддержки множественных слоев, слайсов и так далее. Пришлось найти документацию по формату и потратить неделю на написания парсера.

Пример использование парсера:

PSDParser parser = new PSDParser(new FileInputStream("image.psd")); 
PSDLayerAndMask layerAndMask = parser.getLayerAndMask();  
 
List layers = layerAndMask.getLayers(); 
List images = layerAndMask.getImageLayers(); 
int i = 0; 
for (PSDLayerStructure layer : layers) { 
    PSDLayerPixelData pixelData = images.get(i); 
    BufferedImage image = pixelData.getImage(); 
    if (image != null) 
	ImageIO.write(image, "png", new File(layer.getName() + ".png")); 
	    i++; 
}

Исходники проекта

Исходники проекта выложены в свободный доступ, под лицензией APACHE LICENSE.
Возможности — экспорт всех слоев, включая главный. Общая информация о файле, слоях. Полная поддержка слайсов.
Используйте данный код на свой страх и риск, также я буду благодарен, если сообщите об ошибках или способах улучшения кода.

psd_parser.7z