Черный Думер» Помню, что раньше экран загрузки мог съедать некоторые сетевые пакеты, чтобы обрабатывать выключение сервера посреди загрузки.
Может ли быть здесь тоже что-то в подобном духе? DeaDDooMER» Не, вроде ничего не съедает. Пакеты для скачивания идут отдельным от игровых данных каналом. А дисконнект отдельным эвентом. Посмотрел - всё оказалось именно так, как я говорил. Очень странно, что никто почему-то не увидел этого раньше, меня аж расстроило. Это было всего-то второе моё предположение - первое заключалось в возможной потере пакетов подобно тому, как пропадали данные в потоке TCP при работе с 39dll в Doom2DMP из-за переполнения внутреннего буфера WinSock2 на 64 килобайта.
Суть в чём. В коммите
b171ccb1 (октябрь 2019) Кетмар сделал странную вещь: он добавил три проверки на получение пакетов по каналу передачи карт. Одна находится в
g_game.pas, две - в
g_net.pas, и все они определяются по комментарию "ignore all download packets, they're processed by separate code", по которому видна изначальная задумка.
Проблема же в том, что на этих местах пакет УЖЕ вытащен из очереди вызовом функции
enet_host_service(), то есть как только мы отказываемся от его обработки, то он исчезает в никуда. И да, такое
уже было.
Проверка в
g_game.pas не оказывает вообще никакого влияния (её можно убрать), потому что находится в функции
g_Game_StartClient(), вызываемой только при подключении к серверу. До неё нельзя дойти из последующего вызова
g_Res_DownloadMapWAD() или сопутствующих функций. О проверке в
g_Net_Client_Update() из
g_net.pas можно сказать то же самое. А вот проверка в
g_Net_Client_UpdateWhileLoading() как раз всё и ломает, потому что эта функция вызывается из
ProcessLoading(), а она в свою очередь вызывается аж из пяти (!) мест, которые постоянно дёргаются кодом передачи:
- g_Game_SetLoadingText() - выставление строк текста в процессе загрузки
- g_Game_StepLoading() - обновление строки загрузки с показателем скачанного ("downloading map")
- g_Net_Wait_MapInfo() - запрос информации о карте (читай: о файле карты)
- g_Net_RequestResFileInfo() - запрос информации о файлах-ресурсниках карты
- g_Net_ReceiveResourceFile() - получение файла-ресурсника
Парадоксально, но Кетмар здесь не виноват - он просто этого сначала не учёл, а затем не совсем понял (и сделал тот странный коммит).
То есть, причина очень простая: если получение первого пакета клиентом выпадало на вызов
enet_host_service() не из кода скачивания, а из
ProcessLoading(), то возникало зависание. Отсюда же связь с высоким пингом, кстати. Удостовериться довольно просто - достаточно закомментировать там вызов
g_Net_Client_UpdateWhileLoading(), после чего всё начинает на удивление хорошо работать. При тестировании выяснилось, что текущая система даже поддерживает докачку при следующем подключении в случае прерывания соединения. Спасибо, Кетмар!
Однако я не знаю, исправилась ли проблема с получением уже имеющихся карт. Если исправилась, то я не понимаю, почему. Надо тестировать. Возможно, это связано как раз с докачкой.
Пока что единственная более-менее гипотеза, которая у меня есть - это что оно могло съедать и не первый пакет, в результате чего игра могла решить, будто у неё другая версия карты, и запросить передачу.
Следует заметить, что при заходе на сервер эта проблема не возникала потому, что
g_Game_StartClient() и клацаемая ею
g_Net_Connect() хоть и вызывают сами
ProcessLoading(), но
g_Game_StartClient() в самом начале выставляет
NetState := NET_STATE_AUTH, который держится вплоть до начала игры, и при котором обработка сети в
ProcessLoading() не производится.
Сейчас придумаю, как по уму всё это поправить, и закоммичу. Делать отдельный
NET_STATE_DOWNLOAD не хочу - мало ли какие там косяки ещё могут вылезти на этом.
Prostovitalik» нахуя там вообще аки если в енете уже есть аки DeaDDooMER» я хуй знает, кэтмар так сделал Это для того, чтобы не держать все файлы в памяти во время передачи. Спросил у него лично, он подтвердил.