-
Content Count
12 -
Joined
-
Last visited
Community Reputation
0 Neutral-
Если кому то нужно. Вытащил формулы полета стрелы и эффектов из Dalam World.
-
Ждем
-
Так как в Dalam World дают бонусы за посты на форуме, решил вам красивые арты по игре поскидывать ))
-
Ура-ура. Наконец Valhalla выводят хотя бы в инкубатор. Я 16 лет ждал Project Valhalla и наконец они дотащат это:) Очень жаль, что в 2027 году только, так как уже есть необходимость value-классов, хотя бы, в той же разработке l2j: инлайн структур в класс. А пока приходится ограничиваться record-классами, как точками, которые будут потом заменены на value. В конце концов: не загружать же отдельные сборки JVM с поддержкой value-классов, верно? Тем более, что работать они могут, кхм, несколько нестабильно:)
-
Решил я тут посмотреть очень древние версии L2J (когда они еще не переехали на свой собственный svn/trac). По таймлайну это где-то середина нулевых годов. Какого же было мое удивление, что довольно большую часть систем, которые еще используются почти во всех l2j-форках - спроектировал и написал один человек. Да-да, в L2J когда-то был архитектор - maximus / mkizub и он же Wooden. Причем, судя по тому, что L2J хостился на ныне умершем opensvn - он скорее всего, еще и лидил это все дело. В любом случае, на opensvn оно могло попасть только через Кизуба, т.к. сервис был российским и на русском языке. Я, конечно, и раньше видел его авторство во многих классах, но не мог связать, что это все один человек, а тут, внезапно, связалось. Что же заложил в свое время Кизуб? 1. Базу скилл движка. И я говорю не про обработчики скиллов, а про xml-представление, которое почти 1-в-1 сохранилось по сей день: таблицы, вложенности и прочее. Более того, сюда так же входит все что идет от DocumentBase. 2. Первая версия mmocore (еще до выделения в отдельную библиотеку KenM'ом). До этих изменений ребята дрочили байтики напрямую и использовали блокирующие сокеты. На то время, переход на NIO - был прям прорывом на острие ножа технологий Java. 3. Многопоточка. Пулы потоков и базовая модель исполнения игровой логики из очереди обработчиков пакетов. 4. ... и много другого 🙂 Вот они, настоящие fallen heros 🙂 Хотелось бы увидеть, конечно, как бы выглядел L2J сервер и дальше, если бы он продолжил над ним работать, а не переключился на другие свои проекты. Но имеем, то что имеем.
-
Увидел тут забавный код в jctools библиотеке: byte b000,b001,b002,b003,b004,b005,b006,b007;// 8b byte b010,b011,b012,b013,b014,b015,b016,b017;// 16b byte b020,b021,b022,b023,b024,b025,b026,b027;// 24b byte b030,b031,b032,b033,b034,b035,b036,b037;// 32b byte b040,b041,b042,b043,b044,b045,b046,b047;// 40b byte b050,b051,b052,b053,b054,b055,b056,b057;// 48b byte b060,b061,b062,b063,b064,b065,b066,b067;// 56b byte b070,b071,b072,b073,b074,b075,b076,b077;// 64b byte b100,b101,b102,b103,b104,b105,b106,b107;// 72b byte b110,b111,b112,b113,b114,b115,b116,b117;// 80b byte b120,b121,b122,b123,b124,b125,b126,b127;// 88b byte b130,b131,b132,b133,b134,b135,b136,b137;// 96b byte b140,b141,b142,b143,b144,b145,b146,b147;// 104b byte b150,b151,b152,b153,b154,b155,b156,b157;// 112b byte b160,b161,b162,b163,b164,b165,b166,b167;// 120b byte b170,b171,b172,b173,b174,b175,b176,b177;// 128b Сразу стало понятно, что это борьба с false sharing. Вспомнилось, что в Java когда-то даже ввели аннотацию для автоматического выравнивания памяти - @Contended. Самое забавное, что ее потом тупо выключили для кода, который находится вне бут-лоадера. Функция есть, а воспользоваться нельзя. Почему? Потому-что иди нахрен, вот почему. 😞 Вот и приходится выкручиваться самыми разными способами. Тут разработчики решили вручную забить байты между данными для продюсеров и данными для консюмеров очереди. Поражает в этом во всем только глубокое отрицалово комитета самой Java, где у них не существует false sharing, memory padding и других вещей, которые лежат чуть-чуть ниже уровня самого языка. При этом, в бесконечной попытке ускорить JVM и стандартную библиотеку, разработчики языка понимают все это и вводят механизмы для работы с данными проблемами, но нет, не дают это пользователям языка, ато вдруг везде понатыкают, верно? Зато, бл$!ь, никому не нужная CORBA у них была и они ее поддерживали десяток-другой лет. Печально 😕
-
Вы когда-нибудь сталкивались с критами? Хе-хе, ну мне то не врите, конечно сталкивались. Сегодня я принес поесть небольшую помощь в казуальной отладке клиента игры. Немного предыстории. После очередного куска рефакторинга сервера, нужно было протестировать работу этого всего. И вот, исправляю я ошибки и натыкаюсь на прелестный баг: после создания тестового персонажа и возврата в лобби - игра вылетает с критом: History: IsLoadedResource <- User::SetPawnResource <- NCPawnSelectWnd::AddPawn <- NConsoleWnd::AddCharacterInfo <- d <- CharacterSelectionInfoPacket <- UNetworkHandler::Tick <- Function Name=CharacterSelect <- UGameEngine::Tick <- UpdateWorld <- MainLoop Понятно, что упал он на загрузке каких-то ресурсов, но не понятно каких именно. Пару слов о клиенте. Максимально чистый, прямиком из корейского 2007 года: полностью снята и очищена Themida со всех файлов; пропатчено выключение GG. Максимально из отличий - полностью пересобранные все dat-файлы, но внутри они оригинальные (кроме system-messages, где добавлена пара новых сообщений). О, ну и да, конечно же пропатчены глифы для поддержки русского языка. С такими вводными проблема может быть где угодно: от сервера и до клиента. Начать я решил с клиента. Первым шагом я попытался включить логи через флаг запуска -log - но нихрена. Если он и работает где-то, то точно не на той версии клиента, что у меня. Помучав пару минут нейросеть, она предложила мне добавить в l2.ini такую хрень: [Core.System] PurgeLogs=False SaveLog=True Log=L2.log ... Первый раз такое вижу, но попытка - не пытка... Как оказалось: очень даже пытка - включить эти логи. Если оно не хочет работать, значит ему надо помочь и самому включить логи. Во всяком случае, писать на C++ чуть меньшая пытка:) Вооружившись IDA, CLion и исходниками UE 2.5 - была быстро написана dll-ка на крестах, которая, тупо, сплайсит вызовы FOutputDevice:Log* и сыпет это в консоль. В общем, проблема оказалась в кривом пакете CharSelectInfo. При рефакторинге слетело количество элементов в paperdoll-персонажа, из-за чего структура пакета съехала и в face & hair персонажа приходили очень интересные значения, а клиент радостно пытался их жевать, пока не падал:) А dll-ку с исходниками приложил чуть выше, может кому-нибудь пригодится.
-
Вывод логов клиента: DLL + src ( terminal.zip ) Достаточно просто положить в DalamWorld. Если файл уже существует, то его можно заменить, т.к. orc.dll в новых обновах DW не используется
-
Обнаружил забавный баг в IDEA-плагине Manifold. При использовании интерполяции строк, если сослаться внутри шаблона на метод, класс которого не используется больше, то IDEA подсвечивает импорт этого класса, как неиспользуемый и весело грохает его при оптимизации импортов. Уже отписал Скотту по проблеме:) А для тех, кто не хочет указывать FQN класса в шаблоне строки, пока баг не исправен, есть костыльное решение: просто создать приватный статичный класс с неинициированным полем импортируемого класса.
-
Какой игра должна была быть изначально? Никогда не задумывались над этим вопросом? К счастью, если хорошо исследовать, то можно обнаружить эти следы во всеми нами любимом корейском коде:) В процессе избавления от всеми любимых getInstance синглтонов, то и дело приходится отвлекаться на всякие сторонние вещи, такие, как исправления принципов единой ответственности, да и вообще, архитектурного разделения обязанностей слоев. Логика отъезжает в сервисы, данные остаются в данных или разбиваются на несколько DTO; появляются наметки слоя валидации данных и команд, которые будут затем выведены в полноценное API модулей. В эту же кучу уходят и сетевые пакеты, которые также разрезаются на сериализаторы/десериализаторы и слой DTO-данных. А мы в l2j. Что это значит? А это значит, что часть пакетов состоит из unknown-параметров или магических констант, которые были взяты когда-то из сниффера трафика. Приходится открывать IDA, NetPro (благослови бог savormix <3) и разбираться с этим ужасом. Как раз в процессе копания в этой всей радости, я обнаружил, что когда-то, в очень стародавние времена, планировалась ручная раскидка атрибутов персонажа: STR, DEX, CON, INT, WIT, MEN. Прям, как в нормальных RPG-играх! Следы этого остались в древних пакетах NewCharacterSuccess и RequestCharacterCreate. Первый пакет говорил клиенту, какой диапазон каждого атрибута может быть выбран для каждого начального класса. Еще и с рекомендуемыми значениями! private final List<CharacterTemplate> templates; public static class CharacterTemplate { private final int race; private final int classId; private final Attribute strAttr; private final Attribute dexAttr; private final Attribute conAttr; private final Attribute intAttr; private final Attribute witAttr; private final Attribute menAttr; } public static /*value*/ class Attribute { private final int max; private final int base; private final int min; } Второй же пакет присылал, что там накликал игрок, в процессе создания персонажа, в том числе, его атрибуты. name = readS(); race = readD(); sex = readD(); classId = readD(); intAttr = readD(); strAttr = readD(); conAttr = readD(); menAttr = readD(); dexAttr = readD(); witAttr = readD(); hairStyle = readD(); hairColor = readD(); face = readD(); Такие дела. Чисто теоретически, можно переделать UI создания персонажа и вернуть раскидывание первичных атрибутов персонажа. Пакетка вполне себе это позволяет, движок клиента под капотом эти данные принимает и крутит.
-
На днях решил покопаться в l2j говнокоде, раз уж делать совсем нечего. Вытащил l2hardcore, который с 2024 года не трогал. Каким-то неведомым образом, я обнаружил себя рефакторящим приват-сторы и трейд-листы (и так всегда, хотя делать собирался совсем другое :D). Внутри код наподобие: Который, после выноса логики из модели данных, конечно же, начал принимать на вход TradeList. Synchronized, же, начал лочить уже не объект модели, а синглтон сервиса. Да и вообще, synchronized я не видел уже тыщу лет и раньше лучшим выбором было использовать ReentrantLock, так как он работал шустрее стандартных мониторов Java. А если еще вспомнить про Loom в Java 21+, где мониторы не поддерживаются, то выбор, казалось бы очевиден: просто снести к херам synchronized и заменить на ReentrantLock, который будет валяться в модели. Единственное, что меня основило от такого решения, лишь то что, в CopyOnWriteArrayList я обнаружил использование монитора, хотя раньше там был ReentrantLock, причем с комментарием: "We have a mild preference for builtin monitors over ReentrantLock when either will do". Интересно, да? Вот и мне так показалось. В общем, после гугления оказалось вот что: 1. Мониторы заоптимизировали просто в усмерть - лок скиппинг, лок мерджинг и прочие приколы, и даже была таска чтобы переделать блокировки с ReentrantLock на synchronized 2. Лок монитора по Object lock = new Object() - значительно дешевле по памяти, чем создание и поддержание ReentrantLock 3. Мониторы до сих пор привязываются к карьер тредам (Loom) :( Теперь актуальный юсейдж synchronized выглядит так: 1. Дохрена объектов для синхронизации или важна память 2. Используется только примитивная блокировка 3. Маленькое время блокировки (не IO операции), либо не использовать с Loom Для всего остального - ReentrantLock.