Как стать автором
Обновить
47
0
Александр Стешенко @CorvOrk

In-Game Source SDK

Отправить сообщение
Ну и наркомания!
«Русского нет!.. Нет русского!.. Добавьте русский язык!.. Разрабы псы!»

Статья очень понравилась, большое спасибо:)
Это позволяет защищать игры от DoS-атак.

То есть теперь сервер доты перестанет крашиться из-за передачи большого кол-ва трафика через чат?

он должен находиться внутри игрового процесса, где его обнаружит система VAC.

image
Могу добавить, что динамическое кодирование Хаффмана используется в Quake3 для компрессии передаваемых данных (как дельта состояния, так и полного).
Спасибо за статью. Делал keygen для Black&White, читы для Silent Storm, Dota2 и прочее, связанное с играми (разумеется только в целях любопытства). Только у меня интерес к этому проснулся намного позднее — уже в университете — все детство только и делал, что играл (Вы «слезли» с игр за пол года — для меня это было самой настоящей зависимостью, особенно с появлением MMORPG).

Да, все это прокачивает понимание работы ОS, как данные хранятся в процессоре/ОЗУ, ассемблер и многое другое. Только вот в работе это никак не помогает — даже олимпиадное программирование полезнее (узнаете алгоритмы/структуры, может что спросят на собеседовании, раз в сто лет даже что-то можно применить в работе) — слишком узконаправленные знания.
В обсуждениях отмечается, что GHIDRA проигрывает своему оппоненту в скорости и надежности, но ее преимущество заключается в дружелюбном интерфейсе и возможности работы с мобильными ОС.


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

Олимпиады не имеют никакого отношения к промышленному программированию — это больше математика — Вы не получите тут опыта использования средств совместной разработки, технологий, фреймворков, ООП и т.д. Но в тоже время, олимпиады развивают способность четко понимать задачу, фокусироваться над ней и оценивать сложность реализации — эти способности нужны и в промышленном программировании.
Привет, спасибо за статью.

В главе «Пляски со временем» хорошо было бы иллюстрировать картинками/примерами, т.к. это может вызвать трудности у тех, кто с этим не знаком. Это по сути лагокомпенсация и заслуживает отдельной статьи.
Самый простой пример, который можно привести — сбор награды по заканчивающейся акции за пару секунд до ее окончания — клиент считает, что осталось еще целая секунда до завершения акции, но запрос приходит на сервер через две секунды и не проходит валидацию — для него акция уже прошла. Эту штуку без визуализации сложно понять, нужно порисовать таймлайны и возможные варианты.

Использование модели для тестирование интерфейса выглядит для меня новой, помоему это сильно загрязняет модель — будут поля только для клиенте, только для сервера,
общие, те, что должны реплицироваться только локальному игроку — это усложнит понимание модели.

«На самом деле большинству игр нужна только одна команда, ожидающая ответ — GetInitialGameState»
Не соглашусь, таких команд может быть много — зависит от того, как много логики скрывается от пользователя.

«Как команды делятся между серверами»
Первый вариант имеет право быть, так как Вы не можете запросить часть данных — неизвестно, что нужно команде для работы,
что она меняет — соответственно нужен полный стейт.
С другой стороны, это не реал тайм — тут нет необходимости молотизировать 20 раз в секунду логику, тут 1) запрос/ответ
2) не так просто отследить, что клиент покинул игру и нужно закрыть его процесс.
В итоге и стейт нужен полный (кто знает, какие данные нужны команде) + трудно определить, когда клиент покинул игру + процесс по большому счету будет простаивать.
Поэтому открывается N процессов с игровой логикой, они загружают статические правила игры (один раз) и далее получают разных игроков и исполняют над ними разные команды
через общение с кластером, а кластер уже общается с клиентом (в реал тайме игровая логика общается напрямую).
Понял Ваш подход, спасибо. Второй способ (с отдельными командами) выглядит интересней — можно переиспользовать команды; легко компоновать; сервер также отображает эти модельные команды зеркально у себя, все синхронно; для каждой команды вьюшка также описывает свою логику и отдельно ей управляет.
Разве что много команд будет, но это не плохо.

«Сервер присылает нам список:»

По опыту разработки социалок и реал тайма не встречал, чтобы сервер присылал игровые команды. Обычно клиент шлет команды, связанные с логикой, сервер шлет реплику и может слать управляющие команды по типу «у тебя плохое соединение, перезапустись». Как в quake 3 в общем.
Если у Вас клиент выполняется синхронно с сервером, для чего получать от него команды? Клиент сам может спавнить команды и управлять этим (кроме каких-то команд, требующих получения данных от сервера, которые нельзя предсказывать — сокрытие определенной логики — открытие сундучков например, но и там клиент обычно получает данные, не команды).
Не очень понял Ваш подход. Вы описываете случай реал тайма (игровой цикл) или рассматриваете социалки (запрос-ответ)?

«Но анимации совершенно разные и поле должно обновиться в совершенно разные моменты, а не сразу вместе с моделью.»

Если рассматривать социалки (запрос — ответ) — тут обычно делается отдельный запрос на сбор возобновляемого ресурса / побежденного босса / взятии груза. Если заказан самолет с деньгами, деньги лучше забирать отдельным запросом, записывая в модель (на клиенте и сервере) факт того, что груз заказан (который фиксируется в первом запросе). За убийство босса тоже лучше начислять награду отдельным запросом на взятие награды или в запросе на ластхит.

Поля моделей обновляются сразу, вьюшка же может приберечь историю этих изменений и работать с ней, причем, если ваш друг в своем браузере должен видеть, что вы собираете награду и ее много, эта история изменения идет и в модель, чтобы далее ее получил друг и его клиент все порционно отрисовал.

«Босс должен после смерти красиво упасть и только потом зачислятся деньги.»

Награда в моделях начисляется сразу, клиент же может предсказывать сервер (используя тот же сид рандома к примеру), либо ждать награду от сервера (если логику начисления награды нужно скрыть от пользователя) — это не важно, главное, чтобы исполнение команды было упорядоченным и давало одинаковые результаты на клиенте и сервере.
Первый вариант FlowerGivesMoneyView по сути корутина Unity — произошла команда, она изменила модель, далее ее поймала вьюшка и она описывает логику отрисовки (вложенные корутины).
Клиент и сервер синхронны, все чисто. Как ведет себя второй вариант — у нас появляется две команды и вторая команда ждет первую? (которая нужна лишь для анимации
и не изменяет модель, чтобы потом запустить вторую с начислением денег?) Потом каждая команда запускает свой запрос, или это только клиентская штука?

Заранее извиняюсь если неверно все понял.
Согласен с Вами. Poly2Tri намного проще, собственно поэтому и использовал — мне было важно полностью понимать каждое действие — читал статьи + смотрел готовые реализации. По сути использовал связку Poly2Tri c Clipper в качестве «прототипа», потом все переписывал — в целом эта связка делала ту часть работы, которая нужна для построения динамического nav mesh, в основном первые этапы.

По поводу построения сетки — там на самом деле много было проблем из-за float, переписывание на интах сильно помогает, особенно когда речь идет не просто о построении, а о последующем применении рейкаста к этой сетки (например движение персонажа, управляемого игроком при помощи джостика — в RTS с этим проще, там во многом достаточно pathfinding применить)
Спасибо за статью. Пробовал для триангуляции Triangle.NET и poly2Tri — последняя библиотека понравилась больше,
особенно в союзе с clipper (использовал для реализации динамического 2D навигационного меша).
Избавление от double это правильно (тот же recastnavigation, который использует Unity3D, довольстуется float),
но в некоторых случаях недостаточно — лучше полностью переходить на целые числа (как в AStarProject к примеру,
где многие функции используют перегрузку с Vector2/Vector3 на Int2/Int3),
особенно если код будет работать не только на клиенте.
Спасибо, классная статья.
Спасибо за ответ. Это довольно интересная тема для меня, если не против, еще пару вопросов:
1. Хотел уточнить (ответ впринципи ясен, но в статье этого не нашел), правильно ли я понимаю, что все поля, которые находятся внутри компонента должны быть либо простыми типами, либо IComponent,
чтобы кодогенерация могла понять, как их сериализовать и т.п. (аналог UPROPERTY в Unreal)? Не видно, чтобы сами поля обрамлялись в атрибуты (например [IComponent] Invulnerability{[UProperty] int duration;}),
значит поля рефлексией итерируются и делается определенное заключение. То есть в компоненте Transform поле Position является [IComponent]public class Vector{...}?
2. Если говорить о взаимодействии Моделей и Презентера, можете общими словами описать, как это происходит? Как я предполагаю, у Вас в ПрезенторКонтекстаБоя создается и инициализируется ECS.
В этом презенторе происходит подписывание на событие добавления/удаление сущностей. Когда сущность спаунится, презентор оповещается об этом и создает под нее ПрезентерСущности.
Далее вопрос, как построить презентер для компонентов сущности, которые добавляются в рантайме. Например сущность может стать на некоторое время неуязвимой и придумали визуально показывать щит вокруг персонажа.
Как ПрезентерСущности узнает, что появился новый компонент и нужно внутри добавить ПрезентерНеуязвимости? Он оповещается о всех новых добавленных компонентах и под каждый компонент
подбирает и создает нужный презентер, где происходит примерно следующее? public class InvulPresenter(IEntity entity, IInvulView viewContainer) {var invul = entity.GetInvul(); invul.Changed += OnInvulChanged; invul.Removed += OnInvulRemoved; ...}
Здравствуйте Etlay,
Большое спасибо за статью, есть несколько вопросов после прочтения.
1) Правильно ли я понимаю, что у Вас возможно хранение компонентов без привязки к Entity?
(например компонент SpawnAvatarRequest, который не привязан к Entity и несет в себе данные о том, кого и когда необходимо заспаунить)
Почему не сделать SpawnAvatarRequst сущностью? Мое понимание ECS основано на том, что компонент обязательно должен принадлежать сущности.
2) Компоненты могут добавляться динамически в «рантайме». Действительно ли это нужно и используется ли это в игре?
То есть, можно в RuleBook расписать для каждой сущности набор ее компонент при спауне. В процессе игры добавляются ли к сущности новые компоненты, кроме тех, что добавились на спауне?
(интересен конкретно Ваш опыт, в теории конечно понятно, что динамическое добавление компонента к сущности нужно, но встречается ли это на практике у Вас? особенно в шутере)
3) Так как мир инициализируется на сервере и сущности спаунятся на сервере — бывают ли ситуации,
когда на клиенте эта самая инициализация (в момент передачи полного gameState при первом запросе или при рестарте соединения)
превышает время, отведенное для тика? (например Hz 20=50 ms, а полный gameState при ините мира/рестарте сети занимает 120ms).
Если такие ситуации бывают, как Вы с ними работаете?
4) var playerEntity = gs.WorldState.CreateEntity(avatarRequest.Value.PlayerId); И далее идет работа по инициализации компонент (playerEntity.Add...()).
В интерфейсе у сущности для каждого компонента есть своя функция по добавлению? Можете этот момент прокомментировать?) Правильно ли я понимаю, что мне как программисту при добавлении компонента нужно в интерфейсе сущности также еще добавить функцию, которая и реализует добавление этого нового компонента?

Еще раз спасибо за статью.
Советую автору в качестве моделей присмотреться к ESC (https://habr.com/company/pixonic/blog/413729/).
Прочитав первую статью решил, что Вы фрилансер) Спасибо за статьи.
2

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность