Структура потоков
Мультипоточность для любой соврем енной системы, среды, приложения, да и просто для скрипта, имеет первостепенное значение. Но не в случае Майнкрафта. Эта игра использует один поток фактически на все: отображение интерфейсов, генерацию мира, отображение существ и прочего. Пока это идентично работает на всех изданиях игры, создавая проблемы с производительностью и повышая системные требования. Но все ли так плохо и когда можно задействовать несколько потоков, а также, для чего вообще это нужно. Давайте разбираться.
Что такое поток
Многие сразу могли заметить для себя новый термин, так что если вы еще не пошли искать его в сети, давайте рассмотрим это в наиболее простой тематике. Поток занимается последовательной обработкой возложенных на него процессов. Не волнуйтесь, давайте просто посмотрим на реальный пример, так все станет понятнее.
Итак, представим себе цикл отрисовки мира игры:
Начиная с обработки неба, мы заканчиваем наложением руки игрока, начиная все снова и снова, и так до тех пор пока мир используется игроком. Это четыре совершенно разных и не связанных друг с другом процесса. Однако, кое-что общее у них все же есть. Их обработает один поток. Это означает, что процессы будут выполнены друг за другом, последовательно, и ни один из них не может завершиться раньше другого.
Приходя к понятию многопоточности, можно подумать, что процессы просто выполнятся в разных потоках. И это может быть так, но скорее всего несколько потоков понадобится под разные виды задач, а не конкретные процессы. Дело в том, что любой процесс состоит из действий — тех строчек кода, что находятся в вашем скрипте. И обычно программисты отделяют ресурсоемкие задачи (не требующие срочной обработки) в отдельные процессы, оставляя основной поток разгруженным для совершения менее сложной работы быстрее.
Игровой мир обрабатывает все вместе, используя лишь один поток. Это несет для нас некоторый ряд ограничений, ибо выполнение действий параллельно друг другу в большинстве случаев попросту не предусмотрено, а отдельные потоки обрабатываются именно так. Майнкрафт не ассинхронен (не может параллельно обрабатывать процессы), так рассмотрим же каким именно образом это повлияет на нас.
Создаем процессы
Мультипоточность создается за счет конструкций Java, платформа оптимизирована для запуска потоков. Для чего их использовать? Вариантов масса — от обработки информации до анимирования интерфейсов. Тут решать только вам и давать каких бы то ни было рекомендация мы не можем, советую изучить сторонюю статью.
Начнем с создания простого потока, имитирующего работу. В общем случае, потоки создаются с помощью метода:
Threading.initThread(name, action, priority?, isErrorFatal?, formatFunc?)
Где name определяет строковый идентификатор, а action описывает процесс, совершаемый потоком. Давайте в качестве примера запустим ресурсоемкую задачу:
Threading.initThread("mod_testProcess", function() {
alert("Запускаем процесс");
for (let i = 0; i <= 5; i++) {
java.lang.Thread.sleep(4000);
alert((i / 5 * 100) + "%");
}
alert("Готово!");
})
Правда вместо задачи мы просто "усыпили" поток на 4 секунды. Идентификатор потока может быть любым, но лучше придерживаться чего-то вроде краткоеимямода_описаниеПроцесса (к примеру, tcon_crafting). Поэкспериментируйте с различными задачами, мы неоднократно затронем потоки в будущем.
Вследствии вызова этого метода, созданный объект потока может быть получен по имени, используя getThread. Объект потока является его обработчиком, выделим ключевые методы здесь:
const thread = Threading.getThread("mod_testProcess");
if (thread) { // процесс уже мог быть завершен
const another = Threading.initThread("mod_asyncProcess", function() {
while (thread.isAlive()) { // процесс уже мог быть завершен
// прерывание с минимальным периодом времени
java.lang.Thread.yield();
// можно воспользоваться join как альтернативой
}
alert("Предыдущий поток завершен!");
});
if (!another.isInterrupted()) {
// прерывание потока вызовет ошибку внутри него
// если использовать sleep или yield; если же
// поток уже усыплен, ошибка вызовется сразу
another.interrupt();
}
}
Большинство из этих методов могут быть вызваны в текущем потоке, используя java.lang.Thread.* (где * — название метода). Либо наоборот, методы java.lang.Thread могут быть вызваны на объекте обработчика.
Так в каких случаях ни в коем случае нельзя использовать потоки?
- Размещение блоков, призыв существ, изменение их атрибутов и прочее
- Получение информации о игровом мире, атрибутов существ, блоков и прочего
- Любые действия, связанные с нативной частью, если это затрагивает игру
Вы никогда не можете точно знать какой проект может вызвать проблемы потоков, результат их постоянного использования неизвестен и уникален для каждого случая. Лучше воспользуйтесь обновляемыми объектами, они предсказуемы и не вызывают рассинхронизаций. А потоки не должны использоваться для взаимодействия с игрой от слова совсем.