Предисловие
В этом блоге я буду рассказывать о том, как я в 3 часа ночи решил разобраться, почему же Тарков такой поломанный?
И раз уж я получил официальную работу, то я смогу с гордостью заявить, что я инженер программист. Хоть моя работа и заключается в программировании микроконтроллеров и мат. моделей, но моё мнение чего-то да стоит.
И важная ремарка — Я НЕ ЛЕЗ В КОД ИГРЫ. Я просто читал логи и документацию к нескольким библиотекам для выяснения «полной» картины мира.
Ну, а теперь Рыба!Автор блога
Логи Таркова, или как их делать не надо
Начнём с формы логов игры Escape From Tarkov. На данный момент (Версия 0.16.1.0.34861) логи представляют собой папку с кучей .log файлов, что содержат сообщения от различных модулей.
Подробнее о каждом:
- Application – содержит информацию об основном процессе программы
- Notifications – содержит информацию о всех уведомлениях, которые приходят во время игры (Исключаем игровые сообщения по типу завершения крафтов или заданий)
- Spatial-audio – логи звукового движка
- Traces – «трассировка событий». Если проще, это подробная запись последовательности действий и изменений состояния в системе
- Network-connection – подключения к серверам
- Network-messages – сообщения об передаче данных (тестовых)
Все сообщения в выше перечисленных логах пишутся по следующей логике:
Дата Время GMT | Версия | Уровень сообщения | тип сообщения | Данные
Вот типичный пример:
2025-02-13 19:01:52.910 +03:00 | 0.16.1.0.34861
| Error | spatial-audio | GO can't be null, can't start occlusion process
А теперь оценим логи. Они не удобные. Если быть точнее, то волнуют две проблемы:
- Избыточность – большинство сообщений дублируются, а некоторые просто не имеют смысла в разделении. Например, network-connection и network-messages можно спокойно объединить потому, что в первом мы пишем «ПОДКЛЮЧЕНО», а во втором «ОТЛИЧНОЕ ПОДКЛЮЧЕНИЕ» (если упростить). Или же spatial-audio, который можно было спокойно кинуть в Application, а notification в traces, ну и так далее.
- Описания – зачастую к данным идут описания в виде json данных или огромные ошибки в 10 – 30 строк. Почему нельзя было написать их в отдельный файл с ссылками, чтобы потом можно было искать через условный Ctrl+F?
А если быть ещё более точным, файл логов должен быть один. Да, тогда вы спросите: как их читать, это же не удобно?! А я отвечу: Log Viewer Plus или же бесплатная версия Log File Viewer. Да, для них не подойдёт «НАШ» формат ввода логов, там нужен более классический и систематизированный «structured logging» (да, такой термин существует :/), который имеет более «табличный» вид:
2023-08-05 09:15:27 ERROR MainApp Ошибка при сохранении данных в базу данных User123
Но если вы внимательно читали, то видели момент об .json описании. Можно подумать, что там в идёт монолитная стена одну строчку (что иногда встречается, но не приветствуется), но нет! Там буквально json с отступами, и ладно если там 5 или 10 строк, я бы мог понять 15, но не 916 (нецензурная лексика). Если что, это было сообщение об начале группового рейда, где описана ПОЛНАЯ информация о всех участниках: кто, с чем, когда, в каком состоянии, ну и там по мелочи.
Теперь поговорим о генерации. Обычно в играх логи могут сохранятся либо динамически, что часто используют в однопользовательских проектах, либо пост-фактум, что можно встретить в онлайн проектах, либо смешанно, когда сообщения идут «партиями». В нашем случае используется первый вариант, к выбору которого, в купе с большим количество одновременно перезаписываемых файлов, есть вопросы, однако это можно понять, если вспомнить о частых вылетах.
Но появляется вопрос:
2025-02-13 19:23:55.839 +03:00 | 0.16.1.0.34861 | Info | network-connection | Send connect (address: 74.119.145.122:17009, syn: True, asc: False)
Они в реальном времени пишут IP сервера, куда ты подключаешься. Интересно, что же будет, если кто-нибудь DDoS кинет! Если судить по логам, то во время игры порт сервера открыт, а это значит, что любой может зайти в рейд, посмотреть в логи, а потом ддосить сервер. Да, возможно, сервер поймёт, что что-то не так, но проверять я это не собираюсь. Однако, сам факт того, что в логах содержится и в реальном времени генерируется столь деликатная информация наводит на определённые мысли.
Поломки, ошибки и вопросы
А теперь самое интересное. Я собрал более 400 лог файлов, что были у меня и моих друзей, благодаря чему получилось собрать график с отношением ошибок к общему числу сообщений.
И тут возникнет вопрос, что это за (нецензурная лексика)? Как это описывать? В некоторых версиях кол-во сообщений об ошибках превышает 80%!
Ну, а если серьёзно, то во время анализа ошибок я заметил, что большинство ошибок будто игнорируются разработчиками (а некоторые, после условного патча, просто заменяются на аналоги). Опираясь на статистику выявлены самые часто появляющееся ошибки (без учёта копий сообщений в других файлах):
- NullReferenceException – ссылка на объект, которго не существует (равен null)
- Can't find way from position to core cover – бот не может построить маршрут к нужной ему точке укрытия
- BitWriterStream::WriteLimitedInt32 Data Loss Error. Min 0, Max 7, Value 8 tag:ToggleTacticalComboPacket0 – вписываемое значение больше допустимого
- Unknown custom item type: 0 – неизвестный тип предмета
- IndexOutOfRangeException – ссылка на индекс в массиве, который выходит за рамки его размерности (для примера: Попытка получения значения номер 10, хотя размер массива 9)
- Already registered object – попытка добавить объект, что уже был добавлен
- KeyNotFoundException – попытка получить значения по ключу, которого не существует. Если не вдаваться в подробности о типах данных, то это ошибка схожа с IndexOutOfRangeException, однако там мы обращались по порядковому номеру, а тут по специальному имени ячейки
- GO can't be null, can't start occlusion process – игровой объект равен null. Да, подобная ошибка уже была, но это ошибка расчёта звуковой окклюзии аудио движка
- SupplyData is null - supplyData равен null. Тут сложно сказать к чему это относится, но предположу, что к системе поиска лута в контейнерах
- No foldable found on … - чаще всего относиться к оружию. Предположу, что это ошибка возникает тогда, когда игра пытается «сложить» оружие, которое не имеет складываемых элементов
Вы заметили один очень схожий «паттерн»? Все ошибки из «топ-10» так или иначе связаны с валидацией данных! Да, классическая и всем нужная проверка данных на то, могут ли они быть использованы, или же стоит запросить данные ещё раз и перепроверить их.
И это подводит нас к другому вопросу: если игра и так работает, то зачем что-то менять? А всё очень просто: скорость, надёжность. Если мы говорим про большие программы, то часто работа сводится к минимизации потерь, как по скорости, так и по ресурсам ПК, и для этого чаще всего добавляют валидацию. В этом случае валидация выглядит как простейшая «таблица», что проверяет данные на правильность. Таким образом, если данные «кривые», то они не участвуют в последующей работе.
Самое интересное впереди: как такую валидацию сделать? В нормальных рабочих программах, как я и говорил, используются таблицы. Самый простой пример — это проверка типа данных при вызове функции. Таким образом код сразу сможет проверить, где и какие типы данных используется, и выдаст ошибку, в случае некорректности. Также могут добавлять if-овые деревья на простейших логических командах сравнения (в идеале), что бы программа могла за счёт незначительного усложнения получить бóльшую стабильность и скорость.
Если разбирать на примерах, то в уже представленных случаях отлично бы подошло следующие:
- if (myObject != null) {} else {…}
- if (agent.CalculatePath(targetPosition, path); …) {agent.SetPath(path);} else {}
- if (value >= 0 && value < 8) {WriteLimitedInt32(value); …} else {}
- if (itemType == 0 || itemType == ‘0’) {} else {…}
- if (index >= 0 && index < array.Length) {var element = array[index]; …} else {}
- HashSet<GameObject> registeredObjects = new HashSet<GameObject>(); if (!registeredObjects.Contains(obj)) {registeredObjects.Add(obj); …} else {}
- if (dictionary.TryGetValue(key, out var value)) {…} else {}
- if (audioSource != null && occlusionObject != null && OculusSpatializer.IsInitialized()) {OculusSpatializer.SetOcclusionEnabled(true);OculusSpatializer.SetOcclusionObject(occlusionObject); … } else {}
- if (supplyData != null) {…} else {}
- if (weapon.HasFoldablePart) {weapon.Fold(); …} else {}
Готово! Это частично исправит положение! Просто впишите за место «…» код, что был раньше и всё! В else можете вписать что-то для исправления данных, но я не разработчик, чтобы в этом разбираться.
И после всего этого возникает вопрос: как я, человек, что пишет на python, C++, maple и mathlab и взявший C# с Unity буквально во время написания статьи, смог что-то придумать, а РАЗРАБОТЧИКИ (нецензурная лексика) нет.
С этого момента у многих людей, как и у меня, должны были возникнуть вопросы к компетенции разработчиков и их проверки качества продукта, что они разрабатывают. Если судить только по этому «топу ошибок», никакой проверки не ведётся! Ну нельзя оставлять ошибки в коде, что появляются ПОСТОЯННО.
Но… ХАХАХАХА! Вы ещё не видели «МАГНУМ ОПУС» разработчиков:
2025-02-13 18:59:40.192 +03:00|0.16.1.0.34861|Error|Default|PlayerBody destroyed without being disposed. Please call Dispose before destroying.
Чтобы вы понимали, это сообщение появлялось 232 раза. И первое её упоминание встречается в версии 0.16.0.1.34481 от 28 декабря 2024. То есть, столь очевидная ошибка находится там уже 3-й месяц! Хотя, не исключаю, что она могла появится в версии .34447, когда происходило обновление Unity.
Проблема в последствиях - «dispose» в Unity используется для освобождения «объектов неуправляемых ресурсов» (к таким относится и playerBody). Подобные объекты могут использовать файлы, сетевые подключения и память абсолютно без контроля. Это делается для того, чтобы объект мог без изощрений использовать сторонние плагины, но из-за этого «автоматический» сборщик не работает, а «dispose» выступает в качестве «мануального» сборщика. Как только этот метод вызывается все данные, связанные с объектом, выбрасываются из памяти чтобы она не заполняла место.
Ещё есть пара интересных ошибок:
- Error insuring item – Ошибка страхования объекта
- Cant find counter for Quest – Не найден счётчик для квеста
Если первое я могу понять - аккаунт старый, некоторые предметы поломались. Но второе нет... Ошибка счётчика квеста? Как?
А это вопрос к валидации данных (да, (нецензурная лексика), опять). Просто, пока рассказывал о «dispose», я решил отвернуться от слона в комнате. Вы и так уже видели огромное кол-во ошибок из разряда: объект не найден или объект равен null. Но как вам это?
- Door with doorId door_Reserve_Base_PTOR_00012 not found!
- FastAccess item 67799795e23b51349807fccd for index Item5 not found
- Item not found: 677945cde05b4721d40f6a7a
- Already registered WindowBreaker's Id …
Да, ошибки WindowBreaker и Item not found уже исправлены, но, как и прежде, это наталкивает на вопросы к разработчикам. У вас есть ETS сервер! Вы на нём ВООБЩЕ, ХОТЬ, ЧТО-ТО ТЕСТИРУЕТЕ? Или просто так, по приколу, пока не (нецензурная лексика)?
Стоит поднять вопрос об исправлении старых ошибок! Вы видели все те ошибки, что я перечислил (во всяком случае паттерны)? Это ошибки почти за 9 месяцев. И знаете сколько из них исправлены? Правильно, две! Те самые WindowBreaker и Item not found.
Ну, если же сравнивать нормально, то за всё время по самым оптимистичным расчётам было исправлено 7373 ошибки, но 1311 из них не были исправлены до конца. При этом за это время, появилось 4586 новых ошибок! Так же стоит учитывать, что под «оптимистичными расчётами» я подразумеваю не сами ошибки, а их «экземпляры». То есть ошибка с двумя разными наборами аргументов будут считаться как две разные ошибки, что, по сути, ошибка одна. Подобное «облегчение» вызвано тем, что некоторые ошибки, просто криво написаны, из-за чего использование какого-то одного метода для парсинга этих «ошибок» весьма затруднено (тратить несколько месяцев на разбор excel таблиц на 10000+ строк «в тупую» ради статьи, я не горю желанием).
И, прежде чем мы перейдём к следующей части статьи, я объясню почему был показан относительный график, а не количественный:
Да, это график. Если вам интересен размер «огромной жёлтой линии», то это 772 422 warn-ов.
Сокрытие и недоработки
Теперь поговорим об «неудобной правде»: ошибок намного больше. Просто, некоторые из них либо не отслеживаются, либо несут более «визуальный характер». К 1-ым относится уже исправленная ошибка с отключением аудио-движка, работа которого просто не отслеживалась. А к визуальным ошибкам и недоработкам чаще всего относятся:
- Кривые границы прогрузки объектов
Думаю, раньше карта имела немного другую геометрию, и данная граница была скрыта, однако после обновления локации она стала видна. - Непрозрачность прозрачных объектов (Не уверен, но вроде это с 0.13.0.0.21469)
Скорее всего вызвана неправильной настройкой материала или же текстур. - Баги текстур
Затрудняюсь ответить в чём именно проблема. Это могут быть как эффекты и текстуры воды, так и неправильная их настройка. - Кривые эффекты тумана, дыма и соответственно затуманивания дальних объектов
- Ошибки синхронизации (по типу уже легендарной 228)
Это проблема сетевого кода, а именно валидации данных. Сервер может понять, где и как произошла ошибка, но он просто не имеет функции «исправления» ошибок. Например, в тех же логах прописано, что сервер вместе с ошибкой отправляет полный json про то, какие действия пошли не по плану и почему, однако же сетевой код просто не рассчитан под «откат изменений», из-за чего он банально перезагружает профиль с последнего «сейва». - Отключения от сервера посреди рейда
Это может быть вызвано целым списком проблем, начиная от банальных проблем с интернетом на серверах, так и более интересными крашами рейдов, вызванных сторонними ошибками. - Ошибки подключения к серверам при запуске рейда
Тут сложно сказать, однако, в отличие от 6-го пункта, сбросить на «проблемы с интернетом» не выйдет. Как правило подобное происходит моментально после подключения к серверу, либо же после «генерации лута», из-за чего я склоняюсь к мнению, что сервер просто выдаёт ошибку и, либо не пускает игроков, либо не запускает рейд вовсе.
Таких ошибок в игре великое множество, а как «вишенка» на торте, это оптимизация.
Если говорить о причинах подобного, то проблема, опять же, в контроле и тестировании, (скорее всего, они либо просто плохие, либо же отсутствуют вовсе).
А теперь и поговорим об оптимизации. Она… плохая. Нет, не ужасная, просто плохая. Вы можете удивиться, но «оптимизация» не является главной причиной низкого фпс. Главная причина низкого фпс - [барабанная дробь] сетевой код. Да, сетевой код, опять. Вся проблема в том, что только по одному Буянову ведомой причине, код, отвечающий за общение с сервером, идёт через «main thread». Этот «поток» отвечает за обработку всех основных событий в игре и, как в нашем случае, за интернет, в частности.
В обычных играх для «обхода» подобного используется асинхронность - во время ожидания запроса от сервера игра продолжает работать, просто с низким TPS. Однако в Таркове всё не так. Хотя движок и старается раскидать игру на несколько потоков, но из-за однопоточной логики кода, игра продолжит виснуть.
В подтверждение могу привезти SPT, где с установленными графическими модификациями фпс редко падает ниже 80, однако на официальной серверах той же версии 30 – 40 фпс норма (15 - 30 без DLSS).
Знаете, что самое удивительное? В Unity уже есть встроенная функция «.GetAsync» относящееся к классу «HttpClient», но видимо её почему-то не используют.
Другая значимая проблема оптимизации - объекты. Я не знаю, что за мания делать по 100 объектов на комнату, но из-за неё возникает проблема в рендеринге. Я понимаю, что это может звучать не логично, однако отрисовать один ОГРОМНЫЙ объект проще, чем много маленьких.
В доказательство большого количества объектов могу привести такие кадры прогрузки:
Проблема в том, что во время прогрузки, Unity опрашивает объект и требует отдельного вызова «отрисовки» для каждого из них. Для одного же объекта только один, поэтому тратиться меньше времени и ресурсов для передачи информации, её приёма и обработки. (прогрузка объектов на выше показанном «слайдшоу» заняла целых 100 мс!)
А теперь поговорим о том, как их исправляют! Проблема с оптимизацией? Понизим графику! Проблема с границами? Закроем дверь! Проблема с сетевым кодом? Поставим очередную заплатку, чинящую один или два специфических случая. А любые жалобы или же замечания встречаются в штыки, из-за чего каждый, кто не является крупной «общественной личностью» просто затыкается (либо баном, либо «замечаниями» и последующим удалением сообщений).
Читеры и за́мок без стен
И тут мы разберём всех волнующий вопрос: а откуда столько читеров? Помните, что я говорил про то, что сервер не проводит никакой валидации данных? Ну, как итог, читер может перехватывать отправляемый на сервер пакет данных и подменить его. Никакого dll и не понадобиться, нужен просто всем известный Cheat Engine! Если быть точнее, то конкретно им взломать не выйдет, но принцип работы схож.
Я нашёл старую версию чита в opensource и прочёл код (слава богу он был на C++ 😊). Если кратко, то он работает по такой логике - мы знаем, что нам нужна ячейка начинающееся с какого-то паттерна (например, TY), а после ищем подходящее значение, читаем его или изменяем. По такому принципу чит создавал полноценную динамическую карту лута и игроков, давал возможность смотреть сквозь стены и многое другое.
Да, версия старая, но если судить по сообщениям разработчика чита на форуме, то никаких критических изменений, влияющих на работу читов, в игре так и не произошло, не смотря на регулярные обновления игры и античита.
Вся проблема в последнем. Античит обычно делают с целью защиты игры от внешнего вмешательства, в виде добавления сторонних скриптов, но изменения данных из ОЗУ подобная программа не отследит, она просто не рассчитана на подобное!
Но, что насчёт СБЭУ-Комаров?! А всё очень просто. Тут играет роль ранее упомянутая валидация. В игре есть защита от спид хака, но она максимально тупая: если скорость выше максимальной, значит игрок читер. Если же игрок будет двигаться в пределах нормальной скорости, но при этом лежать, сервер не будет видеть проблем.
Вся эта ситуации с читерами описывается комедийной сценой:
«Эта дверь даже ядерный взрыв выдержит, вам в жизни её не пробить!»
«А стены?»
«Б***ь…»
Итог
Игру вряд ли починят. Да, скорее всего продолжат выходить патчи, которые будут залатывать дыры, но суть проблемы это не изменит.
Какое-то время назад было обновление Unity, которое было надеждой на улучшение и пересмотр технической стороны игры, но кроме большего количества проблем и костылей особо ничего не было. Аудио движок сломали, старые баги, связанные с кодом на серверах, не починили, «крупное обновление», которое должно было убрать большую часть проблем и быть лучиком света в беспросветной тьме, оказалась очередным проходным патчем. А все речи о большей свободе разработчикам и крошки выеденной не стоят… Пока новые версии не начнут хотя бы нормально тестироваться, и разработчики перестанут умалчивать о проблемах, в лучшую сторону вряд ли что-то изменится. Главное, с чего стоит начать - сетевой код.
Боже, какие-то китайцы с русско-европейской командой под руку смогли сделать ПОЛНОЦЕННО РАБОТАЮЩИЙ БЭКЭНД. При этом, если исключить десинхронизацию открытия дверей и не самую удобную настройку сервера, то, по сравнению с официальным Тарковым, проблем вообще нет. ФПС нормальный, вылеты… бывают, но ни разу не было такого, что кого-то не подключало к серверу. А в купе с поддержкой модов~.
Ладно, вот теперь точно эпилог
Если разработчики не соберутся, и не начнут ответственно подходить к контролю разработки и критической переработке всего кода, то за дело во всю возьмётся сообщество. И это не как с некоторыми играми, как например DayZ, где многие игроки идут на сервера сообщества, чтобы поиграть с модами, нет. Если всё так и продолжиться, то даже те, кто любят исключительно официалку, будут ставить сторонние лаунчеры и патчи, только ради того, чтобы играть без «проблем». А если вспомнить, что в подобные версии можно вставить кряк, то, возможно, игру и вовсе перестанут покупать!
Огромное Спасибо:
Андрей Майоров (МАТ) - редактура
Даниил Грудзинский (abrikos) - консультации по анализу сетевых логов
Григорий Харламов и остальное сообщество TarkovGame | Escape from Tarkov | Tarkov Arena за идею и моральную поддержку
Лучшие комментарии
К сожалению, автор утверждает о техническом состоянии как о «неизлечимым», да и более того, рассуждая о путях решения проблем, которые он, как уверен, можно решить такими костыльными подходами, как if-else и т.п. упускает очень важный момент: логгирование ошибки не означают то, что ошибки нигде не обрабатываются выше уровнем.
Логгировать исключения вполне нормально, перехватывать и обрабатывать ошибки корректнее выше по стеку, а не в момент возникновения, т.к. зачастую на низком уровне в конкретном методе просто не будет хватать контекста для разрешения данной ситуации.
Что касается валидации: крайне странно утверждать об еë отсутствии только по характеру логов (это вообще не возможно), т.к. тип логгируемой информации определяется разработчиком, вполне возможно, что чтобы понять контекст, имеет смысл его явно залоггировать, чтобы потом иметь возможность проанализировать.
Что касается однотипных исключений: а автор имел коммерческийопыт работы над проектом огромных масштабов? Однотипные ошибки, зачастую, означают не конкретную ошибку, а класс, и причины у этих ошибок могут (да и наверняка) имеют различные причины.
По поводу формата логов: в промышленных приложениях абсолютно НОРМАЛЬНО, даже больше скажу, это стандарт индустрии ведение различных уровней логгирования и разных журналов.
По поводу якобы однопотояного исполнения кода: всегда, абсолютно всегда побочные потоки продуцируются главными, а также не стоит забывать, что не всë возможно распараллелить (тут вступает в игру закон Амдала, согласно которому, наступает такой момент, когда затраты на синхронизацию параллельных вычислений начинают сильно превышать профит).
Также стоит отметить, что главный поток — это и есть текущее общее состояние системы, и некоторые операции невозможно вести параллельно этому состоянию, например, валидацию перемещения объекта, т.к. нужно постоянно в реальном времени пытаться подогнать его к реальному. А решения типа: ну вы чë, глупые совсем, ну вызовите HttpClient.async, чë сложного то, вызывают только уныние… Да будет известно, что одновременно по сети гоняет данные не один поток, а множество, и распараллеливание происходит на уровне пула потоков, а не в конкретном соединении.
К тому же стоит отметить, что по http грузятся только какие-то статические данные (условно говоря, какой-то id предмета их контейнера), а вот игровая логика http соединения не имеет и использует протокол не выше, чем TCP, т. к. игре необходимо ПОСТОЯННОЕ соединение для работы (отсюда происходит и дëрганье при потере пакетов и нестабильного интернета), а http тут представить достаточно сложно, т.к. этот протокол поддерживает открытый коннект только, когда этот запрос исполняется (пример был выше).
Про читеров: хочется заметить, что практически каждая такая программа для подобных проектов — это сложный анализ ОЗУ и попытка перехватить оттуда необходимые данные с целью их последующего изменения, тот же wh и aim бот, а эти детские шалости по типу sql инъекции и подмена запросов — что-то из ряда выходящего, вы сами-то в это верите?) Неужели вам, ааа джуну, удалось прийти к этому, а крупной студии — нет?) Какой-то сюр, честное слово… Узнаю подход джунов, которые приходят на проект с огромными амбициями и самомнением, а когда до работы дело доходит, то тушите свет( Тут if поставим, там костыль вставим. А в итоге потом отваливается в самом неочевидном месте.
По поводу тестирования: господа, прошу внимательно читать документы, которые подписываете. Вы поддержали разработчика и получили доступ на ТЕСТИРОВАНИЕ, никто вам не обещал рабочий продукт, не выдумавыйте то, чего нет…
Хотел бы каждый аспект статьи разобрать, да доступа к ПК сейчас не имею
Не знаю что там с читами на основе пакетов(я слишком глуп чтобы даже читать этот код), но софт читающий память имеет практически безграничный контроль над игрой.
Я сам себе года четыре назад писал простенький софт на вх+сх. Так вот, я без профильного опыта программирования и знаний за 3 месяца добился отрисовки предметов на экране, на пиратке, с использованием стандартного кода маленького драйвера для чтения памяти(вроде даже у Майкрософта по этому поводу есть статья). Потом подписал его сертификатом разработчика, вышел в лицензию игры и удивился, что все доступно и все работает. Фактически я обошел античит подписью.
Спустя некоторое время и количество доработок рисовал игроков, ботов, их инвентарь, стату, никнеймы, добавил себе термальное зрение, ночное зрение, полеты, и т.д., мелкий не критичный функционал(ничего супер экстраординарного)… На все про все с нуля ушло где то месяцев шесть в общем.
Если сейчас посмотреть на форум читеров — там игру за это время сломали вдоль и поперек, вплоть до вызова метода/функции спавна предметов прямо в рейде.
Против этого любой аналогичный шутер выпущенный в этот срок сразу делает себе какую то шифровку списка игроков, прячет указатели, добавляет систему для анализа стрельбы, выявление софтеров на основе его КД, выживаемости и т.д...
А вы говорите они ошибки не чинят…
И это не единственный проект, куда я пытался запихать свои ручки.
Такой свободы действий я не видел нигде.
Мне мой тимлид говорил: «Лучше писать в логи, чем не писать»
А проблема читаемости решается специализированным софтом.
Процесс разработки сложная вещь, и там нельзя просто поправить ошибку, которая пишется в лог, если тебе захотелось. Проблема должна быть, выявлена, приоритеоризирована и решена в порядке приоритета. И если есть более приоритетные задачи (что решают зачастую не разрабы), то править другую не будут.
А и да, важное замечание:
Когда я говорил о читах, я говорил не об всех программах, а только об одном из типов читов, исходный код которого, я смог найти
А лучше, пусть читатель сам прочтёт наш диалог и сам решит, кто прав, а кто виноват
В коде игры очень сильно извините за мой французкий *насрано*, причём Буянов вызывал спецов по Юнити и те когда посмотрели код, ну процитирую Дона Карлеоне -посмотрите что они сделали с моим мальчиком! на исправление надежды мало, многие моменты и ошибки смогли побороть в СПТ удивительно одна игра а мододел Вася исправил то что не смог программист БСГ, грусна это всё :(
В правилах прописано, что запрещён в любом виде, даже запрятанный под звёздочки. Так что, нет нет, да прикопаться всё же могут.
Прочитал весь спор выше, возникли вопросы
1. Тестирование и контроль качества
Ваша позиция:
Вы утверждаете, что игроки являются тестировщиками, а проблемы с качеством — это нормально для прототипа.
Почему это вызывает вопросы:
Наличие ETS-сервера подразумевает возможность систематического тестирования. Если разработчики не используют его для полноценного тестирования, это вызывает недоумение.
— Графики ошибок (например, 80% ошибок в одной из версий) указывают на то, что обновления выпускаются без должного тестирования. Это не соответствует ожиданиям даже для «прототипа».
— Игра находится в тестировании уже долгое время, и игроки покупают её за реальные деньги. Это создает ожидание хотя бы минимального уровня качества.
2. Логгирование ошибок
Ваша позиция:
Логгирование ошибок как Error и их обработка выше по стеку — это стандартная практика.
Почему это вызывает вопросы:
— Если ошибки помечаются как `Error`, но фактически обрабатываются выше по стеку, это создаёт путаницу. Например, игроки могут воспринимать такие сообщения как серьёзные проблемы.
— Избыточность логов (дублирование сообщений с точностью до миллисекунды) усложняет анализ проблем. Это можно и нужно оптимизировать.
3. Валидация данных
Ваша позиция:
Нельзя делать выводы об отсутствии валидации данных только по логам.
Почему это вызывает вопросы:
— Конкретные примеры (например, `Unknown item type`, ошибки индексов или ключей словарей) указывают на отсутствие базовой валидации. Такие ошибки могли бы быть предотвращены.
— Если сервер знает последовательность действий и причину ошибки (например, ошибка 228), но игнорирует её, перезагружая данные игрока, это говорит о недостатках в архитектуре.
4. NullReferenceException
Ваша позиция:
Исключения генерируются средой исполнения (например, CLR для C#), а не языком программирования напрямую.
Почему это вызывает вопросы:
— Да, исключения генерируются средой исполнения, но причины таких ошибок часто связаны с отсутствием проверок на уровне кода (например, проверка на `null`).
— Ошибки типа `NullReferenceException` могли бы быть предотвращены с помощью валидации данных и более строгой обработки исключений.
5. Сетевой код
Ваша позиция:
Проблема с потерей пакетов и зависаниями характерна для всех шутеров. Её невозможно полностью решить.
Почему это вызывает вопросы:
— Да, потеря пакетов — это общая проблема, но влияние сети на FPS указывает на недостатки в архитектуре сетевого кода. Например, автор предлагал использование асинхронных операций.
— Проблема с сетью не должна влиять на FPS. Это должно быть два разных процесса.
6. Читерство
Ваша позиция:
Невозможно полностью защититься от читерства, пока игрок имеет доступ к ОЗУ клиента.
Почему это вызывает вопросы:
— Хотя полная защита невозможна, текущая система античита кажется слишком уязвимой для простых методов взлома (вроде Cheat Engine).
— В других играх (например, CS:GO) подобные методы либо менее эффективны, либо требуют значительно больше усилий. Это указывает на недостатки текущей системы защиты.
7. Компиляция vs Интерпретация
Ваша позиция:
Компиляция не отменяет последующую интерпретацию. В конечном итоге любая программа интерпретируется процессором.
Почему это вызывает вопросы:
— Да, процессор выполняет команды пошагово, но это не то же самое, что интерпретация исходного кода. Ваше утверждение звучит как попытка объединить разные уровни абстракции.
— Спор о компиляции vs интерпретации выглядит так как будто вам уже не знаете что цепляться и просто хотите выставить автора дураком, хотя это вообще не относится к теме статьи.
Ваши аргументы частично правильны, но они часто уклоняются от конкретных проблем игры.
— Вы защищаете разработчиков, но не предлагаете конкретных решений.
— Вы фокусируетесь на абстрактных технических деталях (например, компиляция vs интерпретация), которые не помогают улучшить игровой опыт.
Автор статьи, напротив, предоставляет конкретные примеры проблем и предлагает практические решения. Это делает его аргументы более убедительными для игроков, которые сталкиваются с этими проблемами каждый день.
Последний раз играл в тарков года 2 назад, ушел из за того что банально конкуренты уже играются лучше и относятся там к игрокам и к критике игр нормально. Если разработчики и дальше будут забивать на мнение людей, не будут решать мелкие проблемы или просто хотя бы слушать критику, а не затыкать рты, может что то из таркова и выйдет в дальнейшем, например игра
Ну, я делал согласно правилам. И это должно подходить под понятие цензурирования. Если это не так, то пусть мне сообщит модератор или же проверяющий, тогда уберу
Играю в данный шедевр уже больше 6 лет. Описанные автором проблемы очень похожи на правду. Хз что там куда компилируется, пакеты, потоки… Но игра крайне забагована и с каждым патчем становится менее играбельна
По существу не отвечено, ещë и гпт((( так он же сам и ответил, что компиляция — преобразование, а интерпретация — исполнение. Логика, не?) что происходит дальше с скомпиленным файлом шарпов? Где он и как запускается, его сам процессор читает?)))
Дальше, компиляция не отменяет последующую интерпретацию, откуда вы это вообще взяли???
Вообще то и так стёрто, не знаю где ты в двух буквах маты увидел? Может я «бухать» или «брить» имел ввиду
1. А они не тестируют? Это твоë внутреннее ощущение, доказательств у тебя нет. А что они должны, прописано в лицензионном соглашении, не стоит фантазировать.
2. Из какого стандарта следует, что они должны их помечать как варнинг? Опять ощущение?
3. Так, а если такие ошибки есть, то как это показывает, что нет валидации? Такие ошибки лишь сообщают о том, что кто-то криво что-то обработал, либо что данные неконсистентны.
4. Глубокое заблуждение. Для шарпов есть среда исполнения, написанная на плюсах, которая и генерирует исключения. В плюсах исключения генерируются ОС посредством системных прерываний, так например. А щарпы крутятся в CLR, которая и генерит исключения, по типу «выход за массив и null reference, советую подтянуть мат часть.
5. Был бы разработчиком данного продукта, рассказал бы.
6. Должны? Откуда такая уверенность?)
На остальное не стал отвечать, дабы не повторяться
Я это и воспринял как наезд в чистом виде :)
1. Я залез и прочитал там такие ключевые, в контексте нашего обсуждения, пункты:
— О том, что мы пришли сюда тестировать и искать ошибки:
— то, что не гарантируется bsg (мы с вами это приняли, когда заключили сделку):
— И отдельным пунктом можно выделить (что также не гарантируется):
Читая это соглашения сразу снимаются пункты обо всех ошибках, которые не фиксятся. А никто и не обещал, игроки сами это выдумали :)
2. Опять же, не получается уловить связь между логами (техническими журналами) и игроками.
3. Я вам больше скажу, это стандарт индустрии — обработка исключений в языках высокого уровня в проектах такого масштаба (а насколько огромен тарков, тут даже сложно представить себе).
4. Данные при принятии валидируются базово на допустимые значения и возможные аномалии в них, а смысловая часть обрабатывается отдельно, и вот как раз в процессе обработки получаются подобные ошибки.
— Как я выше и писал, что в контексте таких низкоуровневых ошибок решение проверкой на null не поможет, т.к. первопричина того, что там оказалась нулевая ссылка скрывается где-то гораздо ниже по стеку, тут по таким ошибкам как раз и нужно выявлять первопричину
5. Сильно сомневаюсь, что падение фпс связано с тем, что, якобы, тарков работает в один поток (ну это физически невозможно, но да ладно), тут нужен более комплексный анализ. Даже больше вам скажу, при проблемах с сетью зачастую мы получаем откидывания назад, или жуткие дисинки (противник не вышел и нас убил, либо выстрелы не зарегистрировались).
6. Ну можно начать с того, что bsg не занимается античитом, его она покупает у стороннего издателя (BattleEye), алгоритмов работы его мы с вами не знаем, но можно точно сказать, что там и базы способов взлома содержатся и обновляются, и ОЗУ защищается и т.п., просто в таркове читер приносит гораздо, гораздо больший дискомфорт, чем в той же кс (где, по словам игроков, читеров не мало).
Тут мой ответ ушëл на модерацию из-за ссылки на ютуб, ответил в вк, тут появится позже. Там доступным языком объяснили, что в КОНЕЧНОМ итоге ЛЮБАЯ программа интерпретируется
Ну насчёт ГПТ, согласен, просто подгорело отвечать ему каждые пять минут. В работе его использую, но в качестве примера потому, что брать его код на полном серьёзе себе же дороже, а подсмотреть как график сложный нарисовать или же библиотеку муторную использовать вполне можно.
Насчёт костылей… Возможно ты и прав. Однако, проблема в том, что я хотел предложить хоть, что то, однако без просмотра кода я не могу предложить что-то лучше.
А про инженер-программиста. Я говорил, что разработка игр и тем более C# не мой профиль. Я занимаюсь микроконтроллерами, да ПЛК. Python, для мат. моделей и пост обработки данных.
И да, после спора я заглянул на, то о чём он говорил, однако я понял две вещи:
1. Из-за своего профиля работы я с этим банально не встречался
2. Его слова о том, что все компилируемые ЯП аналогичны интерпретируемым, ошибочно. Да, такое делают, иногда, однако под одну гребёнку подводить всё тоже нельзя, всё же о терминологии забывать не стоит.
Но… Думаю всё равно спасибо за отзыв.
Он писал не только сюда, но и дублировал в вк, при чём с его же слов у него не работает копирование и ему пришлось вручную переписывать XD
Мужик, классная статья! Не сдавайся, не переставай разбираться в теме и уж тем более не давай заднюю из-за «умников» в комментариях. Такие как ты нужны, ибо если люди будут молчать — код игры и её техническое состояние в целом будет стоять на том же месте.
Просьба к вам, перед началом диалога, сразу обозначить ваш стек и стаж работы. Мой: php — 1 год (веб-студия), далее java 5 лет в энтерпрайз разработке фин. тех.
1. Вы, как и автор, опять опираетесь на свои ожидания «не должен», «недоумения». Прочитайте лицензионное соглашение внимательно, а после уже соотнесите с тем, что и кому должен. Как вы определили, что данное состояние не характерно для прототипа? Какую шкалу измерений вы для этого используете?
— А вы уверены, что мы можем использовать этот график вообще хоть для чего-то? Почему вы решили, что нужно писать в лог сообщения, которые не несут особой смысловой нагрузки при анализе инцидентов? Ещё раз, мы говорим о графике, который построен на логах, которые решил написать разработчик, которые необходимы ТОЛЬКО для разбора и устранения ошибок...
2. Ну это вообще тушите свет… Какие игроки?) Логи нужны ТОЛЬКО разработчикам, зачем вы их приплетаете?
— Ошибка логгируется на вершине стека, когда нет достаточного контекста для её разрешения, передаётся ниже по стеку и обрабатывается. Если вы делаете иначе, то у меня к вам вопросы.
— Как вы определили избыточность логов? Избыточность для кого? У вас есть доступ к инструментам, которыми пользуются разработчики для анализа логов и сбора статистики?
3. Unknown item type — это и есть сообщение от сервера, когда переданные с клиента данные были провалидированы… Иначе кто её выдал?) Про словари (предположу, что Map) — просто нет никакой необходимости при каждом обращении в мапу делать проверку на наличие ключа, иногда достаточно получить такое исключение от неё и обработать ниже по стеку, что, скорее всего, и делается.
— 228 это какой-то класс ошибок, появление которых (по всей видимости) говорит о неопределённом состоянии, из которого корректно невозможно восстановиться (нужно исправить первопричину, которая к ней привела, а не само состояние, оно уже не валидно настолько, что стоит начать с сейвпоинта), или в вашей картины мира не существует синего экрана у винды, либо перезагрузки биоса, либо ошибках установки программ (а чего, давайте исправим и продолжим, когда нет разрешения, либо данные сломаны/неконсистентны, либо сеть упала, либо контрольные суммы не сошлись. Да примеров куча, это стандартные практики для таких состояний).
4. Т.е. вы перед каждым обращением по ссылке рекомендуете её проверять на null? А если вы проверите, то что произойдёт, хватит ли вам контекста, чтобы обработать это состояние на этой глубине стека? Да и вообще, если делать проверки в КАЖДОМ месте, где хочется по ссылке обратиться, то вы начнёте заниматься процессом, обратным оптимизации… Скажу вам больше, даже компиляторы и интерпретаторы вырезают подобные проверки из стандартной библиотеки (и из клиентского кода в том числе), когда есть понимание, что эта ссылка не пуста… Ну и очевидно, что если возникла такая ошибка (а тут ещё нужно понимать, клиентский ли это код, либо код из стандартной библиотеки) из-за отсутствия в конкретном месте, то её тут никто не ожидал, а значит данные были испорчены гораздо ниже по стеку, тут нужно устранить первопричину, для этого ошибка тут и логгируется.
5. А вы уверены, что ФПС в таркове зависит от стабильной сети? Я писал о крайних случаях, когда происходят какие-то аномалии при получении из бекенда (что вы предлагаете показывать пользователю, когда не удалось актуализировать критичную информацию?), но если мы говорим о потере пакетов, то вы получите банальные откидывания назад, игра не замирает в это время. Или о чём речь?
6. Как вы определили эффективность? Какой методикой вы пользуетесь? Про какие конкретные методы мы говорим, давайте в конкретику.
7. Т.е. вы хотите сказать, что процессор не интерпретирует команды, а делает… Что он делает, как этот процесс исполнения кода называется? Книжки говорят, что интерпретация… Интерпретация идёт как завершающий шаг на нижнем уровне, будь-то прикладная интерпретация, или компиляция с последующей интерпретацией на уровне процессора, рекомендую видео: youtube.com/watch?v=DidtJLKSB8U (ознакомьтесь целиком, там простыми словами разобрана база, поймёт даже школьник)
Спор был затеян не мной, автор допустил критические ошибки по поводу того, кто и когда генерирует исключения. Было дано утверждение, в корне противоречащее этапам работы C#, на котором написан тарков и юнити.
PS: а где вы нашли оскорбления автора? Выявление некомпетентности являются оскорблениями?
Нет, я просто к индустрии разработки имею непосредственное отношение почти 6 лет, всë конструктивно написал, но меня минусуют совершенно некомпетентные люди)