Ускоритель мира

Версия Minecraft
1.7.10
API
Forge
236
4
22
Доброе утро всем. Подскажите пожалуйста, как в Forge можно реализовать "ускорение тайлов"? Я конечно понимаю, что для этого я должен чаще вызывать метод updateEntity() всем тайлам в мире, но вопрос, как получить все тайлы во всех загруженных чанках? На сколько я понял, мне нужно будет ловить ворлд тик ивент и в нём уже нужное кол-во раз вызывать updateEntity() для каждого тайла. Вообще, я нашёл 1 List в World и попробовал пройтись циклом, но в ближайшие 10 минут я получил краш с ошибкой ConcurentModificationExeption.
TickHandler:
@SubscribeEvent
    public void onTick(TickEvent.WorldTickEvent event)
    {
        if(event.phase == TickEvent.Phase.END || event.world.provider.dimensionId != ConfigurationHandler.dimensionId) return;
        for(int count = 0; count<ConfigurationHandler.worldTickSpeed; count++)
        {
            for (TileEntity tileentity : (Iterable<TileEntity>)event.world.loadedTileEntityList)
            {
                if (!tileentity.isInvalid() && tileentity.hasWorldObj() && event.world.blockExists(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord))
                {
                    try{tileentity.updateEntity();}catch(Throwable ignore){}
                }
            }
        }
    }
Других способов получить все активные тайлы я пока, увы, не нашёл :(. Также, как по мне, код выше - нагрузочный. Можно ли его сделать менее убойным для игры? Заранее всем спасибо за ответы!
 

jopi

Попрошайка
1,421
30
260
ConcurrentModificationException вылетает как правило либо во в одновременную попытку доступа к объекту(коллекции)/изменение объекта(коллекции) во время его перечисления циклом for/foreach и т.п. (из практики только это встречал)

По сути из вариантов могу предложить достать 'ключи' если у тебя мапа либо размер листа если же лист, и просто доставать значения из мапы/листа по ключу/индексу и уже проигрывать этот метод.

если нужно больше чем 20 раз в секунду - используй потоки(Thread)
 
236
4
22
Данное поле - список. Чтобы не было эксепшена, бегай по нему через fori.
Не совсем понял, что за "fori". Цикл со счётчиком чоли или нет?
Просто если ты про for each - то как раз выше я его и использовал...
 
236
4
22
Трюкач нужен, ибо сам тайл может выкинуть исключение и сервер упадет. Советую нормально обработать исключение как это сделано в Майне.
Нуу, кусочек
Java:
if (ForgeModContainer.removeErroringTileEntities)
{
   tileentity.invalidate();
   w.setBlockToAir(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord);
}

можно забрать. А вот хрень с крашем тайла, не думаю что стоит...
 
236
4
22
ну типо, если код нормальный то и ошибок не будет, не
Тайлы из других модов могут накосячить в оверрайде апдейт энтити и тогда крашнется весь сервак, а так try catch предотвратит это. Сам же майн использует эту конструкцию.
 
236
4
22
Выходит, нужный мне код примерно такой:
Искусственное обновление тайла:
for(int ID = 0; ID<w.loadedTileEntityList.size(); ID++)
            {
                TileEntity tileentity = (TileEntity)w.loadedTileEntityList.get(ID);
                if (!tileentity.isInvalid() && tileentity.hasWorldObj() && w.blockExists(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord))
                {
                    try
                    {
                        tileentity.updateEntity();
                    }
                    catch (Throwable throwable)
                    {
                        CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Ticking block entity");
                        CrashReportCategory crashreportcategory = crashreport.makeCategory("Block entity being ticked");
                        tileentity.func_145828_a(crashreportcategory);
                        if (ForgeModContainer.removeErroringTileEntities)
                        {
                            tileentity.invalidate();
                            w.setBlockToAir(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord);
                        } else throw new ReportedException(crashreport);
                    }
                }
                if (tileentity.isInvalid())
                {
                    w.loadedTileEntityList.remove(ID);
                    if (w.getChunkProvider().chunkExists(tileentity.xCoord >> 4, tileentity.zCoord >> 4))
                    {
                        Chunk chunk = w.getChunkFromChunkCoords(tileentity.xCoord >> 4, tileentity.zCoord >> 4);
                        if (chunk != null)
                        {
                            chunk.removeInvalidTileEntity(tileentity.xCoord & 15, tileentity.yCoord, tileentity.zCoord & 15);
                        }
                    }
                }
            }
Или я опять чо-то нахерачил?
 

tox1cozZ

aka Agravaine
8,454
598
2,890
Чел ты прикалываешься? У тебя случается ошибка она падает в try-catch в котором ты кидаешь краш, если нет try-catch краш выкинет майнкрафт, где смысл авчом агде???
Еще раз внимательно почитай код. Мы создаем краш отчет, заполняем его КОНКРЕТНЫМИ ДАННЫМИ (ТАЙЛ, ДАННЫЕ ТАЙЛА, БЛОК) и тд. Если же майн просто крашнется, этих данных в отчете НЕ БУДЕТ. Разницу уловил?

Или я опять чо-то нахерачил?
Последний блок if (tileentity.isInvalid()) убери, он не нужен, ибо если тайл будет инвалидным, то в основном коде майна эта проверка сработает и он удалится.
 
Сверху