Лисп в изгнании
224 subscribers
137 photos
21 videos
5 files
225 links
Авторский канал на околоайтишную тематику.

По всем вопросам @awkravchuk
Download Telegram
#common_lisp

Меж тем в воскресенье в Тбилиси прошёл митап по функциональщине, на котором был крутой доклад про оптимизацию кода на Common Lisp от Димы Игнатьева, широко известного в узких кругах как love5an — благодаря его троллингу в начале 10-х я заинтересовался лиспом)) Из доклада даже я вынес для себя что-то новое 😊

Ссылка с таймкодом вот
#лытдыбр #common_lisp

Ну штош, сегодня дочитал The Art of MetaObject Protocol (точнее, дошёл до того места, где эта книга перетекает в нудный справочник по MOP), а вчера на практическом опыте (см. рис. 1) убедился, что скорость доступа к слотам CLOS-объектов такая же (если не выше), как и скорость доступа к слотам defstruct-структур, хотя я всю жизнь думал, что слоты объектов медленнее 🤯 Да даже документация к SBCL утверждает, что

> The cost is roughly 1.6 times that of an open coded structure slot accessor.

Причём, что интересно, этот вывод верен как минимум для трёх компиляторов — SBCL, CCL и Franz Allegro ©® CL, я проверял)

Получается, что затеянный рефакторинг моего ECS-фреймворка не только упростит его код и решит проблемы с переопределением компонентов при работающих системах, но и с точки зрения производительности не сделает хуже — по крайней мере, если отталкиваться от нарисованного у меня в голове плана этого рефакторинга; а как известно, в бою первым гибнет план боя 😅

В общем, осталось найти время и силы на то, чтобы перелопатить свой код 😁
This media is not supported in your browser
VIEW IN TELEGRAM
#лытдыбр #common_lisp

Итак, после полутора недель возни переделал внутрянку своей ECS-библиотеки на использование CLOS-классов вместо структур для добавления возможности переопределения компонентов на лету, во время работы систем, но мёрджить пока рано — есть целый ряд мелочей, которые хотелось бы улучшить, да и тесты проходят только на двух компиляторах, SBCL и CCL, с другими нет-нет, да что-то отвалится 😅 Надеюсь, хотя бы до НГ успею зкончить эту уже поднадоевшую задачу)
#common_lisp #лытдыбр

На новый год мейнтейнеры SBCL решили в качестве подарка пользователям не уступать традиции выпускать по новой версии каждый месяц и выпустить новую юбилейную версию 2.5.0, а у меня, как обычно, обновились соответствующие docker-образа для геймдева. Правда, фикс проблемы, из-за которой на особенно сложных окнах в моей GUI-либе cl-liballegro-nuklear SBCL крэшится с внутренней ошибкой, попадёт только в следующую версию (его закоммитили буквально через несколько часов после релиза), а это, считай, в феврале. Ну да ничего, есть много других вещей, над которыми нужно поработать в следующем году 😊
#лытдыбр #common_lisp

Ну штош, праздники плавно подходят к концу, и я наконец доделал фичу в своём ECS-фреймворке на CL, которую начал ещё в прошлом году 🌚 А именно, определение внутренних Struct-of-Arrays хранилищ данных компонентов через defclass, а не defstuct, что позволяет гораздо проще и без багов переопределять компоненты "на лету", прямо во время работы систем, а именно — добавлять/удалять новые поля в компонентах и менять их типы. Как сообщает git, 533 additions и 307 deletions, заняло гораздо больше времени, чем я рассчитывал, но результатом доволен.

Сначала я вообще хотел навертеть там мьютексов, и даже выяснил, что захват мьютекса в SBCL занимает всего 2 тысячных миллисекунды, но потом я узнал о таком великолепном механизме CLOS, как UPDATE-INSTANCE-FOR-REDEFINED-CLASS, который позволяет кастомизировать процесс обновления существующих инстансов классов в соответствии с новым определением класса, причём этот механизм работает лениво, т.е. обновление происходит только при первом обращении к инстансу, получается, мьютекс не нужен 😊 Самым тяжким, наверное, было заставить этот механизм работать одинаково под всеми шестью поддерживаемыми мной реализациями Common Lisp, потому что стандарт стандартом, но в мелочах они часто отличаются.

Ещё у меня в коментах спрашивали, что там с производительностью, так вот, буквально сегодня утром закончил замеры — в бенчмарке создаётся 10к объектов с тремя компонентами, и затем 10к раз вызывается (через run-systems) система, обращающаяся ко всем трём компонентам и делающая с ними нехитрую арифметику с тригонометрией. Выяснилось, что замена хранилищ данных на классы замедляет скорость работы буквально в рамках погрешности, на пару процентов 🎉 Более того, я закодил так, что в релизном варианте (при добавлении кейворда :ecs-unsafe в *features*) данные хранятся по-старому, в структурах. По ходу дела я также выяснил, что этот релизный вариант всего процентов на 5-6 быстрее не-релизного варианта, который по умолчанию.

В общем, наконец с этой задачей окончено, можно двигаться дальше, есть много планов на этот год, включая попытку в коммерческий релиз игры на Common Lisp 🤩
#лытдыбр #common_lisp

Между делом тут запилил в ECS-фреймворке давно напрашивавшийся рефакторинг — позаменял все глобальные переменные на те, которые предоставляет библиотека global-vars — они почти как настоящие лисповские переменные с динамической областью видимости, только быстрее, потому что шарятся между тредами, как в какой-нибудь прямолинейной C-шке и всегда являются bound, т.е. у них всегда есть значение. В итоге небольшая система move, для которой я хвастался дизассемблерным листингом в туториале по ECS, занимавшим 210 байт, теперь ужалась до 169 байт стройного и прямолинейного ассемблерного кода! 🎉 Хотя тут, судя по всему, и разработчики компилятора SBCL постарались, он как будто более уверенно обращается с переменными с плавающей запятой.

В общем, пытаюсь отвлечься от традиционного ежегодного бюроктатического ада с ВНЖ, как могу 😅
#лытдыбр #common_lisp

Не далее, чем сегодня утром, в лисповый биндинг cl-liballegro замёрджили мой пулл-реквест с макросами, упрощающими доступ к полям структур из liballegro — ещё один пунктик из TODO-списка в постмортеме к моему первому рогалику выполнен 😌

Автор библиотеки мне ещё по ходу дела накидал фидбека, так что в итоге совместными усилиями получилась вообще красота, теперь вместо чудовищного

(print (cffi:foreign-slot-value mouse-state '(:struct al:mouse-state) 'al::buttons))


можно просто и красиво написать

(al:with-mouse-state-slots () mouse-state
(print buttons))


😊
#лытдыбр #common_lisp

Вчера вечером закончил с пачкой давно назревших изменений в Docker-образе для сборки лисповых игр под Windows и Linux, docker-lisp-gamedev:

• бампнул версию компилятора SBCL до 2.5.1, в которую попал фикс моей проблемы со слишком зубодробительными макросами для UI;
• сделал сборку из исходников для линуксовых middleware-библиотек (liballegro, raylib и SDL2), чтобы не зависеть от мейнтейнеров убунты, и чтобы их версии и флаги компиляции плюс-минус совпадали с виндусовскими;
• наконец, самая мякотка — сделал автоматическое тестирование собранных Docker-образов посредством костылей, мусора и веточек pipewire и Xvfb, во всех вариациях ОС и middleware, аж целая матрица получилась 😎

Ещё вчера вечером чинил отвалившуюся сборку под MacOS в CI, но это уже другая история 😅

Так что теперь бампать версии софта внутри контейнера я могу одним лёгким движением руки, и если что-то где-то отъебнёт, я тут же про это узнаю и быстро, решительно починю. Обожаю возиться с автоматизацией сборки софта ☺️
#лытдыбр #common_lisp

Небольшой сник-пик новой библиотеки, над которой я работал последнюю пару недель и уже причёсываю для того, чтобы выложить в паблик. Кто пользовался этим веб-интерфейсом (для взаимодействия с которым библиотека), наверняка вздрогнул, увидев скриншот, такое не забывается 😅
#лытдыбр #common_lisp

Ну штош, отболев традиционную зимнюю ОРВИ, я наконец добил проект, который пилил пол-февраля, необходимый для отчётов об ошибках в играх: окошко "Hey guys, we got a big error here" со стек-трейсом — это, конечно, прикольная пасхалка, но рядовой пользователь никогда в жизни не будет его скриншотить, а тем более ещё искать, куда отправить. Шынмера для таких целей запилила целое своё серверное приложение по имени Feedback и клиент к нему в рамках своего движка Trial, увидев которые, мой внутренний software engineer немножко умер внутри, потому что же уже миллион лет существует готовое решение под названием Sentry, специально предназначенное для сбора ошибок в программах на огромном количестве языков, которое можно селф-хостить, а можно использовать в облаке бесплатную версию с довольно щедрыми лимитами.

Более того, я даже нашёл неофициальный клиент для Sentry на Common Lisp, под названием cl-sentry-client, но убедился, что для сдампанных в выполняемые файлы Lisp-программ он показывает довольно бесполезные стек-трейсы, а это чуть ли не главное, что нужно для понимания сути ошибки. Посмотрел ему под капот, и немножко умер внутри ещё раз — он, на секундочку, тащит зависимостью Swank, лисповую часть плагина к Emacs для работы на Common Lisp, просто для того, чтобы получать стек-трейсы (но всё равно обсирается, потому что расположение исходных файлов при сборке не обязательно совпадает с расположением исходных файлов на машине, где программу запускают, их там вообще скорее всего не будет). Поэтому я затеял проект по написанию полноценного Sentry-клиента на Common Lisp, который бы сохранял прямо в сдампанном образе все нужные исходники и заодно поддерживал бы нужные мне фичи протокола Sentry, вроде отправки файлов и пользовательских комментариев. Прошу любить, жаловать и ставить звёздочки: lisp-sentry 😊

Теперь ничто не мешает приступить на выходных к джему 7DRL, который начнётся уже в эту полночь по UTC 🙈
#лытдыбр #common_lisp #проекты

Между делом в рамках подготовки демо будущей игры (это уже третья итерация рогалика, лол) напилил в своём ECS-микрофреймворке для лиспа новых крутых фичей: хелпер-функции для сброса состояния компонента на дефолтные значения, макрос DEFENTITY для определения глобальных переменных с автоматически инициализируемыми сущностями, и самая мякотка — генерируемые слоты у компонентов, прямо как в SQL GENERATED STORED, потому что уже надоело городить костыли для автоматического подсчёта номера тайла исходя из координат на экране 🙈 Надо будет разобраться с выкладыванием в Guix и зафейленными тестами, лол, и делать новый релиз 0.7.

Ещё и переписал всю внутрянку библиотеки для деревьев поведения cl-fast-behavior-trees, чтобы было легче менять деревья на лету во время разработки, но эти изменения пока не закоммитил — надо опробовать либу в деле, на демо рогалика 😊

В общем, в планах в ближайшее время сбацать клёвое демо и далее работать над ним, чтобы можно было его показывать незнакомым людям после фразы "а я вообще-то в виде хобби видеоигры разрабатываю" 😁
#common_lisp

Меж всем тем, в январе этого года тихо и незаметно вышла новая версия самой распространённой middleware-библиотеки для создания игр SDL, 3.2, которая ломает совместимость с существовавшей уже лет десять SDL2. Биндинги Common Lisp к SDL были традиционно низкого качества и кишели багами и фичами-медвежьими услугами, и вот тут человечек из CL-сообщества подсуетился и сделал бинды к SDL3. Вроде на первый взгляд выглядят неплохо, т.к. написаны, судя по всему, вручную, а не через кривой генератор, как к SDL2. Я-то уже прикипел к менее распространённому middleware liballegro, но cl-sdl3 стоит взять на заметку лисперам-игроделам, привыкшим к обилию туториалов и документации по используемым инструментам 😊
#лытдыбр #common_lisp

А сегодня с утра тихо и незаметно вышла новая версия 0.7 моего ECS-микрофреймворка для Common Lisp cl-fast-ecs. Из крутых изменений, как я уже проспойлерил, макрос DEFENTITY для определения глобальных сущностей, генерируемые слоты, дженерик RESET-COMPONENT и дженерик ASSIGN-COMPONENT. Не обошлось и без поломанной обратной совместимости: функция BIND-STORAGE удалена, вместо неё достаточно вызвать MAKE-STORAGE для инициализации фреймворка; а feature expression :ECS-UNSAFE, добавляющий процентов 5 производительности ценой возможности переопределения компонентов был переименован в :ECS-RELEASE. Соответствующие изменения уже внесены в обе части туториала, а документация теперь всегда соответствует версии библиотеки в репозитории Lucky Lambda 🎉

Теперь можно заниматься дальше деревьями поведения и дёмкой будущего рогалика 😊
#лытдыбр #common_lisp

Наконец закоммитил огромный внутренний рефакторинг своей библиотеки для деревьев поведения cl-fast-behavior-trees. Проверил на практике (в демо нашего нового рогалика, оставайтесь тунцом — завтра, даст Будда, выложу в паблик), работает без сучка без задоринки 😊

Версию библиотеки пока не стал бампать, есть ещё идея, как там ещё чутка соптимизировать, хотя, казалось бы, куда уж дальше — теперь на одно дерево поведения создаётся только один ECS-компонент и одна система, а не целая пачка, как раньше 😅

В общем, происходит буйство перфекционизма))
#common_lisp

Тут ньюсфидом принесло прекрасное: запускающийся прямо в браузере (!) Emacs с подмножеством Common Lisp(!!): https://lisperator.net/s/slip

Можно в приглашение REPL слева вбить что-то в духе (load "examples/clock.lisp"), и оно запустит графическую (!!!) дёмку. В общем, куда техника шагнула, аж дух захватывает 😱

Подумываю иногда о том, что надо бы тоже попробовать для браузера игры делать, но для этого нужно прямо сильно заморочиться с ECL — это пока единственный компилятор, умеющий генерировать WASM, и там это прямо сейчас активно пилят. Поживём-увидим, в общем 😊
This media is not supported in your browser
VIEW IN TELEGRAM
#common_lisp #видео

Надысь тут в Lisp-дискорде человек хвастался своими успехами в геймдеве на Common Lisp с использованием Raylib, не могу не поделиться небольшим, но крутейшим видосом процесса разработки 😊
#лытдыбр #common_lisp

Меж всем тем, на той неделе случилось небольшое эпохальное событие — я переписал код нашей будущей игры в стиле literate programming, придуманном Кнутом, при котором кодовая база по сути является текстом на естественном языке с фрагментами кода, которые из него выдираются и скармливаются компилятору. Выглядит это всё нереально круто (см. рис. 1), а работает посредством пакета cl-org-syntax, сделанного одним из столпов русскоязычного лисп-коммьюнити @akater (подпишитесь на бложек, его лапищщи невероятно мощны).

Насколько мне известно, literate programming для публичного кода на Common Lisp использует примерно человек шесть во всём мире, и половину из них я знаю лично 🤣 В силу редкости работает всё неидеально — требует кастомных патчей на емаксовские пакеты, и даже с ними емакс иногда начинает чудить и по нажатию волшебных клавиш C-c C-c почему-то начинает отправлять код в пекедж cl-user вместо текущего, ну да это не страшно.

В целом это довольно крутой и необычный опыт, сродни TDD на всю голову, в котором сначала пишется тест, а потом уже код, что позволяет тщательно продумать интерфейс кода до его написания. Здесь тоже всё время пытаешься держать в голове, как ты будешь человеческими словами описывать тот код, что сейчас пишешь, и думается от этого явно по-другому. В общем, рекомендую попробовать 😊
#лытдыбр #common_lisp

А пока движется работа над нашей игрой, я потихоньку вношу сопутствующие улучшения в свои лисповые библиотеки для геймдева, например, добавил вот в библиотеку деревьев поведения вспомогательную отладочную функцию для дампа дерева в виде ASCII арта 💅😊
#лытдыбр #common_lisp

Это очередной нытья пост о том, как всё плохо, на этот раз в макоси. Потратил по сути весь сегодняшний рабочий день (см. рис. 1), чтобы сделать сборку игры в обоих вариантах (intel и apple silicon, спасибо хоть, что про архитектуры m68k и PomerPC не надо думать, потому что уже давно отмерли). Даже по ходу дела багу завёл в багтрекере MacPorts доисторическом (Trac, на секундочку), который, сука, у меня почему-то только с тор-браузера открывается. В итоге обкостылил, просто насильно wget-ом и tar-ом устанавливая на Ventura бинарный архив для Monterey. Бинарник-то благодаря этому костылю собрался, но при запуске он вешается на каком-то мьютексе внутрях liballegro (см. рис. 2), видимо, потому, что перемешиваются два разных стандартных рантайма в одном бинарнике, от вентуры и от монтери. Короче, с билдом под интеловые маки придётся продолжать возиться, когда на это будет время 😩

Ну казалось бы, есть у тебя в основе нормальный UNIX, с ядром, спижженным из BSD, как его можно превратить в анально огороженный сад, каковым макось является сегодня — для меня загадка. Реально, при Джобсе было лучше 😡
#лытдыбр #common_lisp

Меж всем тем, вот уже вторую неделю в нашей игре используются шейдеры, пока только для эффекта урона на персонажах, но в дальнейшем будут и для других визуальных эффектов. Финт в том, что я ни разу в жизни не писал шейдеров. Как же я добавил их в игру, спросите вы? Очень просто, с помощью DSL из либы 3bgl-shader, которая позволяет написать код на нормальном, человеческом Common Lisp (см. рис. 1), а затем автоматически транслирует его в код GLSL шейдера (см. рис. 2)! Если это не нереально круто, я тогда вообще не знаю, что означает слово "круто" 😍 Как же я с этого проекта писял кипятком, а когда написал на нём свой первый шейдер, это был вообще улёт 🤯

Сделал, кстати, к либе пуллреквест с добавлением поддержки функций plusp и minusp, вы знаете, куда насыпать лойсов, чтобы автор его побыстрее принял 🌚