Slomix / ParkourBeat

4 stars 5 forks source link

Проблемы с отменой сохранения чанков #87

Open Dymeth opened 5 months ago

Dymeth commented 5 months ago

В бакките творится какой-то ад с управлением мирами и сохранением отдельных чанков. В итоге не удаётся отменять сохранение ненужных чанков. Ниже пойдёт речь о проблемах в коде выгрузки и миров, реализованной в данном менеджере: https://github.com/Slomix/ParkourBeat/blob/main/src/main/java/ru/sortix/parkourbeat/world/WorldsManager.java

Проблема №1: ChunkUnloadEvent НЕ вызываются при отгрузке миров. Это касается абсолютно любых чанков - и тех, которые могут быть выгружены "вручную", и тех, которые не могут быть выгружены сейчас по тем или иным причинам. Из-за этого приходится перед выгрузкой миров пытаться вручную выгружать все чанки мира - для того, чтобы вызывать ChunkUnloadEvent'ы и отключить сохранение отдельных чанков. Однако стоит учесть, что ChunkUnloadEvent НЕ вызывается, если чанк используется, и не может быть отгружен в данный момент. Поэтому наша задача подготовить все чанки к выгрузке - например, телепортировать всех игроков в другой мир.

Существует ещё один способ отменять сохранение лишь отдельных чанков - передавать в метод World.unloadChunk() булин, отвечающий за сохранение. Данный вариант пока не тестировался. Стоит попытаться использовать этот способ - возможно так удастся решить перечисленные ниже проблемы. Однако с технической точки зрения этот способ значительно менее удобен, чем вариант с ChunkUnloadEvent, поскольку придётся передавать Predicate прям в метод отгрузки мира, мы лишаемся всей гибкости системы событий баккита.

Проблема №2: Мир и конкретные чанки НЕ могут быть отгружены, если в них находится хотя бы один игрок. Поэтому при отгрузке все игроки телепортируются на спаун. Однако даже после завершения телепортаций чанки не могут быть отгружены в этот тик. Из-за этого приходится запускать отгрузку чанков в шедулере. Более того, даже задержки в 1 тик не всегда хватает. Бывает, что даже 3-х тиков мало - ощущение, что это какой-то рандом. Подозреваю, это связанно с асинхронными телепортациями игроков (даже несмотря на то, что мы дожидаемся завершения всех CompletableFuture).

Проблема №3: Шедулеры при выключении плагина использовать нельзя - они автоматически завершаются. Даже шедулер с задержкой в 1 тик выполнен не будет, если он был запущен в onDisable(). Таким образом, при выключении плагина мы и вовсе теряем возможность гибко управлять сохранением отдельных чанков. Мы можем отказаться от выгрузки миров при выключении плагина, но точно НЕ можем отказаться от запрета сохранения отдельных чанков, поскольку неизвестно, перезагружается ли только плагин или сервер целиком. Как решать данный вопрос - пока неясно.

Проблема №4: Некоторые чанки не выгружаются даже через секунду после телепортации игроков. Телепортация и шедулер с задержкой позволяют выгрузить лишь ~30% всех чанков мира, для всех остальных метод World#unloadChunk() возвращает false по неизвестной причине. Была попытка использовать World#setKeepSpawnInMemory(false), однако никакого результата она не дала. Возможно на применение этой опции тоже требуется минимум один тик. Пока не пытался запускать действия после этого с задержкой в 1 тик. Поэтому пока неясно, как управлять сохранением оставшихся ~70% чанков даже при каких-либо внутриигровых действиях, не связанных с выключением плагина

Проблема №5: В апи нет возможности сохранять лишь какие-то отдельные чанки - можешь лишь сохранить абсолютно все. Частичное сохранение пригодилось бы для регулярного сохранения данных уровня в режиме редактирования. Можно было бы просто включить автосохранение миров в ядре, но не существует никакого ChunkSaveEvent, чтобы это сохранение при необходимости отменять. Существует лишь WorldSaveEvent, который не подходит для решения данной задачи. image UPD: Создал issue в гите PaperMC по 5-й проблеме

Итог: 1) Мы абсолютно НЕ можем контролировать сохранение чанков при выгрузке плагина 2) При обычных геймплейных механиках мы можем контролировать сохранение лишь ~30% всех чанков

P.S. В данной теме на форуме человек утверждает, что отмена сохранения чанка приводит к невозможности его выгрузки, но подтвердить или опровергнуть эту теорию пока не удалось. ~70% чанков НЕ выгружаются, даже если ни для одного из чанков НЕ отключать сохранение.

P.P.S. Если не удастся в полной мере исправить управление сохранением чанков (в т.ч. при выключении плагина), то необходимо будет протестировать это всё на последнем билде Paper. Если проблема останется актуальной - необходимо написать багрепорты

GreenpixDev commented 5 months ago

Для решения части из этих проблем я делал форк paper с изменённой логикой загрузки/сохранения чанков в мире. Но, скорее всего, этот вариант вас не устроит, т.к. вы ориентируетесь на самодостаточность плагина и отсутствие зависимости от конкретной платформы

GreenpixDev commented 5 months ago

По второй проблеме, если телепортировать игроков не асинхронно, а использовать классический метод Player#teleport? В теории это не должно сильно повлиять на производительность, т.к. чанки спавна зачастую будут погружены (благодаря той же настройке World#setKeepSpawnInMemory(true))

Dymeth commented 5 months ago

По второй проблеме, если телепортировать игроков не асинхронно, а использовать классический метод Player#teleport? В теории это не должно сильно повлиять на производительность, т.к. чанки спавна зачастую будут погружены (благодаря той же настройке World#setKeepSpawnInMemory(true))

Даже при синхронной телепортации требуется задержка минимум в 1 тик (возможно и больше, пока не тестировал это досконально). А если нужна задержка - это шедулер. А если шедулер - то 3-я проблема по-прежнему актуальна