Daily MaverickCLIMATE CASH SHOWDOWN: Africa battles EU ‘delaying tactics’ at COP31 over $120bn climate adaptation lifelinePunch10 killed or missing, 2,000 displaced in Anambra communal clash — NEMASky TG24Spagna, emergenza migranti: quasi 1.500 sbarchi in un giornoInquirerBulusan Volcano logs 438 quakes in 24 hours; eruption threat remainsThe Jerusalem PostYair Golan's Democrats push to repeal Netanyahu's judicial reform attempts in new Knesset committeeZDF heuteAktuelle Pressemitteilungen des ZDFCapital FMChinese musical heritage takes centre stage in Nairobi concertABC NewsUPS plane, Copa Airlines flight collide on taxiway at Miami International AirportSRF NewsKorruptionsermittlungen – Im Wald vergraben: Ermittler finden in Ungarn Millionen EuroStraits Times SportS’pore ref Jansen Foo comes under fire from Ancelotti, Brazil after 3-2 loss to JapanХабрКак работают розыгрыши в Телеграме: как обеспечить лучший охват и честные результатыBollywood HungamaRamayana to release in China, Russia, Japan and South Korea in Q1 2027; film already submitted for censor clearance in China
The Daily Newsstand · Free, Always
Sunday, November 15, 2026

Мультиплеер для интровертов: пишем голосового компаньона для Euro Truck Simulator 2

Translate

В Euro Truck Simulator 2 очень тихо. Мотор, поворотник, навигатор. Можно включить радио, можно позвать друзей в конвой. А можно сделать так, чтобы на пятнадцатом канале кто‑то был.

«Канал 15» — бесплатная программа‑компаньон для ETS2: имитация радиоканала дальнобойщиков. В эфире восемнадцать выдуманных водителей с голосами, характерами, сменами, маршрутами и грузами. Игрок жмёт кнопку на руле и говорит вслух. Ему отвечают.

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

Конвейер: тангента → текст → намерение → реплика

кнопка руля ─► микрофон (буфер 0,4 с до нажатия)
           ─► faster-whisper small, CPU, int8
           ─► классификатор намерений
           ─► колода реплик ─► радиоэффект по дистанции ─► динамики

Всё локально. Голос игрока никуда не уходит — это было условием с первого дня.

Распознавание. faster‑whisper small на CPU, int8, четыре потока. Микрофон открыт постоянно, но пишет только пока зажата тангента, плюс 0,4 секунды до нажатия — люди начинают говорить чуть раньше, чем нажимают. Аудио идёт блоками по 50 мс: двадцать колбэков в секунду вместо ста, 0,8% ядра вместо 2,2%. Мелочь, но рядом работает игра, которой нужно всё.

Модель весит около 2,2 ГБ памяти. Держать её всё время рядом с ETS2 жалко, поэтому она грузится по нажатию тангенты (около 1,7 секунды — успевает, пока игрок произносит фразу) и выгружается через четыре минуты тишины.

Подсказка для whisper. Без неё «кто в эфире?» стабильно превращалось в «кто вы, Хире?» или «кто вы, Сири?». Помогает initial_prompt со словарём канала: «Рация, канал дальнобойщиков. Кто в эфире? Повтори. Приём.» — и позывные всех водителей. Одна строка — и половина ошибок распознавания ушла.

Вторая половина — галлюцинации. На коротких и тихих фрагментах whisper уверенно выдаёт «Продолжение следует…», «Спасибо за просмотр» и «Редактор субтитров». Он учился на субтитрах YouTube и честно дописывает то, что там обычно в конце. Лечится стоп‑листом.

Мёртвый микрофон или тихий человек. Частая жалоба: «рация меня не слышит». Причины две: выбран не тот микрофон (виртуальный, «Стерео микшер») или человек говорит тихо. Отличить можно по разбросу пикового и среднего уровня. Живой микрофон дышит даже в тихой комнате — разброс десятки децибел. Мёртвое устройство — плоская линия, разброс пара децибел. Первому рация говорит «говорите ближе», второму — «выберите другой микрофон».

Намерения

Дальше — классификатор намерений: приветствие, «кто в эфире?», вопрос про конкретного человека, зов того, кого нет рядом, просьба, молчаливое слушание. Это не нейросеть, а основы слов и правила. Главная работа здесь — не точность, а то, что делать, когда не понял.

Колода вместо генерации

Все реплики озвучены заранее, на лету ничего не синтезируется. Отсюда ограничение: в общей версии игрока не зовут по имени — его имени в звуке просто нет.

Эфир собирается из «колоды» с защитой от повторов: у реплики есть вес, время последнего проигрыша и счётчик. Байки идут цепочками: водитель может начать историю сегодня и закончить через пару рейсов. Сейчас в общей сборке больше трёх тысяч звуковых файлов.

Слышно только тех, кто рядом. У каждого водителя своя смена и маршрут по 382 городам. Чем дальше водитель, тем хуже сигнал: радиоэффект накладывается по дистанции, и на краю зоны голос тонет в шипении.

Граф и дружба

Между водителями есть граф знакомств: кто кого знает, кто с кем в ссоре. С игроком — шкала дружбы: от сдержанного «ну, здорово» до приглашения на свадьбу к брату. Порог «знакомого» — 35 очков.

Плохие дни и ссоры сделаны специально. Если все всегда добрые, выходит сироп, а тепло чувствуется только рядом с плохими днями.

Пришлось закрыть и накрутку: дружба росла от перезапусков программы и от пустых ответов. Теперь пустой ответ даёт ноль очков.

Грабли

0xc0000374. Рация падала молча: ни в логе, ни в журнале ошибок — процесс просто исчезал. Код 0xc0000374 — повреждение кучи, падение внутри winmm.dll, стек ведёт в никуда, воспроизводится не у всех. Закономерность нашлась по датам в дампах: падение совпадало с отключением USB‑руля во время опроса кнопок через joyGetPosEx. Исключение рождается в нативном коде, Python‑шный try/except его не видит. Лечение — опрос кнопок через SDL (pygame): там отвал джойстика приходит событием, а не крашем.

«Нет данных». Первая версия на «кто в эфире?» отвечала роботом: «Нет данных». Честно — в зоне никого. Но пользователи читали это как поломку. Робота уволили: теперь в пустом эфире отвечает водитель с дальнего края зоны, в своём характере.

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

Ремарки вслух. В тексты реплик вставлялись ремарки вроде «смеётся». Часть из них голос прочитал словами. Нашли так: прогнали весь эфир, 639 строк, обратно через whisper и поискали ремарки в распознанном тексте. Нашлось 46 строк. Переозвучили.

Телеметрия «blocked, код 2». Иногда Windows не пускает сторонний процесс к memory‑mapped файлу игры. Для игрока это выглядит как «рация молчит». Лечится перезапуском игры. Почему именно так — вопрос в комментарии, буду рад версиям.

Зачем

Мне хотелось место, где тебя помнят и тебе рады, но ничего от тебя не требуют. Никаких счётчиков «дней подряд»: вернулся через месяц — тебе рады. Вокруг люди, разговор идёт, а отвечать не обязательно. Получилось что‑то вроде мультиплеера для интровертов.

Вопросы к инженерам, ради которых я это и пишу: как бы вы отличали обращение к водителю от разговора игрока с кем‑то в комнате? И что вы делаете с галлюцинациями whisper на коротких фрагментах, кроме стоп‑листа?

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.