Как правильно назначить идентификаторы сущностей в сетевой игре?

17

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

В настоящее время я просто увеличиваю счетчик каждый раз, когда создается объект. Я предполагаю, что идентификаторы со временем закончатся, но я не ожидаю, что у меня будет 4 миллиарда сущностей. Также это позволяет избежать проблемы, если сущность № 5 уничтожена, и мы получаем идентификатор 5. Это означает, что он ссылается на новый № 5 или старый удаленный № 5?

Проблема в том, что я не уверен, как справиться / избежать столкновений. В настоящее время, если клиент получает обновление для объекта с идентификатором выше, чем его текущий «свободный идентификатор», он просто увеличивает свой свободный идентификатор до этого. Но это не кажется очень надежным.

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

Есть ли лучший способ справиться с этим? Должен ли я вообще беспокоиться о переполнении идентификаторов или выходе за пределы допустимого диапазона? Я мог бы добавить код для обнаружения этих случаев, но что бы он сделал, если бы они произошли, кроме аварии.

Другой вариант - использовать что-то с большей вероятностью быть уникальным, например, 128-битный GUID, но это кажется очень тяжелым для игры, которая пытается минимизировать сетевой трафик. Кроме того, реально мне никогда не понадобилось бы больше сущностей за один раз, чем поместилось бы в 32-битное или даже 24-битное целое число.

Благодарность!

Лукас
источник
1
Почему не все клиенты имеют одинаковые объекты? Не синхронизированы ли клиенты? Или это какой-то большой мир, в котором не все клиенты запускают одну и ту же игру.
Филипп
2
Моя архитектура до сих пор слабо соответствует архитектуре UE3 (подробнее здесь ). В основном клиенты знают только о сущностях, которые находятся рядом с ними в мире. Кроме того, клиенты не работают в режиме блокировки, но сервер контролирует большую часть логики и может в любой момент перезаписать данные клиента. Я думаю, теперь, когда я думаю об этом, я мог позволить серверу только создавать сущности и заставлять клиентов использовать RPC для этого. Я не уверен в лучшем подходе. Я графический программист днем ​​:)
Лукас
1
Я думаю, как вы говорите, он должен обрабатываться только сервером, если это вообще возможно в рамках данной архитектуры. Затем храните стопку свободных идентификаторов сущностей, которая существует отдельно от списка / карты сущностей, чтобы вы знали, какие идентификаторы доступны. Если модель авторитетного сервера отсутствует, тогда ваш подход к диапазонам должен работать нормально с точки зрения диапазонов. Четыре миллиарда это много, даже чтобы разделить 4000 игроков в MMO. Затем используйте тот же подход для отслеживания доступных идентификаторов, что и для аутентификации. сервер.
инженер
@Lucas, ваша ссылка говорит: «Сервер идентифицирует набор« соответствующих »субъектов для каждого клиента». Это подразумевает, что сервер знает обо всех сущностях и может перечислять их.
Килотан
1
Конечно, но что, если клиент создает новую сущность A, но прежде чем он сможет получить сообщение о создании, сервер создает новую сущность B, им обоим присваивается один и тот же «свободный» идентификатор.
Лукас

Ответы:

13

Что я сделал, так это заставил сервер делать все . Клиент (ы) может просто попросить сервер сделать что-то, но не может ничего сделать сам. В этом случае сервер всегда будет тем, кто назначит идентификаторы и проблема решена.

Я не имел дела с предсказаниями на стороне клиента, пока сервер ждал одобрения таких действий, как «Стреляй в ракету» или «Сделай солнечную станцию ​​здесь». Эти действия захотят создать сущности, а сущности имеют идентификаторы. До сих пор я просто сижу на большом пальце в ожидании сервера, но я верю, что нужно создать временную сущность, пока вы ждете одобрения сервера. Когда вы получите одобрение сервера, сервер назначит идентификатор, и вы можете обновить или перезаписать временный объект.

Я также не имел дело с переполнением идентификатора, но если сервер находится под полным контролем и обнаруживает переполнение, он может делать любую обработку, которую вы считаете необходимой (перезапуск с 0, выбор из свободного стека, сбой и т. Д.) И все клиенты даже не будут знать или заботиться. Клиенты просто принимают идентификаторы, выданные сервером.

Джон Макдональд
источник
Спасибо за хорошую информацию, ребята! В итоге я решил, что сервер создает все сущности, но если я обнаружу, что это приводит к слишком большой задержке, я попробую метод Тревора.
Лукас
Для специфичных для клиента идентификаторов (необходимых для прогнозирования во время ожидания сервера) вы можете просто использовать префикс идентификатора.
Данияр
6

Когда я сделал это для коммерческой многопользовательской игры, я сделал именно то, что вы предлагаете: использовать 32-разрядное целое число GUID, где верхние восемь бит - это номер игрока, а нижние двадцать четыре бита содержат локально уникальный номер.

Если / когда локальный номер переполнится (в моем случае это почти никогда не произойдет; при нормальном использовании для его выполнения потребовалось бы четыре-пять дней непрерывного воспроизведения в одном сетевом сеансе), владелец отправит Сообщение «Сброс всех моих объектов» и перенумерация всех еще существующих объектов, начиная с нуля назад. В сообщении всем сверстникам было отказано в получении объектов, которые они получили, и запросить их снова.

Более причудливым подходом было бы сообщение «Объект с GUID« n »- теперь объект с GUID« m »» для каждого существующего объекта. Но в моем случае это вряд ли когда-либо могло произойти, и я не думал, что люди действительно будут возражать против удаленных объектов, исчезающих из мира на полсекунды, после пяти дней непрерывной игры в одной сетевой сессии. ;)

Тревор Пауэлл
источник
Это хорошая идея для обработки переполнения. Просто, но я не думал об этом :). «Забывать» все ваши сущности - это хорошо, так как он может в основном повторно использовать тот же код, который использует клиент, когда присоединяется к игре
Лукас
4

Если ваши клиенты могут порождать свои собственные сущности, я полагаю, у вас есть одноранговая многопользовательская игра.

Если это так, у вас, вероятно, не слишком много клиентов. Конечно, не более 256. И идентификатор вашей сущности гарантированно умещается в 24 бита (16000000+ сущностей достаточно для всех!). Итак, просто сделайте старший байт вашего идентификатора равным идентификатору клиента:

entityId = clientId<<24 + (maxEntityIn++)

или что-то.

И если я ошибаюсь и у вас есть авторитетный сервер, просто никогда не создавайте новые сущности на клиентах.

Ничего
источник
1

Я использую «самый наивный» метод (просто увеличиваю целое число для каждого нового идентификатора) в моей постоянной многопользовательской игре, и он отлично работает, потому что я не позволяю клиенту создавать новые идентификаторы: s.

Если вы позволите клиенту принять решение (используя объясненную технику GUID), он также может внести различные ошибки, назначив старый идентификатор новому элементу (это то, о чем я думал в течение 5 секунд, думая, что это 5 секунд). может быть множество других лазеек).

Как обычно, чтобы предотвратить мошенничество , сервер должен ВСЕ создавать и проверять .

Valmond
источник