Unglitch — это мод для Minecraft, не позволяющий объектам (постоянно или временно) проходить сквозь стены. См. Https://mojang.atlassian.net/browse/MC-2025 и https://mojang.atlassian.net/browse/MC-10. Он также исправляет некоторые другие сбои, связанные с сущностями.
См. Также:
- http://chunkbase.com/mods/unglitch
- http://www.minecraftforum.net/topic/1920678-162-unglitch-fix-for-escaping-animals-and-more/
Это репо включает в себя большинство соответствующих фрагментов исходного кода (выполните поиск по запросу «Unglitch», чтобы быстро найти изменения в более крупных файлах) и несколько тестовых миров.
Вот довольно техническое описание обнаруженных мной проблем. и как я решил их в моде:
- 1) Состояние гонки (поток клиента и сервера)
- Причина
- Решение
- 2) Неправильные ограничивающие рамки столкновения (Сундуки, наковальни)
- 3) Ошибки с плавающей запятой при загрузке сущности
- Причина
- Решение
- 4) Проблемы синхронизации позиции объекта
- 5) Регулировка позиции, полученной с сервера
- 6) Разное
- Остающиеся проблемы?
1) Состояние гонки (поток клиента и сервера)
Иногда сущности могут покидать огороженные области, «глючая» через блоки во время обычного игрового процесса. Это может произойти только в том случае, если используется интегрированный сервер (однопользовательский или открыт для локальной сети) и только с определенными блоками. Чем больше сущностей сталкивается с определенным блоком, тем выше вероятность их побега. Есть и другие части игры, на которые влияет та же основная ошибка.
Причина
Когда Minecraft проверяет столкновение объектов с блоками, он сначала собирает все ограничивающие рамки столкновения, которые могут пересекаться с объектом в списке. Во многих случаях эти ограничивающие прямоугольники различаются в зависимости от метаданных самого блока (например, хопперов) или в зависимости от идентификатора соседних блоков (например, ограждений) и должны вычисляться во время выполнения.
Проблема в том, что некоторые блоки сначала сохраняют вычисленные границы блоков столкновения в своем глобальном объекте блока, прежде чем они позже снова прочитают эти значения, чтобы добавить их в список ограничивающих блоков.
Для Например, вот фрагмент из BlockFence, который добавляет свои текущие блоки столкновений (до двух) в список:
public void addCollisionBoxesToList (...) {... if (...) {//создаем и добавляем кусок север-юг this.setBlockBounds (var12, 0.0F, var14, var13, 1.5F, var15); super.addCollisionBoxesToList (par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); } ... if (...) {//создаем и добавляем восточно-западную или центральную часть (изолированный забор) this.setBlockBounds (var12, 0.0F, var14, var13, 1.5F, var15); super.addCollisionBoxesToList (par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity); } ...}
Метод this.setBlockBounds сохраняет границы, которые передаются как параметры объекту (this.minX, this. minY, this.minZ, this.maxX, this.maxY, this.maxZ) и super.addCollisionBoxesToList считывает эти значения для создания объекта граничной рамки (с выравниванием по оси), который затем добавляется к список.
Это не было бы проблемой, если бы этот метод выполнялся только одним потоком. Однако со встроенным сервером и клиент, и сервер вызывают один и тот же метод для одного и того же объекта для проверки конфликтов. Таким образом, следующая последовательность является примером того, что может вызвать сбои:
CLIENT THREAD: setBlockBounds (...)//установить север-юг кусокSERVER THREAD: setBlockBounds (... )//установить кусок восток-западSERVER THREAD: addCollisionBoxesToList (...)//фрагмент восток-запад добавлен в список (правильно) CLIENT THREAD: addCollisionBoxesToList (...)//фрагмент восток-запад добавлен в список (НЕ ПРАВИЛЬНО)
Таким образом, в конечном итоге неправильные ограничивающие рамки столкновения могут быть переданы проверке столкновения. Например, обычное ограждение может рассматриваться как угловое ограждение при проверке столкновений, позволяя объектам сбиваться внутри его границ и заставляя дальнейшие проверки столкновения полностью игнорировать блок (поскольку объект уже находится внутри него).
Я обнаружил, что следующие блоки подвержены аналогичному воздействию:
- Пивоваренная стойка
- Котел
- Какао
- Дверь
- Конечная рама портала
- Забор
- Половина плиты
- Бункер
- Лестница
- Панели
- Основание поршня
- Удлинитель поршня
- Череп
- Лестница
- Люк
- Стена
Решение
Насколько мне известно, есть несколько возможных решений, чтобы исправить это. Одним из решений может быть синхронизация потоков, чтобы они не собирали блоки столкновений одного и того же блока одного типа, или использовать два разных объекта блоков (границ) для клиента и сервера. Однако мне не удалось найти решение, которое не потребовало бы большого количества изменений кода и рефакторинга; Итак, для мода я решил применить исправление Дэниела Кинга для этой проблемы (источник), которое исправляет все связанные ошибки (возможно, с небольшим снижением производительности).
2) Неправильные ограничивающие рамки столкновения (Сундуки, наковальни)
Minecraft часто использует неправильную ограничивающую рамку для сундуков и наковальней, что приводит к тому, что игроки отталкиваются от них, а NPC могут проходить через них (см. MC-1635 и MC-1669). Демонстрацию можно найти здесь: http://www.youtube.com/watch?v=y1kon5Wax8I, хотя, похоже, сейчас она влияет только на наковальни и сундуки.
Это легко исправить, добавив (переопределение) следующего метода для BlockAnvil и BlockChest:
public AxisAlignedBB getCollisionBoundingBoxFromPool (World par1World, int par2, int par3, int par4) {this.setBlockBoundsBasedOnState (par1World, par2, par3, par4); return super.getCollisionBoundingBoxFromPool (par1World, par2, par3, par4);}
Это гарантирует, что ограничивающая рамка обновляется перед обнаружением столкновения. Тот же метод используется и для других блоков, таких как люки. Однако он подвержен состоянию гонки, упомянутому в 1). Исправление состояния гонки, используемое для мода, может учесть это, хотя.
3) Ошибки с плавающей запятой при загрузке сущности
Сущности иногда могут также давать сбой через любой блок при загрузке фрагмента (когда они читать из NBT). Это должно повлиять практически на любую среду (клиент и сервер). Чаще всего это происходит, когда координата X или Z близка к степени двойки или когда объект движется вверх.
Причина
Позвольте мне Начнем с того, что я не эксперт в арифметике с плавающей запятой, так что проблема может быть больше, чем то, что я выяснил.
В любом случае, вот что, как мне кажется, происходит: Minecraft, у каждой сущности есть два способа описать свое положение:
- this.posX/this.posY/this.posZ: центр объекта (минимальная координата для y)
- this.boundingBox: содержит минимальные и максимальные координаты ограничивающего прямоугольника объекта (minX, minY, minZ, maxX, ..).
Проверки столкновений ( происходит каждый тик игры) выполняются с использованием только ограничивающей рамки. И как только они будут завершены, значения ограничивающего прямоугольника применяются обратно к полям posX/posY/posZ, чтобы все было синхронизировано. При сохранении объекта сохраняются только атрибуты posX, posY и posZ, а при повторной загрузке ограничивающая рамка будет воссоздана из этих значений.
Проблема, которую я обнаружил в этом, заключается в том, что в редких случаях воссозданный ограничивающий прямоугольник отличается от исходного. Например, если был сплошной сплошной блок от x = 0,0 до x = 1,0, и объект с шириной = 1,0 столкнулся бы с ним, размер x его ограничивающей рамки мог бы быть таким (вымышленный пример с произвольные значения):
minX = 1.000001maxX = 1.999998
Затем центр можно рассчитать как
posX = 1.49998
, что может привести к воссозданному ограничивающему прямоугольнику
minX = 0,99999maxX = 1,99999
Во время проверки столкновений Minecraft будет рассматривать объект как находящийся внутри блока (поскольку 0,99999 меньше 1,0) и игнорировать любые столкновения между ними.
Решение
Опять же, может быть несколько подходящих решений. Хотя из того, что я знаю об арифметике с плавающей запятой, такие ошибки неизбежны. Распространенный способ предотвратить ошибки, вызванные этим, — использовать значение эпсилон для сравнений. Поэтому я заменил сравнения, отвечающие за определение того, блокирует ли блок столкновений попытку перемещения объекта, на метод, описанный здесь: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
Таким образом, сущности, которые едва находятся внутри блоков, не смогут двигаться дальше внутрь, а вместо этого будут вытеснены. При сравнении целочисленных значений допустимый диапазон ошибок масштабируется с величиной возможных ошибок округления. Однако даже для координат на 10 м диапазон будет ниже миллионной, поэтому в игре должно быть мало побочных эффектов..
4) Проблемы синхронизации позиции объекта
-
В текущей реализации EntityTrackerEntry ( класс, который отправляет обновления позиций объектов) существует несколько логических ошибок, которые могут привести к рассинхронизации позиций объектов клиента и сервера. Ошибки на стороне клиента приводят к сбоям, которые обычно устраняются при следующем (относительном или абсолютном) обновлении положения. Я обнаружил следующие ошибки:
- при отправке обновления абсолютной позиции ( Packet34EntityTeleport ) сервер не всегда сохраняет данные объекта позиция (для последующих обновлений относительного положения)
- , когда во время первого (попытки) обновления не было отправлено ни одного пакета, сервер сохраняет позицию
- пакеты порождения содержат текущую позицию объекта, а не сохраненную в объекте трекера.
Интересно, что это также исправляет https://mojang.atlassian.net/browse /MC-19331. Это связано с тем, что при размещении вагонетки на склоне сервер сначала отправляет нижнюю позицию (как если бы она была размещена на плоских рельсах) в пакете появления, а затем пытается обновить повышенную позицию, которая, однако, отменяется (первое обновление ), но позиция сохраняется, как если бы она была отправлена клиентам.
-
Когда клиент порождает слизи или стареющих животных, их реальный размер устанавливается слишком поздно , что может привести к временным визуальным сбоям после первого тика.
-
Сферы XP порождают на стороне клиента в несколько раз больше их позиции на сервере (32x), по сути делая их невидимыми в течение первых нескольких секунд. См. MC-12013.
5) Регулировка позиции, полученной с сервера
Во-первых, я бы сказал, что это не совсем так. ошибка, требующая исправления, а скорее ограничение из-за обновления позиций minecraft в целых и байтах, а не в двойных (по соображениям производительности), что требует достойного обходного пути. В конце концов, проблема сводится к тому, что полученные позиции отклоняются на 1/32, что приводит к массивным визуальным сбоям, если их не отрегулировать каким-либо образом.
Уже есть обходной путь на стороне сервера в место, которое работает достаточно хорошо, особенно с учетом решения других упомянутых здесь проблем. Однако в некоторых настройках он работает очень плохо, поэтому я решил придумать свой собственный обходной путь на стороне клиента, который работает, перемещая объект из его максимально возможного положения (все координаты +1/32) обратно в исходное. позиция (реальная позиция, округленная сервером до минус бесконечности).
6) Разное
- Пловцы : крошечный обходной путь для клиента, не учитывая возможности плавания некоторых мобы, из-за которых они могут ложно выглядеть тонущими.
- Пауки : обходной путь на стороне клиента, чтобы исправить ложные изображения падающих пауков
- Лодки : добавлена проверка столкновений для лодок на стороне клиента, когда они не управляются игроком (исправление MC-3441), и добавлена минимальная гравитация, чтобы заставить их обновить свой флаг onGround (уменьшает «резкие» движения лодок по земле).
- Сферы опыта : в настоящее время размер сфер опыта изменяется с 0,5 до 0,25 после перезапуска сервера/игры , и всегда 0,5 на стороне клиента. Я просто изменил его на 0,25 во всех случаях.
- Сферы и элементы XP : изменил метод pushOutOfBlocks, чтобы он назывался серверной стороной, поскольку он, кажется, вызывает расхождения клиент/сервер.
Остающиеся проблемы?
К сожалению, есть несколько сценариев, которые все еще могут вызывать временные сбои на стороне клиента, но я надеюсь, что с этим решаются надоедливые и постоянные.