Анализ исходного кода Quake


Чит коды Quake 4 на PC

Для смены клавиши вызова консоли найдите файл Quake4Config находящийся по пути: С:\Program Files\id Software\Quake 4\q4base\ (для папки установки по умолчанию) Откройте его любым текстовым редактором и найдите строку «`» «toggleconsole» измените символ ` на любой другой, например: «~» «toggleconsole» Во время игры нажмите левый [Ctrl] + [Alt] + [~] чтобы показать консоль. (или клавишу [`], если не сработал предыдущий вариант) Теперь вводите следующие чит коды: god — неуязвимость noclip — ходить сквозь стены notarget — невидимость freeze — заморозить всех give all — все оружие и патроны give ammo — все патроны map [название_карты] — загрузить карту benchmark — игровая статистика производительности com_drawfps 1 — показать FPS aviDemo — записать демо вашей игры в AVI файл gfxinfo — информация о видеокарте r_gamma [0-3] — установить уровень гамма r_brightness [число] — установить уровень освещенности s_volume_db [число] — установить уровень звука s_showlevelmeter 1 — показать уровень звука s_showlevelmeter 0 — отключить показ уровня звука g_showprojectilepct 1 — показывать % ущерба g_showprojectilepct 0 — не показывать % ущерба killmonsters — убить всех монстров kill — самоубийство quit — выход из игры Названия карт: Используйте следующие названия для кода «map game/[название_карты]» code: Air Defense Base: airdefense1 Air Defense Trenches: airdefense2 Aqueducts: convoy2 Aqueducts Annex: convoy2b Canyon: convoy1 Construction Zone: walker Data Networking Security: network2 Data Networking Terminal: network1 Data Processing Security: process2 Data Storage Security: storage2 Dispersal Facility: dispersal Game/process1: process1 Game/storage1: storage1 Hangar Perimeter: hangar1 Interior Hangar: hangar2 MCC Landing Site: mcc_landing Nexus Core: core1 Nexus Hub: hub2 Nexus Hub Tunnels: hub1 Operation: Advantage: mcc_1 Operation:Last Hope: mcc_2 Perimeter Defense Station: building_b Putrification Center: putra Recomposition Center: recomp Strogg Medical Facilities: medlabs The Nexus: core2 Tram Hub Station: tram1 Tram Rail: tram1b Waste Processing Facility: waste Названия моделей: Используйте названия моделей для кода их получения «spawn [название_моделей]» char_doctor char_kane_strogg char_marine char_marine_fatigues char_marine_medic char_marine_tech_armed monster_berserker monster_bossbuddy monster_failed_transfer monster_fatty monster_gladiator monster_grunt monster_gunner monster_harvester_combat monster_iron_maiden monster_makron monster_network_guardian monster_repair_bot monster_scientist monster_sentry monster_slimy_transfer Названия модификаций оружий: Используйте эти названия для их получения кодом «spawn [название]» Внимание: Вы должны иметь оригинальное оружие чтобы иметь возможность получить его модификацию.(т.е. просто вводите код «give all» перед использованием одного из этих) weaponmod_hyperblaster_bounce1 weaponmod_lightninggun_chain weaponmod_machinegun_ammo weaponmod_nailgun_ammo weaponmod_nailgun_power weaponmod_nailgun_rof weaponmod_nailgun_seek weaponmod_railgun_penetrate weaponmod_rocketlauncher_burst weaponmod_rocketlauncher_homing weaponmod_shotgun_ammo

Сеть

Сетевая архитектура QuakeWorld в своё время считалась потрясающей инновацией. Во всех последующих сетевых играх использовался тот же подход.

Сетевой стек

Элементарной единицей обмена информацией в Quake была команда. Они используются для обновления положения, ориентации, здоровья, ущерба игрока и т.д. В TCP/IP есть множество отличных функций, которые пригодились бы в симуляции реального времени (контроль передачи, надёжность доставки, сохранение порядка пакетов), но в движке Quake World этот протокол нельзя было использовать (он использовался в оригинальном Quake). В шутерах от первого лица информация, не полученная вовремя, не стоит повторной пересылки. Поэтому был выбран UDP/IP. Для обеспечения надёжности доставки и сохранения порядка пакетов создали сетевой слой абстракции «NetChannel».
С точки зрения OSI NetChannel удобно расположен поверх UDP:

Итак, подведём итог: движок в основном работает с командами. Когда нужно отправить или получить данные, он поручает эту задачу методам Netchan_Transmit и Netchan_Process из netchan.c (эти методы одинаковы для клиента и сервера).

Заголовок NetChannel

Заголовок NetChannel имеет следующую структуру:

Битовое смещениеБиты 0-1516-31
0Sequence
32ACK Sequence
64QPortКоманды
94
  • Sequence — это число int, инициализируемое отправителем и увеличивающееся на единицу при каждой отправке пакета. Sequence используется во многих целях, но самая важная задача — предоставить получателю возможность распознавания утерянных/дублированных/внеочередных пакетов UDP. Самый значимый бит этого целого числа является не частью sequence, а флагом, указывающим на то, содержит ли (команда) надёжные данные (подробнее об этом позже).
  • ACK Sequence — это тоже int, оно равно последнему полученному числу sequence. Благодаря ему другая сторона NetChannel может понять, что пакет был утерян.
  • QPort — это обход ошибки маршрутизаторов NAT (подробнее см. в конце раздела). Его значение — случайное число, задаваемое при запуске клиента.
  • Команды: передаваемые значимые данные.

Надёжные сообщения

Ненадёжные команды группируются в пакет UDP, он помечается последним исходящим числом sequence и отправляется: отправителю не важно, будет ли он потерян. Надёжные команды обрабатываются иначе. Главное — понять, что между отправителем и получателем может быть только один неподтверждённый надёжный пакет UDP
В каждом игровом цикле при генерировании новой надёжной команды она добавляется в массив message_buf (управляемый через переменную message) (1

). Набор надёжных команд затем перемещается из message в массив reliable_buf (
2
). Это происходит только если reliable_buf пуст (если он не пуст, это значит, что ранее был отправлен другой набор команд и его получение пока не подтверждено).

Затем формируется окончательный пакет UDP: добавляется заголовок NetChannel (3

), затем содержимое reliable_buf и текущие ненадёжные команды (при наличии достаточного места).

На принимающей стороне сообщение UDP парсится, входящее число sequence передаётся в исходящее sequence ACK (4

) (вместе с битовым флагом, указывающим на то, что пакет содержит надёжные данные).

При следующем получаемом сообщении:

  • Если битовый флаг надёжности имеет значение true, это значит, что пакет UDP доставлен получателю. NetChannel может очистить reliable_buf (5
    ) и готов к отправке нового набора команд.
  • Если битовый флаг надёжности имеет значение false, то пакет UDP не дошёл до получателя. NetChannel делает повторную попытку отправки содержимого reliable_buf. Новые команды накапливаются в message_buf. Если массив переполняется, то клиент сбрасывается.

Контроль передачи

Насколько я понял, контроль передачи выполняется только на стороне сервера. Клиент отправляет обновления своего состояния как можно чаще.
Первое правило контроля передачи, активное только на сервере: отправлять пакет, только если пакет был получен от клиента. Второй тип контроля передачи — это «choke», параметр, который клиент устанавливает командой консоли rate. Он позволяет серверу пропускать сообщения обновлений, уменьшая количество данных, отправляемых клиенту.

Важные команды

Команды содержат код типа, хранящийся в байте, за которым следует полезная информация команды. Наверно, самыми важными являются команды, дающие информацию о состоянии игры (frame_t):

  • svc_packetentities и svc_deltapacketentities: обновляют такие объекты, как следы от ракет, взрывы, частицы и т.д.
  • svc_playerinfo: отправляет обновления о положении игрока, последней команде и длительности команды в миллисекундах.

Подробнее о qport

Qport был добавлен в заголовок NetChannel для исправления ошибки. До qport сервер Quake идентифицировал клиента по комбинации «удалённый IP-адрес, удалённый порт UDP». Чаще всего это работало хорошо, но некоторые маршрутизаторы NAT могут произвольно менять свою схему трансляции портов (удалённого порта UDP). Порт UDP становится ненадёжным, и Джон Кармак (John Carmack) объяснил, что он решил идентифицировать клиент по «удалённому IP-адресу, Qport в заголовке NetChannel». Это исправило ошибку и позволило серверу на лету изменять целевой порт ответа UDP.

Вычисление латентности

Движок Quake хранит 64 последних отправленных команды (в массиве frame_t: frames) вместе с senttime. К ним можно получить доступ непосредственно по числу sequence, использованному для их передачи (outgoing_sequence). frame = &cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK]; frame->senttime = realtime; //Отправка пакета серверу После получения подтверждения от сервера время отправки команды получается из sequenceACK. Латентность вычисляется следующим образом: //Получение ответа от сервера frame = &cl.frames[cls.netchan.incoming_acknowledged & UPDATE_MASK]; frame->receivedtime = realtime; latency = frame->receivedtime — frame->senttime;

Элегантные решения

Зацикленность индекса массива Сетевая часть движка хранит 64 последних полученных пакетов UDP. Наивным решением циклического прохода по массиву было бы использование оператора остатка целочисленного деления: arrayIndex = (oldArrayIndex+1) % 64; Вместо этого вычисляется новое значение с двоичной операцией И для UPDATE_MASK. UPDATE_MASK равняется 64-1. arrayIndex = (oldArrayIndex+1) & UPDATE_MASK; Настоящий код выглядит так: frame_t *newpacket; newpacket = &frames[cls.netchan.incoming_sequence&UPDATE_MASK]; Обновление: вот комментарий, полученный от Dietrich Epp относительно оптимизации операции деления с остатком:
Есть проблема с последней частью, где использование оператора деления с остатком называется «наивным». Вот пример разницы между остатком целочисленного деления и оператором И: Создаём файл file.c: unsigned int modulo(unsigned int x) { return x % 64; } unsigned int and(unsigned int x) { return x & 63; } Запускаем gcc -S file.c и смотрим на файл вывода file.s. Заметно, что функции построчно одинаковы, несмотря на отключенную оптимизацию! То же относится к «остроумным» решениям типа использования << 5 вместо *32. Такие изменения делают код менее читаемым, а преимуществ не дают, поэтому я считаю, что варианты решений с << 5 или & 63 «наивны», а варианты с *32 или %64 более умны. —Dietrich .globl modulo .type modulo, @function modulo: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax andl $63, %eax popl %ebp ret .size modulo, .-modulo .globl and .type and, @function and: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax andl $63, %eax popl %ebp ret .size and, .-and

Консольные команды. Часть первая

Не знаю как писать «интро», поэтому сразу к делу -_-

Про открытие консоли можно прочитать тут

Про раскрашивание ников тут

clan «clan name» — клантаг

ui_clantagpos 1 — тег размещается перед именем (0 после)

sex «male» — ваш пол (female для женщин соответственно)

model «модель персонажа/его цвет» — ваш скин

cg_forceteammodel «модель персонажа/его цвет» — задает скин ваших союзников

cg_forceenemymodel «модель персонажа/его цвет» — задает скин ваших соперников

(для visor, keel, tankjr,crash можно включить яркий скин командой cg_forceenemymodel «keel/bright» )

cg_forcemodel 1\0 включает\выключает ранее указанные замены скинов союзников\противников

cg_drawteamoverlay 1\0 включает выключает панель информации о союзниках

Консольные команды. Часть первая Консольные команды. Часть первая

cg_drawfriend 1\0 включает\выключает показ «лица» противника при наведении на него курсора в правом верхнем углу

cg_drawattacker 1\0 включает\выключает показ лица последнего атаковавшего вас в правом верхнем углу

cg_drawfps 1\0 включает\выключает показ количества фпс в правом верхнем углу

Консольные команды. Часть первая

Консольные команды. Часть первая

com_maxfps «максимальное количество фпс»

cg_drawtimer 1\0 включает\выключает показ внутриигрового таймера

cg_leveltimerdirection 1\0 таймер считает время вниз\вверх

cg_lagometer 1\0 включает\выключает измеритель «лагов» у клиента

Консольные команды. Часть первая

Консольные команды. Часть первая

cg_kickscale 1\0 включает\выключает тряску экрана при попадании в вас

cg_bob 1\0 ваш экран остается статичным при беге\падении\прыжках

cg_fov 70-130 поле обзора , дефолт 90

cg_zoomfov поле обзора при увеличении

cg_drawcrosshairnames 1\0 включает\выключает показ имён при наведении прицела.

cg_crosshairhealth 1\0 раскрашивает прицел в зависимости от вашего количества hp

cg_crosshairpulse 1\0 ваш прицел «пульсирует» при подборе предметов

cg_drawcrosshair 1-10 ваш прицел

Консольные команды. Часть первая

Консольные команды. Часть первая

cg_crosshaircolor 1-7 цвет прицела

Консольные команды. Часть первая

Консольные команды. Часть первая

cg_drawgun 0\1\2 показ оружия, 0-отсутствует,1-качается при ходьбе, 2 -статично

cg_autoswitch 1\0 включает\выключает автопереключение на подобранное оружие

cg_switchonempty 1\0 включает\выключает автопереключение на следующий слот с оружием если в вашем текущем закончились патроны.

Конец первой части. :]

Спасибо Marvelous, qlcfg,

gramota.ru

В следующих частях: настройка hud, video, audio, продолжение weapons настроек, скрипты.

Рейтинг
( 1 оценка, среднее 4 из 5 )
Понравилась статья? Поделиться с друзьями: