Counter-Strike 1.6
Вход
Руководство по оптимизации сетевого кода
Taraizer — 16 Май, 2009 - 02:35
Уфф... Долго я это откладывал... Около 4000 слов - и готово (хотя меня несколько загрузила вся писанина, так что вам придется обойтись без раздела разрешения вопросов).
Это мое долгожданное руководство по сетевому коду для Half-Life вообще и для Fireamrs в частности. Оно не разрабатывалось специально для single connection; я также не даю каких-то конкретных значений, поскольку оптимальные величины зависят от конкретных параметров вашей системы и соединения. Тем не менее, я часто буду заострять внимание на модемах и на широкополосном соединении. Пользователи ISDN могут рассматривать себя как нечто среднее между ними. Также я привожу раздел твиков для админов серверов. А, и еще, я не расскажу, как получить fake lag (хотя это просто).
Остальные, кто имеет кэшированный LAN, попали. Смиритесь, вам ничего не остается делать, поступайте как если бы у вас был ISDN.
Помните, что Half-Life - это сингл, и разрабатывался соответствующим образом. Все, что кажется корявым для мультиплея, скорее всего, таковым и является, но только потому, что это хорошо для сингла. Так что, пожалуйста, не надо комментариев вроде "они вообще не должны были так делать".
У многих появится желание пропустить несколько следующих абзацев, в которых поясняется, как работает игра, и перейти непосредственно к последующему рассмотрению cvar'ов. Тем не менее, прочитав описание игры, вы сможете лучше понять, что именно вы делаете, и найти лучше значения. И вам придется рассматривать cvar'ы в приведенном порядке, поскольку большинство твиков не помогут без выполненных предыдущих.
В сингле программе нет необходимости обрабатывать то, что происходит между кадрами, поскольку игрок взаимодействует только с тем, что он может видеть и слышать. Half-Life, таким образом, работает с игровыми кадрами. В сингле это то же самое, что и графические кадры (как fps - frames per second). Пока видеокарта прорисовывает следующий кадр, процессор просчитывает просиходящее в игре (повреждения, перемещения, ИИ и т. д.), и следующий кадр не начинается до тех пор, пока обе задачи не завершаются.
В мультиплее это работает слегка по-другому, в зависимости от того, какой сервер используется: listen-сервер или dedicated-сервер (выделенный сервер можно отличить по небольшой серверной иконке рядом с соответствующей строчкой в окне серверного броузера). Для listen-сервера сетевые кадры (по которым крутится сетевая игра) те же, что и игровые кадры хоста, т. е. те же, что и графические. Для выделенного сервера (а все хорошие серверы - это именно выделенные серверы) задача прорисовки до невероятного проста - выделенный сервер просто отображает консоль, которую можно прорисовывать очень быстро в силу того, что не требуется производить никаких 3D-вычислений. Следовательно, серверная кадровая частота будет зависеть только от того, как быстро он может обрабатывать игровую информацию (просчитывать перемещения и т. д.). Обычно выделенные серверы работают на 80 fps и выше, а во время затишья между сражениями частенько превышают HL-предел в 100 fps. Они работают на 100 fps все время, когда нет необходимости обрабатывать клиентские запросы. Попробуйте запустить свой сервер, и вы увидите, что как только к вам законнектятся несколько человек, частота кадров сразу значительно упадет.
В текущей версии Half-Life, как утверждает Valve, сетевой и графический фреймрейты полностью разделены, позволяя модемщикам играть на 100 fps без ухудшения производительности сети. В каком-то смысле это верно, поскольку графическая частота кадров намного выше (по крайней мере, в 3 раза) сетевой. Тем не менее, сетевой кадр по-прежнему не может быть начат до тех пор, пока не закончен соответствующий игровой кадр. Это означает, что графическая частота кадров, близкая к сетевой, может дистабилизировать последнюю.
В силу особенностей работы интернета и Half-Life, сетевые проблемы, такие как высокое время запаздывания (high latency) и потеря пакетов (packet loss), минимизируются за счет наличия регулярного потока обновлений. Это достигается благодаря синхронизации с кадровой частотой сервера, установки виртуальных цепочек на PoP и модемных временных алгоритмах переключения. Таким образом, иррегулярные сетевые кадры приводят к вещам, которые мы все ненавидим, - явлениям, объединенным общим названием "лаг"
Думается, мне лучше сначала пояснить, с чем нам придется иметь дело, прежде чем начать рассказывать, как это минимизировать.
Ping - [Packet Information Groper (сначала придумали сокращение, а уж затем - собственно термин).] Это интервал времени (в миллисекундах или в тысячных долях секунды) между посылкой пакета на сервер вашим компьютером и получением ответа ("pong"). Этот параметр наиболее зависим от вашего типа соединения, большинству модемов требуется около 150 мс просто чтобы достучаться до ISP, так что пинг редко бывает ниже 200. Пользователи ADSL, как правило, имеют пинг около 10 мс до провайдера, так что для них преградой является фундаментальные скоростные ограничения их части интернета; это игроки, на коннект которых больше всего влияет расположение сервера (если разница между 30 мс и 80 мс для вас является существенной).
Packet Loss - Это, пожалуй, самый важный и требующий оптимизации параметр, которым часто жертвуют в пользу пинга. Пакет считается потерянным, если на каком-то отрезке пути он был отброшен - или потому, что устарел (наиболее распространенный случай) или потому, что ограниченная пропускная способность не позволила ему пройти. Эти надоедливые Connection Problems? Они появляются, когда потеря пакетов достигает 100% (т. е. ничего не проходит) в течение нескольких секунд единовременно или даже постоянно (из-за чего вы спустя некоторое время уходите с сервера, если не знаете, как справится с этими ужасными проблемами).
Choke - Это среднее время (в миллисекундах) между моментом генерации пакета на вашей машине и моментом отсылки его на сервер. Одной из главных задач оптимизации является получение значения choke, равного 0, или, по крайней мере, близкого к нулю настолько, насколько это возможно.
"Broadband Slowdown" - Клиенты с высоким пингом НЕ являются причиной лагов! Я не знаю, из чего вырос этот глупый миф, но это - абсурд. На самом деле, как вы уже наверное догадались, замедляют сервер широкополосные соединения (broadband connections). Выделенщики (broadbanders) запрашивают большое количество обновлений в секунду с высокой точностью (accuracy - packet size - размер пакета), при этом сами посылают большое количество обновлений, опять-таки с большим размером пакетов. Все, что используется широкополосным соединением (полоса пропускания сервера, используемая одним широкополосным соединением, может "прокормить" от 5 до 10 модемщиков), и все посылаемые пакеты съедают существенную часть ресурсов процессора и памяти сервера. Самое нечестное в этой ситуации то, что модемщики, в большей степени страдающе от падения производительности, еще и становятся козлами отпущения за грехи выделенщиков. Может быть, этот миф появился оттого, что при медленном сервере у модемщиков большой пинг, и выделенщики просто заключают, что это причина замедления, а не его последствие. Кикать модемщиков с сервера при его замедлении не только не честно, но и бесполезно, поскольку никаких заметных изменений это не даст.
Также ошибочно считать, что приведенные характеристики зависят от сетевого кода, используемого конкретным модом. Например, CS и (в меньшей степени) DoD сделаны так, чтобы уменьшить пинг клиентов настолько, насколько это возможно, даже не задумываясь о потере пакетов или choke. Это хорошо и замечательно для широкополосной передачи и хороших видеокарт, но на людей с нестандартными видеокартами и модемами разработчики откровенно клали с двумя проборами. К счастью, Fireamrs обеспечивает хорошее сочетание двух типов соединения, обеспечивая, например, регулируемую клиентом точность, что позволяет существенно снизить трафик и облегчает жизнь людям на коннекте с ограниченной пропускной способностью (т. е. модемщикам).
Как найти подходящие для вас значения? Half-Life имеет замечательную небольшую утилиту под названием netgraph. Чтобы включить ее, наберите в консоли net_graph 1. Можно использовать значения от 1 до 5, каждое из которых показывает несколько различные вещи, 0 отключает netgraph. Лично я использую 3, но никто не запрещает вам выбрать вид на свой вкус. Netgraph может вызвать понижение fps, но я считаю его несущественным. Большое падение должны заметить только те, у кого графический fps значительно выше сетевого. В этом случае netgraph можно или уменьшить в размере или вообще выключить после того, как вы оптимизируете свой сетевой код. Ниже приводится описание информации, выводимой net_graph 1:
1. Счетчик FPS (FPS counter) - ваше текущее значение fps.
2. Сетевое время запаздывания (network latency) - это ваше текущее значение времени запаздывания (пинг).
3. Ширина входящей полосы пропускания.
4. Ширина исходящей полосы пропускания.
5. График, показывающий изменение пинга. Чем выше пинг, тем тоньше становится график. Также отображает патерю пакетов (красным) и рассогласованные объекты (mismatched entities; синим).
6. Текущая частота обновления сервера (входящая частота).
7. Текущая частота обновления клиента (исходящая частота).
CVar - это клиентская переменная (client variable) или серверная переменная (server variable), величина, управляющая некоторыми операциями движка, которая может быть изменена клиентом (или администратором сервера). Например, con_color может быть использована для ввода RGB-значения цвета текста в консоли. Я рассмотрю нужные cvar'ы, объясню, как их нужно использовать, и дам рекомендации по подбору оптимальны значений. Я неизбежно пропущу некоторые из них (их сотни, хотя большинство на самом деле не влияют на сетевую производительность). Далее буквой x будет обозначаться числа; вводятся переменные в консоли (хотя также они могут быть введены из командой строки).
Netgraph CVars
net_graph x - как отмечено выше, управляет отображением netgraph. 0 - выключает, 1-5 отображает выводимую информацию в различных комбинациях. По умолчанию 0. Я предпочитаю 3.
net_graphpos x - определяет позицию netgraph на экране. 1 - внизу справа, 2 - внизу по центру, 3 - внизу слева. По умолчанию 1, что меня вполне устраивает, хотя некоторые ставят 2.
net_graphwidth x - ширина графика в пикселях. Один пиксель на графике соответствует одному отправленному пакету. По умолчанию 192. Не забывайте оставлять значение достаточным для сохранения читабельности текста.
net_graphheight x - высота графика в пикселях. По умолчанию 64. Опять-таки, не забывайте о читабельности текста.
Вам интересно, почему пинг на netgraph'e как правило меньше пинга на scoreboard'e? Хм, пинг, показываемый netgraph'ом - это чистый сетевой пинг. Пинг на scoreboard'e - это, скорее, отображение временных показателей в их действии против игрока, поскольку он включает время, необходимое для прорисовки и отображения пакета на клиентском компьютере. Каждый показатель является по-своему полезным.
CVar'ы, связанные с FPS
fps_max x - устанавливает максимальный графический fps. Любое значение в промежутке от 1 до 100 является допустимым, значение по умолчанию 72. Half-Life попытается равномерно разделить каждую секунду на соответствующее количество "кусочков". Если прорисовка происходит быстрее, чем такой отрезок времени, то программа начинает рисовать следующий, никогда не уходя при этом дальше, чем на 1 кадр вперед; это делается для рационального использования памяти и поддержания заданной частоты. Если же прорисовка очередного кадра не укладывается в соответствующий интервал, то она продолжается в следующем. Никто не верит мне, но это самая важная переменная для оптимизации сетевого кода. Поскольку все в Half-Life завязано на кадрах, а они, в свою очередь, зависят от графических кадров, то это чрезвычайно важно. Самый распространенный совет - ставить значение 100 (максимальное), так, чтобы прорисовывалось как можно больше кадров в том смысле, чтобы проходило наименьшее время между между получением пакета и его прорисовкой. Это абсолютно и полностью неверно. Как отмечалось ранее, сетевой код работает совершенно определенным образом, и самое главное здесь - регулярность, постоянство. Лучше иметь стабильные 20 fps, чем прыгающие между 20 и 30. На практике часто оказывается, что выставление более низкого значения fps_max повышает среднюю частоту кадров, поскольку их прорисовка четко укладывается во временные "кусочки", что ликвидирует неизбежные потери времени, когда кадру для прорисовки требуется больше одного временного интервала. Значение, близкое к правильному, но все же не совсем правильное, хуже резко отличного, поскольку каждый интервал больше, и потеря половины интервала вреднее. Вам следует значительно снизить эту величину, пока вы не найдете точку, в которой ваш fps будет практически постоянным (и близким к выставленному пределу). Разумеется, могут быть карты или большие перестрелки, где fps может падать, но он должен быть постоянным при нормальной игре. При приближении к нужному значению все может выглядеть очень плохо, но когда вы найдете его, результат окажется гораздо лучше, чем вы могли подумать, поскольку кадрирование будет постоянным, и мозгу легче будет интерполировать движущееся изображение. Именно поэтому изображение в телевизоре смотрится лучше, чем игра на 24 fps, поскольку телевизор всегда держит одну частоту. Корректный подбор этой величины может сразу снизить пинг, потерю пакетов и choke. Все еще не верите? Тогда можете прекратить читать это руководство, все, что написано дальше, бесполезно, если вы не выполнили этот шаг. Если полученный результат слишком низний (меньше 20 fps), попробуйте снизить детализацию для повышения скорости рендерринга, для чего приводятся некоторые твики в конце данного руководства (На самом деле их там нет, я их так и не написал). Также бесполезно ставить значение fps_max больше поддерживаемого вашим монитором (60 Hz и 75 Hz - нормально), если только вы не запускаете сервер, поскольку лишние кадры просто не будут отображаться.
fps_modem x - пусть вас не вводит в заблуждение название, эта переменная одинаково применима ко всем типам соединения. Устанавливает максимальное количество графических кадров в секунду для игры по интернету. Используется это значение или fps_max - какое меньше. Допустимо любое число от 1 до 100, по умолчанию 100. Это может как-то пригодится только тем, кто играет и по LAN'у и по интернету - на LAN'е будет использоваться fps_max, а в интернете - fps_modem. Если не считаете, что fps влияет на производительность сети, то как тогда вы можете объяснить использование разных cvar'ов в зависимости от типа соединения? Готов поспорить, что кто-то все еще не верит мне... Возможно будет полезно снизить уровень детализации и получить высокий fps на LAN'е, чтобы воспользоваться преимуществами дополнительной пропускной способности.
fps_lan x - устанавливает максимальный графический fps для игры по LAN'у. Используется это значение или fps_max - какое ниже. Допустимо любое число от 1 до 100, по умолчанию 100. Бесполезен практически для любого HL mod'a, поскольку играет роль только если mod играется и в сингле (где используется fps_max), и по LAN'у (fps_lan) и по интернету (fps_modem). Я таких модов не знаю. Единственная ситуация, которая пришла мне в голову - это если одна и та же машина используется иногда как выделенный сервер, а остальное время - на LAN'е и интернете. В этом случае fps_lan и fps_modem должны иметь нужные значения, а fps_max выставлен в 100, чтобы выделенный сервер работал настолько быстро, насколько это возможно. Что опять-таки неправдоподобно.
Дурные лагоубийственные CVar'ы
Я написал "дурные", потому что не понимаю, зачем людям может понадобится менять их; но когда лагокомпенсатор только появился, все выделенщики хотели знать их, так что...
cl_lc x - 1 или 0, по умолчанию 1. 1 означает использование Half-Life'ом лагокомпенсатора (если мод и сервер его поддерживают), 0 выключает его. Компенсация лагов - это система, с помощью которой вы попадаете в то, что вы целились, когда стреляли, вместо того, чтобы стрелять на опережение цели. Зачем вам может понадобиться отключить его - выше моего понимая, разве что у вас пинг меньше 10. Может быть на быстром LAN'e, где это могло бы ограничить пропускную способность, но поскольку LAN'ы имеют тонны нерастраченной пропускной способности, в этом нет действительной необходимости. Пусть работает.
cl_lw x - 1 или 0, по умолчанию 1. 1 означает, что точность стрельбы и отдачу Half-Life оставит для обработки клиенту. Если отключить, то при нажатии fire вы увидите стрельбу оружия после паузы, равной вашему пингу, потому что придется ждать ответа сервера о том, какая была отдача, и куда полетели пули. Это может иметь некоторый смысл в модах, где стрельба просчитывается на сервере (CS как самый очевидный и жуткий пример), но, например, в Firearms, который в любом случае использует клиентские подсчеты, а сервер подравнивает то, что говорят клиенты, в этом нет смысла, и это делает игру сложнее из-за необходимости учитывать отдачу. Нет разницы в используемой пропускной способности: 1 посылает информацию на сервер, 0 посылает те же данные в другом направлении.
cl_lb x - 1 или 0, по умолчанию 1 (раньше по дефолту стоял 0, что отражено в некоторых руководствах). При 1 игра будет помещать спрайты крови, если ваш клиент считает, что вы попали в цель, при 0 она еще подождет подтверждения от сервера. Это может показаться странным, и служит только для индикации попадания с высококорявых оружий в модах вроде CS, где оружие просчитывается сервером. Бесполезно в Firearms. Оставьте включенным.
Собственно CVar'ы сетевого кода
Эти cvar'ы непосредственно влияют на сетевые пакеты и могут, таким образом, существенно изменить работу сети. Неправильная их установка делает игру неиграбельной или даже приводит к постоянным проблемам соединения при заходе на сервер. Не забудьте сохранить предыдующие значения, прежде чем что-то менять (для этого введите в консоли cvar без числа после него. Half-Life выведет текущее значение).
cl_updaterate x - Любое целое значение от 1 до 200. По умолчанию 20. Это количество обновлений, которое клиент хотел бы получать от сервера в секунду. Клиент сам не отправляет такое количество запросов, просто когда вы присоединяетесь к серверу (или изменяете значение), он шлет серверу пакет с просьбой "Прошу посылать мне столько-то обновлений в секунду". Сервер будет честно стараться посылать столько, сколько запрошено. Лучшее значение равняется fps_max; не превышайте 30 обновлений в секунду (даже 25 не очень хорошо). Если ваше значение fps_max выше, то подберите в качестве cl_updaterate множитель значения fps_max. Например, если fps_max равняется 42, то используйте cl_updaterate, равный 21. Игра начинает дергаться около 13, так что не бойтесь пробовать значения вплоть до 15. Такие значения дают себя знать только когда в игре объекты перемещаются очень быстро, вроде гранат из m79, gp25 или m203. Так как вам просто сообщается то, что уже произошло на сервере, нет необходимости выставлять высокие значения; они только добавят ненужную нагрузку на сервер, вызывая broadband slowdown (см. выше). Ах, да, для LAN'a ставьте 50.
cl_cmdrate x - Любое целое значение от 1 до 100. По умолчанию 30. Величина, противоположная cl_updaterate, - устанавливает число исходящих пакетов в секунду. Нет никакой причины ставить значение выше fps_max, потому что в этом случае будет происходить отсылка одних и тех данных дважды в течение некоторых кадров. Так как исходящая полоса пропускания меняется меньше, чем входящая, в общем случае верхней границей значений является 40 (30 для модемов). Установите его равным fps_max или делителю fps_max (например, половине), если ваш fps_max выше указанных пределов.
cl_rate x или просто rate x - Любое целое от 0 до 9999. Значение по умолчанию определяется выбранным при установке типом соединения. Это объем данных, разрешенных к пересылке каждую секунду в байтах (и входящих, и исходящих). Чем выше значение, тем больше данных пересылается каждую секунду, и тем лучше клиент может отслеживать происходящее на сервере. В то же время, требуется большая полоса пропускания, как на сервере, так и на клиенте. Как клиент, вы захотите установить эту величину настолько большой, насколько это возможно, для оптимальной плавности. Слишком большое значение приведет к потере пакетов, так как просто физически окажется невозможным посылать некоторые пакеты. Начните со значений, несколько больших, чем приведенные ниже, и постепенно сбрасывайте их до тех пор, пока потеря пакетов не прекратится (или станет минимальной, ведь она зависит еще и от сервера). При изменении настроек следует понимать, что это создает разницу в надежности соединения, так что следует потестировать каждое значение 5-10 минут, прежде чем принимать решение.
Здесь приводятся приблизительные величины, для вашего конкретного соединения они могут быть совершенно другими.
56k модем или 64k ISDN – 2500-3000
128k ISDN – 4000-5000
кабельный модем – 6000-8000
xDSL или T1 – 7000-10000
LAN – 10000
cl_resend x - Любое целое значение от 0 до 16. По умолчанию 6. Устанавливает максимальное число попыток переслать потерянные пакеты. Если вы выполнили предыдущие твики, вы должны получить много пп, установка cl_resend в 1 снизит пп, не влияя на производительность и flush слишком сильно.
cl_timeout x - Любое целое значение от 0 до 1000. По умолчанию 30. Устанавливает время (в секундах), после которого соединение считается потерянным, если не было получено никаких пакетов. Часто эта ситуация восстановима, особенно когда вы видите "живые" значения in и out. У меня поставлено 90.
Загрузочные CVar'ы
cl_allowupload x - 0 или 1, по умолчанию 1. При 1 разрешена закачка на сервер своих лого. Так как вряд ли это может вызвать лаги (если только первые 20-30 секунд), и позволяет другим игрокам видеть ваше лого, лучше оставить включенным.
cl_allowdownload x - 0 или 1, по умолчанию 1. При 1 HL может по необходимости загружать звуки или карты с сервера. Для звуков лучше оставить, а вот карты так загружать нельзя НИ В КОЕМ СЛУЧАЕ! Во-первых, карты закачиваются в неупакованном виде, во-вторых, HL-соединение медленнее ftp, так что вы потеряете времени больше, чем необходимо для нормальной закачки карты. Загляните лучше в соответствующий раздел на сайте и возьмите нужную карту оттуда.
cl_download_ingame x - 0 или 1, по умолчанию 1. При 1 разрешена закачка на ваш компьютер лого других игроков во время игры. По выше описанным причинам лучше оставить включенным. Скачанные изображения хранятся в файле custom.hpk в папке соответствующего мода; я рекомендую удалять его периодически (каждые две недели - вполне нормально), поскольку он может достаточно сильно разростись, съедая много памяти и времени при запуске. Все равно HL при необходимости автоматически создаст новый файл.
Админам серверов
Это твики, которые админ сервера может использовать для оптимизации сетевой производительности на своем сервере. Я не уверен абсолютно в приведенном ниже материале, поскольку не имел возможности протестировать его на сервере.
sv_maxrate x - Любое целое число от 0 до 99999. По умолчанию 99999. Устанавливает максимальный rate для одного клиента. Значение надо подобрать так, чтобы умноженное на maxplayers, оно давало 2/3 вашей общей пропускной способности (1/3 - резерв для учета реалей канала, а также для закачки лого и т. п.). Я частенько вижу значения выше пропускной способности, что нельзя назвать умным, потому как rate у всех автоматически падает. Это не только загрязняет аккуратно настроенный сетевой код, но вызывает broadband slowdown (см. выше) и опять-таки портит жизнь модемщикам. На мой взгляд было бы правильным ставить на серверах 3000, чтобы у всех была одинаковая производительность, но я не думаю, что это когда-нибудь произойдет.
sv_minrate x - То же, что и sv_maxrate, только устанавливает минимальный rate вместо максимального. Представляется слегка бессмысленным, люди должны иметь возможность ставить свои rate такими маленькими, какими им хочется. Ставьте 0.
sv_dlmax x - Любое целое значение от 0 до 99999. По умолчанию 99999. Устанавливает максимальный объем закачки в сторону клиента в кб. УБЕДИТЕСЬ, ЧТО ЭТА ВЕЛИЧИНА ПРОСТАВЛЕНА ПРАВИЛЬНО! Лучшим с любой стороны является значение 500. Этого достаточно, чтобы клиент мог скачать любой звук, но недостаточно для закачки любой карты. Это значит, что клиенты не смогут закачивать карт с вашего сервера (что очень неэффективно и сильно лагует сервер, особенно если качают выделенщики).
Ну что ж, это все, на что я смог раскачаться. Возможно, я добавлю раздел устранения неполадок и пополню админскую часть. Извините, что это заняло так много времени, ребята.