Как стать автором
Обновить

Комментарии 23

Огромное спасибо за статью, подчерпнул для себя пару вещиц, которые не знал)

Единственное не очень понятно, ловушки касаются только С++ или БП?
Вызов RPC на сервере не выполнит саму функцию на сервере, только отошлёт команду выполнить её на клиенте. Если необходимо выполнить её и на сервере, надо вручную вызвать Implementation.

В БП Multicast RPC, например, вызывается и на сервере тоже, будучи вызванном с сервера.

Кстати, ещё одна ловушка в БП и плюсах:
OnRep функции от переменных вызываются на клиенте при получении репликации, а на сервере при простом изменении. Но если менять переменную не через Set, а другим способом (например инкремент или SetByRef), то OnRep на сервере не вызовется. В какой-то момент я просидел с этим долго.
А в плюсах изменение переменной вообще не вызывает OnRep на сервере, будь то инкремент или нет. Нужно после изменения вручную вызывать OnRep.
Зачастую, конечно, не нужен онреп на самом сервере, но, например, бывает полезно, когда нужно вызывать диспатчер всякий раз, когда меняется значение. При этом нужно сообщить всем, включая сервер.
C++, все сетевые вещи строго переношу в код. На уровне прототипа БП нормально использовать для сети, но для продакшна такие вещи в них оставлять опасно.

Кстати, ещё одна ловушка в БП и плюсах:

Спасибо за дополнения! :) Еще из веселого — переопределенная в дочернем классе мультикаст функция в блюпринтах будет вызываться дважды, если дёрнуть Parent функцию. Описано здесь, если кому интересно.
Большое спасибо за статью, очень полезная.

Я еще не очень опытный, и первый раз слышу что-то про упаковку чего либо в int и битовые маски, мне это представляется как массив булеанов в виде числа, но как его разбирать? Особенно по объектам, или реализовывать битовые маски.

Был бы очень благодарен за какой-нибудь материал по этой теме, или направления в гугл, а то по своим запросам ничего не нашел.
я так думаю простыми битовыми операциями
Как уже было сказано An70ni выше, это обычные битовые операции :) В гугле находятся кучей туториалов по запросу «c++ bit operations», например, вот: www.cprogramming.com/tutorial/bitwise_operators.html
Главная проблема сетевого стека Unreal Engine — сетевой стек Unreal Engine. Отсюда и мамкины читеры, которые ваяют их на коленке за полчаса.
Иногда бывает еще забавнее — к примеру, радар от одной игры работает в другой буквально без допиливания :)
Это актуально для любого массового движка, только не имеет никакого отношения к сетевому стеку.

Есть принципиально два разных направления хаков:
1. Хак клиента, который вы описали. Мапхаки, воллхаки, эймхаки и иже с ними. Борьба с этим — постоянное противоборство щита и меча. Чем популярнее технология клиента или сама игра — тем больше высококлассных спецов его «разбирают». Читаки пишутся далеко не «мамкиными хакерами» (это потом уже тулзы общего назначения они стараются приладить, но серьёзные читаки это весьма бизнес). Защита — определять по косвенным признакам и банить. Сложно, дорого, не надежно.
2. Хаки косяков сетевой архитектуры. Например, когда клиент решает откуда и куда он выстрелил, а сервер ему верит. Очевидно, это кривые ручки разработчика игры, давшего клиенту авторитарные права на такие вещи. Защита — бить по ушам разработчика. Архитектура, которая не верит клиенту ни в чем, кроме инпута, полностью устойчива к такому виду хаков.

Если ваша игра популярна, с хаками из первого пункта все равно бороться самим ;)
Оук… Вы таки уверены, что на самом деле знаете Unreal Engine, сетевой стек Unreal Engine и славу сетевого стека Unreal Engine? :)

Потому, что сейчас мне показалось что вы обычный кодер, который зачем-то спорит о том о чем вообще даже не догадывается.

радары и сетевой стек
image


Очень толсто :) Хочется увидеть ваш увлекательный рассказ на тему сетевого стека на анриале. Порадуйте меня и общественность срывом покровов.
Что толсто? Я вот теперь уже абсолютно уверен, что как работает *меч* (и собственно каким должен быть щит) вы понятия не имеете. Собственно, кол-во читеров говорит за себя. Если из современных — PUBG тоже понадеялся на дефолтный стек *трольфейс*

PS я уже больше 14 лет ковыряю UE с позиции меча, кудаж мне до великого гуру с хабра :)

Пока ничего кроме голых утверждений ничего не вижу. Ссылочка на проект выше, продемонстрируйте навыки что ли? Мапхак — банальная задача, а что-нибудь более интересное дак вообще смотрелось бы весомым аргументом.

P.S. Про PUBG это даже не смешно. Первые версии и спидхаку были подвержены, ну и? Если вы его копали, вы прекрасно знаете какие вещи там архитектурно были косячны со старта, что для беты весьма ожидаемо.
Спидхак всё еще там ;), а еще и «телепортация» появилась, не знаю насколько успешно банят таких.
Вы пишите так будто сетевой стек в анриле это что-то невероятно сложное, и только Вам удалось его понять.
Проблема тут не в сети а в данных которые передаются. Если клиенту передавать данные о всей карте, то так или иначе можно написать мапхак.
Единственный выход — это не передавать всю карту, а только то, что видит пользователь. Причем для каждого клиента нужно отсылать то, что видит именно этот клиент, а это может создать дополнительные сложности в разработке, поэтому многие забивают на это.
В случае кодирования до 1024 объектов можно было бы обойтись всего двумя int32 (перемножение битовых масок)

Ни кто не подскажет, как 64 битами закодировать 1024 объекта?
Кодируется индекс + маска на 32 объекта, т.е. данный метод предполагает не репликацию массива, а отправку RPC. В случае если мир упорядочен разумно блоками в мире (например, персонаж въезжает в кучу объектов, которые лежат в одной маске или «рядом»), потребление сети и CPU минимально.
Так же хотелось бы добавить следующее:
Если multicast функция помечена как unreliable и имеет входные аргументы, то на клиентах она не вызывается
Нет, если у вас такое поведение unreliable функции, то это первый показатель что сеть у вас «забита». UFUNCTION(Client, Unreliable, NetMulticast) отлично доходят даже с большим числом параметров при нормальной загрузке сети (у нас немало вещей ходят на клиенты таким способом :) ).
Не могли бы Вы на пальцах расписать каким образом все таки кодируется? Или дать наводку, что почитать по этому поводу? Крутил и так и этак битовые маски и все равно не получается закодировать несколько значений, чтобы потом получилось корректно восстановить
Посмотрите www.cprogramming.com/tutorial/bitwise_operators.html, здесь всё очень подробно расписано. Особенно посмотрите пример про машины, в частности:

int is_in_use(int car_num)
{
    return in_use & 1<<car_num;
}
Прошу прощения — не к тому комментарию написал.

Битовые операции это дело ясное. Закодировать в 32хбитной переменной 32 булевых значения проще простого. Я был озадачен тем, как имея 64 бита можно закодировать 1024 значения:
В случае кодирования до 1024 объектов можно было бы обойтись всего двумя int32
Речь идёт о кодировании объектов в RPC. Можно представить это как матрицу 32х32, первый инт — будет задавать к каким строкам применить состояние второго инта. Т.е. это некий аналог «индекс + состояние».
Теперь ясно. А я воображал, что состояние 1024 объектов упаковывается какой-то магией в два int32
Зарегистрируйтесь на Хабре, чтобы оставить комментарий