Это не одноранговая игра, это клиент-серверная.
ИДЕЯ 1. Передавать с сервера картинку. Всё, читерство пресечено на корню. Это те самые Google Stadia и PS Now. Недостатки — в огромной нагрузке на сервер и задержках между управлением и картинкой. Как их решить?
ИДЕЯ 2. Передавать с сервера некую информацию, по которой клиент будет строить картинку. Нагрузка на сервер меньше — он не занимается рендерингом. Зато появляется первая предпосылка к жульничеству — по этой информации жульническая программа определяет, где находится враг, и наводит оружие. Но остаётся недостаток: всё та же огромная задержка между управлением и картинкой. При этом задержку никак нельзя улучшить — у нас то самое «пространство-время», знакомое из теории относительности.
О чём я: между Землёй и Луной секунда, и случились два события, на Земле и на Луне. Возможны три варианта: а) свет доходит от Земли до Луны, и событие на Земле заведомо раньше для любого наблюдателя; б) свет доходит от Луны до земли, и событие на Луне заведомо раньше; в) не успевает дойти ни тот, ни другой свет, и хрен его знает, какое раньше — для одних наблюдателей земное, для других лунное. Подобное пространство-время есть и в любом динамичном мультиплеере.
ИДЕЯ 3. Ну, если задержку не улучшить, купируем её тем, что клиент может как-то предсказывать, чтó остальные будут делать, пока пакет ползёт от сервера. Чего не хватает? 1) Клиенты могут внезапно появляться в поле зрения, и не очень хотелось бы, чтобы мы зашкерились за углом, а враг появился ХЗ где, причём где — это зависит от нашего пинга; 2) Из соображений серверной производительности вопрос «видит ли клиент А клиента Б?» желательно решать очень приблизительно, с запасом — Z-буфер решит эту задачу значительно лучше, чем вычисление на процессоре, видит ли клиент А мизинец клиента Б.
Есть ещё такая штука: представьте себе, у клиента А пропала связь. Он со своей пропавшей связью начинает крутить мышью, и не хотелось бы, чтобы в момент появления связи этот клиент умер от ХЗ кого, кого он даже не видел. Ну или со связью в порядке, но А очень насобачился работать мышью. Так что вопрос «видит ли один другого» обычно не рассматривает направление взгляда, только геометрию уровня.
Да, для таких вопросов все эти конструкции типа «запрос-ответ», «доказательство работы» или «доказательство с нулевым знанием» только повышают ту самую противную задержку и вообще не пригодны для динамичной игры.
Вот, собственно, и причина wallhack’ов: сервер принял решение, что клиент А, возможно, видит клиента Б, и начинает передавать его положение. И потому wallhack’и обычно не работают, если Б далеко: сервер понимает, что Б не виден и в ближайшее время не будет виден.
Есть ещё такая помощь клиенту, связанная с тем, что есть мощные виды оружия вроде снайперской винтовки, с огромной разницей между «попал» и «промазал». Каждый клиент видит своё в зависимости от работы сети (вспомните фразу «ХЗ, что раньше»), и в момент прихода информации о выстреле сервер пытается восстановить, что именно видел клиент на своём экране, и по этой картинке решает, попал или нет (на этом основан глюк «спрятался за углом, и всё равно убили»). Но эту помощь тоже эксплуатируют: представьте себе, пакеты клиент→сервер, которые идут по штуке за, скажем, 50 мс, отправляют по пачке за 0,3 секунды — больше типичного времени компенсации задержек, но меньше типичного времени реакции. Получается, что персонаж скачет (клиенты, заглядывающие наперёд на 100 мс, отказываются предсказывать дальше — пусть он лучше зависает, чем тыкается в стены), причём скачет так, что в него хрен выстрелишь (пока среагируешь, он перескочит в другое место). А поскольку пакеты сервер→клиент ходят исправно, а сервер руководствуется прикидкой, что видел клиент, клиент всё видит и метко стреляет, а в него никто попасть не может. Если этот трюк исполнять автоматически только при появлении врага на экране, это будет максимально беспалевно — ну у игрока начались перекэширования из-за того, что видеопамяти не хватило. Эту штуку можно сделать даже на приставке, даже не разбирая её — нужен свитч (приставки всё-таки насобачились сообщать, что кто-то физически режет провод), кусок витой пары, моторчик с оптопарой и педалька под ногу. А для некоторых игр хватает свитча и педали, главное не жадничать и отпускать её иногда.
А теперь вместо «чечни» (я так обозвал Counter-Strike — он появился в те времена, когда война в Чечне превратилась в антитеррористическую операцию) возьмём какой-нибудь преферанс. В чём разница? А в том, что игра не динамичная! И потому тактика «передавать только те данные, что нужны для рендеринга» вдруг становится годной. И если вы в преферансе сможете палить чужие карты — автор разгильдяй!
Скажу честно, я не знаю, как на всех этих chess.com компенсируют задержки в шахматном суперблице типа «три минуты на партию». Если средняя игра тридцать-сорок ходов, то задержки в 0,1 секунды отъедят 3…4 секунды, а задержки в 0,2 — 6…8. Но из-за шахматного жульничества и далеко ушедшей дебютной теории основной формат игры — именно суперблиц.
В общем, хрен вы реализуете диплом о защите от жульничества, не понимая, как работает мультиплеер и откуда жульничество берётся. А берётся жульничество из трёх предпосылок: 1) участники мультиплеера живут в релятивистском пространстве-времени; 2) очень хочется экономить вычисления на сервере; 3) жульничество иногда маскируют под обычные для компьютерного мира явления вроде сетевого затора или долгого кадра.
Да, как реально защищают от жульничества: 1) Не допускают никого постороннего в программу-клиент, чтобы даже пакеты нельзя было расшифровать; 2) Ловят программы-жулики по принципу антивируса; 3) Передают клиентам как можно меньше того, что они знать не обязаны; 4) Ловят признаки компьютерного вмешательства в изображение или управление.