Получить все контейнеры в мире.

Версия Minecraft
1.12.2
22
0
Нужно при загрузке мира получить все контейнеры и обновить их 1 раз. WorldEvent.Load не принёс результатов, лист loadedTileEntityList всегда пустой. Собственно, как лучше получить все контейнеры в игровом мире? У меня только идея получать контейнеры из каждого чанка, при его загрузке, но тогда производительность на сервере заметно падает(да и этот способ обновляет контейнеры при каждой загрузке чанка,а мне и одного обновления хватит).
 
3,005
192
592
Контейнеры - это тайлы в смысле?

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

Так же смотря что нужно.
Возможно, проще будет через файлы мира изменять тайлы.

Да и если тайл не загружен в мире, а ты хочешь его достать - будут ошибки, ибо тайл не загружен, а ты хочешь с ним работать.
 
22
0
@ロロロ Ну да, нужно получить тайлы которые имеют контейнер. Как можно помечать чанки? Тогда нужно будет обнулять тэг чанка при каждой загрузке мира?
Ну а нужно мне найти все айтемстаки в контейнере которые содержат мой нбт тэг, и сравнить тэг айтемстака с тэгом записанным в файл.
 
7,099
324
1,510
Тайлы не имеют контейнер. Контейнер существует только пока у игрока открыт инвентарь чего-то(не обязательно тайла), причем на каждого игрока свой контейнер.
А инвентарь тайла представлен либо IInventory(типо устаревшее, не рекомендуется к юзу, потому что трудно делать интеграцию с модами) или IItemHandler-капабилити.

Чанки, которые загрузились, можно получить из события ChunkEvent.Load
Получить тайлы из чанка по событию его загрузки можно Chunk#getTileEntityMap
Проверить и получить все капабилити инвентарей можно примерно так:
Java:
if(tile.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, <facing>)){
    IItemHandler inv = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, <facing>)
}
Стоит обратить внимание, что с разных сторон(параметр <facing>) могут быть разные инвентари

Как можно помечать чанки?
Если эти данные нужно хранить только в течении одной сессии(при перезапуске игры сохранять не надо), то можно сделать свое хранилище Map<Integer,Set<ChunkPos>>, это мапа, хранящая множества координат чанков(те что помечены) для каждого мира(который определяется идентификатором, можно взять из World#provider).
А если нужно сохранять и загружать эти метки вместе с миром, то чанку тоже можно добавлять свою капабилити
Пример капабилити для чанка:
 
Последнее редактирование:
1,038
57
229
Лучше записывать внутри предмета, в отдельную переменную или лог, кто и что с ним делает. Например ты его выбросил в мир.
Записываем что этот предмет лежит в таких то координатах. Допустим его кто то поднял. Исправляем запись, что этот предмет теперь не в мире, а у игрока такого то. Допустим он положил его в сундук. Снова исправляем запись что такой то предмет теперь в этом сундуке.
Всё это можно делать как в предмете самом, так и слушая соответствующие события и менять запись поэтому предмету.
И в итоге где бы он не находился (у игрока, в сундуке, в мире). Мы всегда будем знать где он, даже если игрок не в сети или чанк не прогружен.
 
22
0
@hohserg1 Спасибо за ответ, я конечно и сам к этому подобрался, вот что я накидал ещё пару дней назад:
ChunkEvent.Load:
        Object[] tileentity = chunk.getTileEntityMap().values().toArray();
        for (int i = 0; i < chunk.getTileEntityMap().size(); i++) {
            if(tileentity[i] instanceof TileEntity)
            {
                TileEntity tileEntity = (TileEntity)tileentity[i];
                if(tileEntity.hasCapability(net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null)) {
                    IItemHandler container = tileEntity.getCapability(net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
                    if(container.getSlots() > 0)
                        System.out.println("This container has "+container.getSlots()+" slots");
                        for (int j = 0; j < container.getSlots(); j++) {
                        ItemStack stack = container.getStackInSlot(j);
                        if(stack != ItemStack.EMPTY && stack.getItem() != Items.AIR)
                        if(stack.hasTagCompound()) {
                            NBTTagCompound tag = stack.getTagCompound();
                            for (int j2 = 0; j2 < Const.ItemStatsType.length; j2++) {
                                if (tag.hasKey(Const.ItemStatsType[j2]))
                                {
                                    System.out.println("FOUND ONE");
                                }      
                            }
                        }
                    }
                }
            }
        }
(Это конечно абсолютно ужасный код, но я пока просто проверяю работоспособность этой конструкции)
Суть в том, что мне потом все стаки, которые пройдут проверки, сверять с файлом, в каждом сундуке, в каждом чанке. Серверу больно становится. Я поэтому и спрашиваю, может быть у кого-то есть более лаконичное решение данной проблемы. И ещё.Forge настоятельно не рекомендует модифицировать айтем стаки возвращенные IItemHandler.getStackInSlot(). Есть ли нормальный способ получить стак? Без боязни неожиданного краша или ещё чего-то.1573963668872.png
 
1,038
57
229
Я тебе написал способ в котором не нужно делать проверку каждого сундука. Когда предмет у игрока, если этот предмет добавляет твой то ты добавляешь код в Item#OnUpdate.
Соответственно, если предмет не твой, то ты добавляешь на него хук на отрисовку предмета и добавляешь код уже в него.
Это всё будет работать в том случае если предметов в игре не было вообще.
А если предметы уже разошлись по миру, то ты уже не сможешь их получить (обязательно будут те, которые не учтены), этот надо было делать раньше.

Суть в том, что мне потом все стаки, которые пройдут проверки, сверять с файлом, в каждом сундуке, в каждом чанке. Серверу больно становится.
Тебе не нужно делать проверку каждый раз, проверка делается только 1 раз.

Когда у тебя на руках есть список всех предметов, тебе не нужно делать проверку, потому что те данные что у тебя совпадают с теми где они на самом деле лежат. А если предмет вдруг куда то переместиться, то и у тебя обновятся данные благодаря Получить все контейнеры в мире.
 
Последнее редактирование:
22
0
@ZZZubec Вот серьёзно, я так и не понял как это должно решить проблему, мне надо получить все предметы которые имеют определенный нбт тэг, не только из моего мода. OnUpdate сразу отпадает, хуками пользоваться я тоже не горю желанием , ну даже если я как-то запишу где лежит каждый инстанс каждого предемета(а это потенциально сотни или тысячи записей). Как мне потом доставать их? Типо я знаю что предмет точно лежит в сундуке, но достать я его от туда не могу, пока сундук не загружен, или я не прав?
 
1,038
57
229
прав, ты изначально про доставание ничего не говорил. Ну допустим ты достал этот предмет, дальше что ты с ним собираешься делать?
Может ты сразу всё опишешь из того что задумал изначально?
 
22
0
@ZZZubec Что-то типо своей id системы?
Я задаю любому предмету(инструменту,броне или оружию) характеристики, например уровень = 5. Эти характеристики заносятся в нбт тэг этого предмета.
Нбт тэг применятется только к конкретному itemstack, т.е. в мире может быть железный меч(уровень = 2) и железный меч(уровень = 5).
Чтобы не потерять эти предметы я задаю им уникальный id(тоже нбт тэг), вместе с эти данные об этом предмете записываются в файл.
Затем я могу командой получить этот предмет(найду в фале предмет с моим айди и считаю его данные, выдам игроку).
Задача - сделать так, чтобы когда я поменяю значения в файле все предметы с этим же айди поменяли свои характеристики.
Т.е. если у меня в файле есть запись : железный мечь(id = 1, level =5) и я захочу изменить : level = 2, все железные мечи(id = 1) должны стать level = 2
Надеюсь достаточно понятно.
 
1,038
57
229
ну тогда тебе предметы вообще не нужны, наноси урон по ним согласно ID. Тебе лишь надо проверять при нанесении урона какой у него ID и в соответствии с этим, наносить урон.
Урон наносит вроде только один хук. Hurt
А читать характеристики из файла надо при загрузке мода.
 
7,099
324
1,510
А в чем вообще состоит задача? Зачем нужно сверять итемы с файлом?
 
22
0
@hohserg1
Что-то типо своей id системы?
Я задаю любому предмету(инструменту,броне или оружию) характеристики, например уровень = 5. Эти характеристики заносятся в нбт тэг этого предмета.
Нбт тэг применятется только к конкретному itemstack, т.е. в мире может быть железный меч(уровень = 2) и железный меч(уровень = 5).
Чтобы не потерять эти предметы я задаю им уникальный id(тоже нбт тэг), вместе с эти данные об этом предмете записываются в файл.
Затем я могу командой получить этот предмет(найду в фале предмет с моим айди и считаю его данные, выдам игроку).
Задача - сделать так, чтобы когда я поменяю значения в файле все предметы с этим же айди поменяли свои характеристики.
Т.е. если у меня в файле есть запись : железный мечь(id = 1, level =5) и я захочу изменить : level = 2, все железные мечи(id = 1) должны стать level = 2
 
7,099
324
1,510
Для этой задачи вообще не нужно перебирать все итемы
Можно использовать тот же принцип, что и используется для локализации текста
В итемах храни только идентификаторы, НЕ конкретные характеристики.
Создай где-нить в доступном месте отображение идентификатор->конкретная характеристика
Когда игрок долбасит мечем, то урон(конкретная характеристика) получаются из отображения по идентификатору.

Таким образом, чтобы поменять харки всех итемов достаточно поменять отображение.
Отображением может быть просто Map<Id, Value>, которая формируется на основе прочитанного файла
 

tox1cozZ

aka Agravaine
8,456
598
2,893
Я вроде написал решение для его конкретной задачи.
Стак грузится всегда. Грузятся тайлы - грузятся стаки в них. Грузятся энтити - грузятся их стаки.
То есть мы зашли в игру, прогрузился кусок мира, пругрузились стаки. Мы перехватили во время подгрузки и изменить их значение лвла.
Если есть какие-то далекие чанки которые фиг знает когда загрузятся - тоже все ок. Мы доходим до них, грузим, грузятся стаки и меняются значения в них.
 
7,099
324
1,510
Прикол в том, что для решения этой задачи не обязательно менять че-то в стаках
 
22
0
@hohserg1 Т.е. во время загрузки мода/мира прочитать файл с заданными параметрами для айтемов. Из файла передать в мапу. Потом при каждом использовании предмета обращаться к ней чтобы достать статы, я правильно понял? Звучит не идеально, но гораздо лучше, чем вариант с перебором.
 
Сверху