Сообщений: 329
Тем: 16
Зарегистрирован: Nov 2014
Apoloser Написал:Нагрузка в том что любой эмулятор к чему то стремится, в случае Lineage к PTS. Я думаю объяснил внятно
Окей. Вас понял, вопрос к ТС.
Цитата:Зачем: Just 4 fun. Конечно, переработать код такого качества в что-то приемлемое - вопрос непростой (в плане времени), но все же постепенно будем двигаться вперед. Задача довольно понятная - сделать решение приемлемого для С4 качества, при этом не унаследовать все архаизмы из имеющихся решений.
Механики работы тех или иных скриптов и не будет никогда работать идентично ПТС на эмуляторах.
С подходом "Just 4 fun", вы думаете, все сложиться гуд, и проект не сольется через 3-4 месяца разбирания, переписывания тру механики? Каждый когда-то "ломается", всем рано или поздно становиться "впадлу", ибо
1) это не благодарное дело работать на шару.
2) Да просто зае***ь.
3) уникум ЧП.
This is fact of life.
P.S. Кого обидел, либо вызвал пукановзрывательную реакцию, заранее извините плызочки, никого не хотел ... :redlol::redlol::redlol:.
Сообщений: 252
Тем: 2
Зарегистрирован: Mar 2012
Репутация:
902
Я думаю, что у некоторых сложилось немного ложное представление о приоритетах и ресурсоемкости задач. Нам есть чем заняться, определенно, С4 - просто старт для opensource решений. Были мысли опубликовать и HF под MIT, посмотрим, что получится на данной итерации. К тому же, ряд задач переоценен - скажем, та же миграция с Ant'a до сих пор не сделана в l2j (как и сплит LS/GS, о котором я читал еще в 2013, кажется, а работы, по факту, на час).
Что касается механики - безусловно, все непросто. К тому же, у нас нет человека со скиллами RE, поэтому этот вопрос не так очевиден. Но ничего, со временем, думаю, найдется решения и для этого момента.
А что касается благородности opensource - тут каждый видит свои плюсы и минусы сам) Для меня это не есть неблагородное дело.
P.S. Да, что касается "надоест" - опять же, смотря что видеть в таких решениях. Я уже давно не developer, например, и по роду деятельности занимаюсь другими делами, а dev - это хобби, которое не надоедает. К тому же, даже внутри команды есть необходимая самодостаточность для обмена опытом и некоторого проф гейна. Мы все разные по профилю компетентности, есть чем поделиться работая над opensource. Если соберется хоть небольшая экосистема - отлично, нет - тоже не так страшно)
Всем спасибо за комментарии!
Сообщений: 252
Тем: 2
Зарегистрирован: Mar 2012
Репутация:
902
Обновим новости. Дело не стоит на месте, хотя пока что все движется в спокойном вечерне-кодинговом темпе. Итак, из основных нововведений:
- Продолжение интеграции с Spring, добавление связки Spring/SpringData JPA/Hibernate (JPA impl)
- Реализация с нуля retail-like CommunityBoard, использование JTwig (templating), четкое разделение на Service/DAO/Model слои
- Незначительный рефакторинг кода, Java8 местами
Немного деталей.
1. Spring/SpringData JPA/Hibernate
Такой зоопарк позволяет очень быстро решать задачу создания четко определенного DAO-уровня. Hibernate здесь выполняет роль имплементации JPA2. Кто сталкивался с этой темой, думаю, сразу поймет в чем плюс, в качестве примера можно привести реализацию DAO для вкладки Memo (заметки) в CB:
Код: public interface PlayerMemoDAO extends JpaRepository<PlayerMemo, Long>
{
List<PlayerMemo> findAllByPlayerIdOrderByCreateDateDesc(int playerId);
Optional<PlayerMemo> findByPlayerIdAndTitle(int playerId, String title);
}
Вы спросите "А где же имплементация и базовые CRUD-операции?" - ответ прост: все делает SpringData, достаточно только заэкстендить интерфейс JpaRepository, все остальное сделает фреймворк. Потребуются дополнительные (отличные от простых CRUD-методов) методы? Достаточно дописать в интерфейс нужные сигнатуры функций. Идея в том, что фреймворк разбирает название функции и генерирует нужный код. Например, findAllByPlayerIdAndTitle делится на: - findAll - аналог SELECT *
- By - аналог WHERE
- PlayerIdAndTitle - аналог player_id = ? and title = ? , значения берутся из аргументов
Ну и, разумеется, нужна модель PlayerMemo с разметкой JPA.
Не будем вдаваться в детали как это работает "под капотом", если интересно узнать подробности, то все очень детально описано в retail docs: click
Помимо высокого уровня абстракции есть еще один неявный плюс - оформление кода. Такой подход к написанию DAO заставляет четко отделять мух от котлет. Такого мусора, как в L2PcInstance (заменить на нужное, справедливо для всех кодов из шары) не получится. Т.к. в интерфейсе можно использовать только одну модель, то возникает четкое разделение DAO и моделей, что очень удобно. Такой элемент самоорганизации, так скажем.
2. Community Board
Взглянув на то, что есть в шаре, еще раз, стало понятно, что проще все выкинуть, нежели чем пытаться что-то поправить (опять же смотрим выше - DAO/Service как таковых нет, все в одной куче). В этом пункте можно выделить несколько подпунктов:
2.1. Tempaltes
Скажем так, делать конкатенацию строк контента в коде - слегка моветон. Когда возникает ряд состояний и повторяющихся конструкций - это моветон вдвойне. К тому же, представление сильно мешается с контроллером, что совсем плохо. В итоге на помощь приходит шаблонизация. Вариантов тут довольно много, можно брать как logic-less (e.g. Mustache), так и logic-full (e.g. FreeMaker, JTwig) решения. Конечно, более привлекательно для данных задач выглядят вторые. В итоге выбор пал на JTwig как наиболее приятный по идеологии. JTwig позволяет решать 99% задач, возникающих по ходу дела, те, что не решаются из коробки, можно доделать через расширения (доп. функции). Из основных удобств:
- Structured layouts (наследование, включения и пр.)
- Циклы, управление (if/else, foreach etc.)
- Передача любых переменных, доступ к полям\методам (тут + немного рефакторинга уже от нас, чтобы была возможность работать с static-методами и переменными)
- множество built-in функций для решения различных задач при работе со строками, датами, константами, массивами и пр.
На примере это выглядит так (ниже только часть шаблона):
Код: {% for memo in memos|slice(itemsPerPage ** (page - 1), itemsPerPage) %}
<tr>
<td FIXWIDTH=5></td>
<td FIXWIDTH=415><a action="bypass _bbsmemo:action:read:memoid:{{ memo.id }}">{{ memo.title }}</a>
</td>
<td FIXWIDTH=70 align=center></td>
<td FIXWIDTH=120 align=center>{{ formatter.format(memo.createDate) }}</td>
</tr>
{% endfor %}
Здесь memos - список заметок игрока, itemsPerPage - кол-во страниц для вывода на страницу (paging). Таким простым образом выводится список всех заметок (за основу layout'a взят PTS).
Из дополнительных плюсов стоит отметить довольно сильную поддержку в IntellijIDEA и высокую совместимость с оригиналом (Twig, PHP).
Также отмечу, что имплементации Twig в Java-мире, как минимум, две. Про используемый нами можно почитать тут: http://jtwig.org. Также есть Pebble. Принципиальная разница в том, что JTwig использует PG Parboiled. В общем, весьма интересная штука, для собственного развития однозначно стоит посмотреть (в том числе в части Parboiled).
2.2. Refactoring
Так как все с чистого листа, то рефакторинга, как такового, не случилось, но все же возник ряд интересных, на мой взгляд, моментов и решений. Первое - это соглашение о формировании bypass'ов. Кто видел оригинал PTS, явно отметит, что это ужас. К примеру, что можно найти на той же вкладке memo: - _mmcrea
- _mmlist_2_
- _mmlist_1 (почему нет подчеркивания - а черт его знает)
- Write 5 -2 0 Search _ _
- _mmmodi_1
- _mmdele_1
Во-первых, читаемость таких bypass'ов, скажем так, не лучшая. Во-вторых, весьма сложно структурировать потоки данных, придется еще сгородить огород. Выход позаимствован из нашей HF работы, он довольно громоздкий, но решает массу задач. Пример bypass'a:
Код: bypass _bbsmemo:action:delete:id:1
Что и как здесь работает? Первая часть _bbsmemo всегда одна в рамках менеджера (например, в рамках одной вкладки или раздела). Это решает ряд проблем с костылями, которые были раньше. Теперь создается менеджер крайне просто:
Код: @CommunityBoardHandler(bypasses = "_bbsmemo")
public class BBSMemoManager extends AbstractCommunityBoardHandler
{
@Override
public void processBypassInner(L2PcInstance player, String action, Map<String, String> params, boolean write)
{
}
}
в processBypassInner прокидываются все команды, начинающиеся с _bbsmemo. Одна точка входа, что очень удобно. При этом Write-команды приходят сюда же. Далее определяется enum с нужными Action'ами (как минимум INDEX). Возвращаясь к bypass - action:delete как раз отвечает за нужный Action. Как вы уже могли догадаться, после идут параметры в виде пар ключ-значение. Опять же, это громоздко, но очень удобно, читаемо, легко рефакторится и сопровождается.
Вторая часть - это то самое четкое разделение на DAO/Service. Теперь никакого бардака, менеджер BBS отвечает только за прием\обработку байпассов, делегирует работу в сервис, там происходит вся кухня и работа с DAO. И все это завязано на IoC, что очень удобно.
3. Прочий рефакторинг, Java 8
По мере работы так или иначе попадается мусор (точнее, попадается он всегда, потому что абсолютно все ужасно, от оформления (начиная с эстетики в виде переменных с подчеркиваниями вида __value и заканчивая архитектурными бедами вида L2PcInstance на 10+к строк).
Небольшой пример до-после для загрузки территорий:
Было:
Код: public static Integer[][] get2DIntArray(String[] resultFields, String usedTables, String whereClause)
{
long start = System.currentTimeMillis();
String query = "";
Integer res[][] = null;
java.sql.Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
query = L2DatabaseFactory.getInstance().prepQuerySelect(resultFields, usedTables, whereClause, false);
PreparedStatement statement = con.prepareStatement(query);
ResultSet rset = statement.executeQuery();
int rows = 0;
while(rset.next())
rows++;
res = new Integer[rows - 1][resultFields.length];
rset.first();
int row = 0;
while(rset.next())
{
for(int i = 0; i < resultFields.length; i++)
res[row][i] = rset.getInt(i + 1);
row++;
}
rset.close();
statement.close();
}
catch(Exception e)
{
_log.error("Error in query '" + query + "'", e);
}
finally
{
try
{
con.close();
}
catch(Exception e)
{
}
}
if(_log.isTraceEnabled())
_log.trace("Get all rows in query '" + query + "' in " + (System.currentTimeMillis() - start) + "ms");
return res;
}
Код: public void reload_data()
{
_territory = new FastMap<>();
Integer[][] point = SqlUtils.get2DIntArray(new String[]{"loc_id","loc_x","loc_y","loc_zmin","loc_zmax","proc"}, "locations", "loc_id > 0");
for(Integer[] row : point)
{
// _log.info("row = "+row[0]);
Integer terr = row[0];
if(terr == null)
{
_log.warn("Null territory!");
continue;
}
if(_territory.get(terr) == null)
{
L2Territory t = new L2Territory(terr);
_territory.put(terr, t);
}
_territory.get(terr).add(row[1],row[2],row[3],row[4],row[5]);
}
}
Стало:
Код: @PostConstruct
public void reload()
{
log.debug("Loading territories.. ");
territories = new ConcurrentHashMap<>();
try (Stream<TerritoryPoint> allAndStream = territoryDAO.findAllAsStream())
{
Collector<TerritoryPoint, L2Territory, L2Territory> downstream = Collector.of(
(Supplier<L2Territory>) L2Territory::new, L2Territory::addPoint, L2Territory::merge);
territories = allAndStream.collect(Collectors.groupingBy(TerritoryPoint::getId, ConcurrentHashMap::new,
downstream));
}
log.debug("{} territories loaded", territories.size());
}
+ интерфейс уже известного JpaRepository, еще 5 строчек, приводить не буду.
SpringData JPA закрыл этот жуткий ужас всего несколькими строками, Java 8 Stream API отлично решил задачу группировки (с простым кастомным коллектором). Помимо украшательств, тут же ушла и ошибка, допущенная в SqlUtils, которую глазом не сразу и заметишь (к вопросу об уровне абстракции и почему рутина - не всегда хорошо).
Резюме
Вот такая вышла ночная повесть, надеюсь, не слишком утомительно. Предвкушая вопросы вида "зачем так тяжело", "почему столько !@#$ enterprise-огородов", "зачем оно под хайлоад" и пр. отмечу несколько субъективных убеждений: - L2 в текущем состоянии уже не хайлоад. С4 - тем более
- Оригинальный код ~2005-2006 года, сейчас 2015. За 10 лет деревья стали-таки зеленее, а вычислительные мощности доступнее и производительнее - сейчас уже можно не особо переживать о том, что приложение отточит пару лишних Gb памяти. Конечно, это этом нужно думать, но не так, как десять лет назад
- Производительность - это вопрос как палка о двух концах. Конечно, такие решения - это лишний оверхед. Но, во-первых, см. п2, во-вторых - если поставить на весы скорость разработки, гейн и перфоманс, то далеко не факт, что написав в 5 раз больше кода получится хотя бы в два раза более быстрое решение. Яркий тому пример - как раз этот код. Вся эта рутина ничего не стоит, когда лажают на простых вещах, не говоря уже о Concurency. По моему сугубо личному мнению, значительно эффективнее сначала прототипировать, потом оптимизировать. Вооружившись профайлером, можно эффективно проработать узкие места и переписать все ботлнеки.
Такие новости к 3 утра. Да, ну и правки конфигов, разумеется!
До скорого!
Сообщений: 2,455
Тем: 53
Зарегистрирован: Apr 2010
Репутация:
19,728
Почему именно jtwig? В java-мире есть еще куча других шаблонизаторов, как пример - Velocity, который я использую. Меньше наворотов, легче синтаксис и все нужные вещи из коробки.
m0nster.art - clear client patches, linkz to utils & code.
Гадаю по капче.
Сообщений: 6
Тем: 1
Зарегистрирован: May 2015
похвальное начинание, моя молодость)
Сообщений: 252
Тем: 2
Зарегистрирован: Mar 2012
Репутация:
902
05-12-2015, 11:16 AM
(Сообщение последний раз редактировалось: 05-12-2015, 11:43 AM ProDev.)
Pointer*Rage Написал:Почему именно jtwig? В java-мире есть еще куча других шаблонизаторов, как пример - Velocity, который я использую. Меньше наворотов, легче синтаксис и все нужные вещи из коробки.
Шаблонизаторов, действительно, очень много, выбрать нужный не так непросто, соглашусь. Почему именно JTwig? Есть ряд доводов, часть из них, скрывать не буду, довольно субъективные:
- Функциональность и расширяемость - богатый набор built-in функций, если не хватает - очень быстро пишутся расширения, что позволяет удачно переносить view-логику в шаблон;
- Совместимость с HF - немаловажный фактор. Часть шаблонов (например, те же пагинаторы на страницах списка заметок и кланов) можно заимствовать практически as-is;
- Синтаксис - заимствован из Twig, это не столь важно, но все же упрощает редактирование шаблонов другим участникам команды, кто работал с twig'ом в мире php. Хотя это капля в море при выборе решения, конечно, но некоторый плюс дает;
- - Parboiled. Опять же, это больше субъективизм, но очень нравится весьма элегантный, на мой взгляд, подход. С точки зрения потребителя никакого значения не имеет, но если хочется покопаться "под капотом" (что мы иногда и делаем), то это некоторый приятный бонус.
Upd: забыл упомянуть еще один приятный бонус - интеграция с Spring MVC. Непосредственно к c4 отношения, конечно, не имеет, но опять же вопрос унификации - удобно, когда в ряде проектов один и тот же шаблонизатор, можно эффективно повторно использовать часть шаблонов.
Velocity много не использовал, но все же думаю, что он +- решит те же задачи. По поводу синтаксиса - думаю, что примерно одинаково, все субъективно, Velocity выглядит более лаконично, но разница не столь велика, как мне кажется. К тому же, хорошая поддержка в IDE нивелирует эту особенность.
Да, и еще одна деталь, о которой я забыл упомянуть в предыдущем посте. Такой подход дает заметно больший объем на выходе (переносы строк, выравнивание и пр.). Но когда шаблон вырастает до ~100 строк, использовать подход вида "запишем все в одну строчку без отступов" (который так любят во многих решениях) уже неприемлемо. В итоге на помощь приходит HtmlCompressor - маленький, но очень полезный инструмент. В зависимости от шаблона его эффективность (сохраненный объем) может быть очень высока, статистику не собирал, но по логам примерно 30-60%. Работает очень быстро, никакого ботлнека не возникает, что тоже приятно.
Сообщений: 78
Тем: 16
Зарегистрирован: Mar 2013
Репутация:
143
Вы не поверите, но в этом году у меня так же возникла мысль: "а почему никто на Java так и не допилил сервер хроник C4?" Все команды, которые когда-либо пытались что-то сделать - опускали руки не доделав. Те, кто пытался опустить Interludе до С4 так же бросали это дело не закончив.
С полгода назад поискав что-то стоящее - ничего не нашел. А в этом году на глаза попался (совершенно случайно) форум http://java-build.ru/ и я понял - есть еще надежда, ведутся работы! Я в Java-коде толком не смыслю, но датапак (в том числе html) править умею, руки растут с нужного места. Хотел внести свою скромную лепту в этот проект, но не смог зарегистрироваться на том форуме (на мыло не приходит ссылка активации). Но думаю с доступностью PTS сервера и его датапака моя помощь врят ли понадобится.
Искренне Желаю Вам удачи и терпения в реализации этих многими любимых хроник!
Сообщений: 1,240
Тем: 29
Зарегистрирован: May 2013
Репутация:
2,505
ntking Написал:Вы не поверите, но в этом году у меня так же возникла мысль: "а почему никто на Java так и не допилил сервер хроник C4?" Все команды, которые когда-либо пытались что-то сделать - опускали руки не доделав. Те, кто пытался опустить Interludе до С4 так же бросали это дело не закончив.
С полгода назад поискав что-то стоящее - ничего не нашел. А в этом году на глаза попался (совершенно случайно) форум http://java-build.ru/ и я понял - есть еще надежда, ведутся работы! Я в Java-коде толком не смыслю, но датапак (в том числе html) править умею, руки растут с нужного места. Хотел внести свою скромную лепту в этот проект, но не смог зарегистрироваться на том форуме (на мыло не приходит ссылка активации). Но думаю с доступностью PTS сервера и его датапака моя помощь врят ли понадобится.
Искренне Желаю Вам удачи и терпения в реализации этих многими любимых хроник!
Опять реклама конфиг билдеров?
R7u195 - 15/01/2015
Цитата:- Игрок не может использовать какие-либо итемы если на нем висит эфект Fear
R8u2 - 23/03/2015
Цитата:- Нельзя использовать банки когда на игроке висит эффект Fear
Ну если что-то переписывать, то нормально. А так костыль на костыле.
Родился, живу и когда-нибудь умру.
Сообщений: 555
Тем: 2
Зарегистрирован: Feb 2011
Репутация:
1,507
Donatte, не надо палить контору! само по себе исправления подобного навыка в "23/03/2015" просто абсурдно
Сообщений: 78
Тем: 16
Зарегистрирован: Mar 2013
Репутация:
143
Donatte Написал:Опять реклама конфиг билдеров? Не понял о чем ты, если честно, но не о какой рекламе и в мыслях небыло.
Приятно видеть, что легендарные (в моем понимании) игры не забыты и по ним ведется работа.
Даже если их надолго не хватит "ходить по граблям", будет серьезный задел для желающих продолжить это дело.
|