/ Отключить

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) Состояние гонки (поток клиента и сервера)

Иногда сущности могут покидать огороженные области, «глючая» через блоки во время обычного игрового процесса. Это может произойти только в том случае, если используется интегрированный сервер (однопользовательский или открыт для локальной сети) и только с определенными блоками. Чем больше сущностей сталкивается с определенным блоком, тем выше вероятность их побега. Есть и другие части игры, на которые влияет та же основная ошибка.

Причина

Когда 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) Проблемы синхронизации позиции объекта

  1. В текущей реализации EntityTrackerEntry ( класс, который отправляет обновления позиций объектов) существует несколько логических ошибок, которые могут привести к рассинхронизации позиций объектов клиента и сервера. Ошибки на стороне клиента приводят к сбоям, которые обычно устраняются при следующем (относительном или абсолютном) обновлении положения. Я обнаружил следующие ошибки:

    1. при отправке обновления абсолютной позиции ( Packet34EntityTeleport ) сервер не всегда сохраняет данные объекта позиция (для последующих обновлений относительного положения)
    2. , когда во время первого (попытки) обновления не было отправлено ни одного пакета, сервер сохраняет позицию
    3. пакеты порождения содержат текущую позицию объекта, а не сохраненную в объекте трекера.

    Интересно, что это также исправляет https://mojang.atlassian.net/browse /MC-19331. Это связано с тем, что при размещении вагонетки на склоне сервер сначала отправляет нижнюю позицию (как если бы она была размещена на плоских рельсах) в пакете появления, а затем пытается обновить повышенную позицию, которая, однако, отменяется (первое обновление ), но позиция сохраняется, как если бы она была отправлена ​​клиентам.

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

  3. Сферы XP порождают на стороне клиента в несколько раз больше их позиции на сервере (32x), по сути делая их невидимыми в течение первых нескольких секунд. См. MC-12013.

5) Регулировка позиции, полученной с сервера

Во-первых, я бы сказал, что это не совсем так. ошибка, требующая исправления, а скорее ограничение из-за обновления позиций minecraft в целых и байтах, а не в двойных (по соображениям производительности), что требует достойного обходного пути. В конце концов, проблема сводится к тому, что полученные позиции отклоняются на 1/32, что приводит к массивным визуальным сбоям, если их не отрегулировать каким-либо образом.

Уже есть обходной путь на стороне сервера в место, которое работает достаточно хорошо, особенно с учетом решения других упомянутых здесь проблем. Однако в некоторых настройках он работает очень плохо, поэтому я решил придумать свой собственный обходной путь на стороне клиента, который работает, перемещая объект из его максимально возможного положения (все координаты +1/32) обратно в исходное. позиция (реальная позиция, округленная сервером до минус бесконечности).

6) Разное

  • Пловцы : крошечный обходной путь для клиента, не учитывая возможности плавания некоторых мобы, из-за которых они могут ложно выглядеть тонущими.
  • Пауки : обходной путь на стороне клиента, чтобы исправить ложные изображения падающих пауков
  • Лодки : добавлена ​​проверка столкновений для лодок на стороне клиента, когда они не управляются игроком (исправление MC-3441), и добавлена ​​минимальная гравитация, чтобы заставить их обновить свой флаг onGround (уменьшает «резкие» движения лодок по земле).
  • Сферы опыта : в настоящее время размер сфер опыта изменяется с 0,5 до 0,25 после перезапуска сервера/игры , и всегда 0,5 на стороне клиента. Я просто изменил его на 0,25 во всех случаях.
  • Сферы и элементы XP : изменил метод pushOutOfBlocks, чтобы он назывался серверной стороной, поскольку он, кажется, вызывает расхождения клиент/сервер.

Остающиеся проблемы?

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

Оцените статью
Gamicon.ru
Добавить комментарий