Синхронизация

Версия Minecraft
1.7.10
API
Forge
236
4
22
Добрый вечер всем. Хотел бы спросить, как майнкрафт выполняет передачу с сервера клиентам данные о надетой броне и предмете в руке игрокам? У меня есть мод, где на сервер-сайде игроку "привязаны" 4 айтемстака. На клиенте их нужно рендить, на подобие брони. Ясное дело, что мне нужно как-то передавать айтемстаки клиентам с сервера. Думаю над этим 2ой день, идей много.. Но нужно сделать, чтобы не было нагрузки.

В 1 моде видел такую систему: Клиент послал пакет-запрос серверу (внутри ник игрока) - сервак принял пакет, нашёл по нику игрока, получил эти айтемстаки и отправил пакетом тому, кто запросил. Клиент же у себя имеет мапу "Ник игрока: его содержимое" и пока содержимое null + игрок видит игрока в камере обзора - идёт спам пакетом серверу с запросом. В принцепе варик рабочий, но ужасно нагрузочный, особенно если учесть то, что читами пакеты можно массово спамить - отличная "дыра" для ддоса сервака...

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

Затем на других форумах нашёл такую идею: Каждый тик игрока искать игроков в радиусе от игрока и хранить в мапе флажок, нужно ли слать пакет данных и если нужно - шлётся. Это очень оптимальный вариант, но из-за ежетикового поиска игроков в радиусе - этот способ становится самым плохим, ибо нагрузка будет дикой.

По этому я пришёл сюда спросить, как же майнкрафт выполняет такого рода синхронизацию для рендера к примеру брони игрока. Возможно у самого майна есть оптимальный способ синхронизации...
 
Решение
EntityLivingBase#onUpdate. Проверяется каждый тик, изменялся ли предмет в слотах брони или в руках. Если да - шлем всем игрокам которые "могут видеть" данного игрока пакет. Могут видеть в данном случае вроде 512 блоков. Именно в таком радиусе доступен другой игрок на клиенте.
1612203088417.png
EntityTrackerEntry#tryStartWachingThis. Вызывается когда игрок впервые увидел другого игрока (вошел в радиус видения, тпшнулся, пришел из другого измерения, вошел на сервер и тд).
1612203137771.png

Если тебе нужно сделать что-то подобное - вот паттерн. Копируешь верхний метод, хранишь "предыдущие" стаки в IEEP, сравниваешь с текущими.
Для второго же случае есть ивент PlayerEvent.StartTracking, в котором делаешь всё по аналогии.
EntityLivingBase#onUpdate. Проверяется каждый тик, изменялся ли предмет в слотах брони или в руках. Если да - шлем всем игрокам которые "могут видеть" данного игрока пакет. Могут видеть в данном случае вроде 512 блоков. Именно в таком радиусе доступен другой игрок на клиенте.
1612203088417.png
EntityTrackerEntry#tryStartWachingThis. Вызывается когда игрок впервые увидел другого игрока (вошел в радиус видения, тпшнулся, пришел из другого измерения, вошел на сервер и тд).
1612203137771.png

Если тебе нужно сделать что-то подобное - вот паттерн. Копируешь верхний метод, хранишь "предыдущие" стаки в IEEP, сравниваешь с текущими.
Для второго же случае есть ивент PlayerEvent.StartTracking, в котором делаешь всё по аналогии.
 
ntityLivingBase#onUpdate. Проверяется каждый тик, изменялся ли предмет в слотах брони или в руках.
Если инвентарь свой, то можно не чекать каждый тик, а только при изменении стаков в слотах
 
Будет дыра. Достал стак из слота (getStackInSlot), изменил нбт. Всё, ты уже не задетектишь никак изменение стака в слоте.
Да, ты у себя можешь так не делать, но откуда ты знаешь что в других модах так делать не будут?
Лучше проверять каждый тик как это делает майнкрафт, тогда изменения в любом случае будут обработаны.
 
Это если рендер как-то зависит от нбт
У брони он зависит, например, от зачарований
 
EntityLivingBase#onUpdate. Проверяется каждый тик, изменялся ли предмет в слотах брони или в руках. Если да - шлем всем игрокам которые "могут видеть" данного игрока пакет. Могут видеть в данном случае вроде 512 блоков. Именно в таком радиусе доступен другой игрок на клиенте.
Ивента PlayerEvent.StartTracking в 1.7.10, увы, нет. А способ, показанный первым скрином, как я понял, нужно вызывать ежетиково в PlayerTickEvent. Но не слишком ли нагрузочным будет такой ужас? И можно ли чуток подробнее о методе #func_151247_a(this, пакет)? this - это игрок, который отправляет данные о себе или это тот кто должен получить данные? Этот метод шлёт пакет игрокам в зоне видимости игрока?

И да. В таком случае если игрок зайдёт на сервер - он не получит никаких данных о айтемах игроков, пока игроки их не обновят. А слать при входе огромный пакет со всеми айтемами игроков - не очень хороший вариант.
 
Ивента PlayerEvent.StartTracking в 1.7.10, увы, нет
Есть, посмотри внимательнее. Ты не тот PlayerEvent открыл, их у форджа два.

А способ, показанный первым скрином, как я понял, нужно вызывать ежетиково в PlayerTickEvent. Но не слишком ли нагрузочным будет такой ужас?
Нет. Метод очень простой и никакой нагрузки он не несет.

И можно ли чуток подробнее о методе #func_151247_a(this, пакет)? this - это игрок, который отправляет данные о себе или это тот кто должен получить данные? Этот метод шлёт пакет игрокам в зоне видимости игрока?
Я же это и написал выше -.- Открой реализацию и посмотри как достать всех видимых игроков для текущего игрока.

И да. В таком случае если игрок зайдёт на сервер - он не получит никаких данных о айтемах игроков, пока игроки их не обновят. А слать при входе огромный пакет со всеми айтемами игроков - не очень хороший вариант.
PlayerEvent.StartTracking!!!!!!!

Это если рендер как-то зависит от нбт
У брони он зависит, например, от зачарований
У тебя будут лежать неверные данные на клиенте. Это уже в корне неверно. В один момент ты захочешь получить зачарования на броне другого игрока с клиента и потратишь часы, если не дни, чтобы понять почему же на сервере они одни, а на клиенте другие.
 
Есть, посмотри внимательнее. Ты не тот PlayerEvent открыл, их у форджа два.
PlayerEvent.StartTracking!!!!!!!
Сорри, не знал. Посмотрел по импортам - нашёл нужный.
Нет. Метод очень простой и никакой нагрузки он не несет.
Ну хз, циклом 4 слота прогонять ежетикого) Ну что ж, дела нет.

Я же это и написал выше -.- Открой реализацию и посмотри как достать всех видимых игроков для текущего игрока.
Ну ок, покопаюсь. Ненавижу обсфа-методы майна
 
Я же это и написал выше -.- Открой реализацию и посмотри как достать всех видимых игроков для текущего игрока.
Ну вообщем как я понял мне нужно каждый тик игрока искать его трекинг игроков. Иметь хешмапу, в ней держать UUID игрока : его старые данные и потом циклом по трекинг игрокам идти, брать их инвентарь и сверять с реальным инвентарём и в случае несоотвествия синхронизировать и обновлять данные в мапе
 
У тебя будут лежать неверные данные на клиенте. Это уже в корне неверно. В один момент ты захочешь получить зачарования на броне другого игрока с клиента и потратишь часы, если не дни, чтобы понять почему же на сервере они одни, а на клиенте другие.
Согласен, если рендер или другая логика на клиенте зависит от нбт предметов в инвентаре, то имеет смысл поддерживать актуальность данных на клиенте.
Кстати, я щас подумал, можно оптимизировать чек изменения предмета: вместо того чтобы каждый тик чекать, сделать обертку(или хук) для итемстака, чтобы все его сеттеры(и сеттеры его нбт) помечали инвентарь как грязный(mark dirty), чтобы делать чек и синхронизацию только если инвентарь dirty
 
Согласен, если рендер или другая логика на клиенте зависит от нбт предметов в инвентаре, то имеет смысл поддерживать актуальность данных на клиенте.
Кстати, я щас подумал, можно оптимизировать чек изменения предмета: вместо того чтобы каждый тик чекать, сделать обертку(или хук) для итемстака, чтобы все его сеттеры(и сеттеры его нбт) помечали инвентарь как грязный(mark dirty), чтобы делать чек и синхронизацию только если инвентарь dirty
Ну с миксинами не дружу. По этому уже не буду "вылизывать дерьмо" и сделаю просто проверку в тикивенте старого инвентаря на соответствие с новым. Так будет проще и 100% работоспособно.
 
Ну вообщем как я понял мне нужно каждый тик игрока искать его трекинг игроков
Тебе каждый тик нужно сверять итемстаки и если они отличаются - слать пакет с этим стаком.

Удобнее делать с помощью IEEP. Мне вообще не нравится когда в коде куча подобных мать с <ИмяИгрока, Какие-тоДанные>.

чтобы все его сеттеры(и сеттеры его нбт)
Ну, во-первых, не знаю как в 1.12.2, но в 1.7.10 нет сеттеров и все меняется через переменные. Опять же, никто не отменял рефлексию. Короче, это может быть оптимизацией, но зная что делают разные моды в коде, это может вылиться в супер-мега трудноуловимые проблемы. Оно того не стоит.
 
Тебе каждый тик нужно сверять итемстаки и если они отличаются - слать пакет с этим стаком.
Это я уже понял и делаю. Только в таком случае не ясно зачем ивент трекинга ловить, ведь всё равно перебираем каждый тик "рядом стоящих" игроков.

Удобнее делать с помощью IEEP. Мне вообще не нравится когда в коде куча подобных мать с <ИмяИгрока, Какие-тоДанные>.
Возможно, но у меня уже сложилось так, что без экстенд пропертов. Учитывая что мне нужен оффлайн-доступ пришлось свою систему чтения и записи гнать + на ней уже строить остальное. А вот в мапе не имя игрока, а UUID. На uuid куда безопаснее, особенно если говорить о серваках с возможкой менять игровой ник. Тут уже на вкус и цвет - товарищей нет.
Ну, во-первых, не знаю как в 1.12.2, но в 1.7.10 нет сеттеров и все меняется через переменные. Опять же, никто не отменял рефлексию. Короче, это может быть оптимизацией, но зная что делают разные моды в коде, это может вылиться в супер-мега трудноуловимые проблемы. Оно того не стоит.
Вот из-за рефлексии + миксинов/ASM лучше и пойти через ежетиковую сверку айтемов из "кеша" игроков и текущих айтемов + синка при различии. Ненавижу эти миксины... От них дольше запускается игра и юзать сложно.
 
Только в таком случае не ясно зачем ивент трекинга ловить, ведь всё равно перебираем каждый тик "рядом стоящих" игроков.
Потому что у игрока изменился слот - он отправил всем рядом - всё. Далее к тебе подбегает человек, твои слоты никак не менялись, соответственно человеку пакет не полетит и он не узнает вообще о твоей экипировке. Ты ведь в апдейте шлешь пакет ТОЛЬКО КОГДА ЭКИПИРОВКА ОБНОВЛЯЕТСЯ.
Для этого и нужен этот ивент. Я описал выше что он вызывается когда ты впервые "трэкаешь" игрока и его данные должны прилететь тебе на клиент, а вместе с ними ты шлешь свои данные о экипировке.
 
Ты ведь в апдейте шлешь пакет ТОЛЬКО КОГДА ЭКИПИРОВКА ОБНОВЛЯЕТСЯ.
Угу, старая в мапе лежит <UUID, ItemStack[]>. Там стоит метод getOrDefault. Если игрок ещё не видел игрока или имеет "фальшивые" данные в кеше - происходит синк + обновление данных. Ясное дело никакой ивент тут не нужен.
 
Ты опять меня не понял. Я не знаю уже как тебе объяснить.
Кароче, делай без трекинга, потом попробуй подойти к игроку, затем тпшнись далеко от него, тем игроком измени экипировку, а игроком который тпшнулся вернись обратно. Увидишь что для того кто тпшался экипировка игрока не изменилась, хотя он ее менял.
 
Назад
Сверху