Проверка многоблочной структуры

Версия Minecraft
1.20.1
API
Forge
95
4
6
Мне нужно проверять правильно ли игрок построил многоблочную структуру. Дело в том что моя структура довольно большая (13x13x7) и проверять каждый блок - это мазохизм. Можно ли проверять структуру, например, с помощью nbt файла, созданного через структурный блок?

Я попробовал решить эту проблему так:
Создал подобные массивы для каждого слоя структуры:
static String[] myStructureLayer0 = new String[]{
            "sssssssssssss",
            "s     s     s",
            "s     s     s",
            "s  sssssss  s",
            "s  s     s  s",
            "s  s  s  s  s",
            "ssss s s ssss",
            "s  s  s  s  s",
            "s  s     s  s",
            "s  sssssss  s",
            "s     s     s",
            "s     s     s",
            "sssssssssssss"};

Потом создал функции для получения словаря:
    static Map<String,Block> getBlockMapMyStructure(){
        Map<String,Block> a = new HashMap<>();
        a.put("g", ModBlocks.ENGRAVED_CRYSTALLINE_STONE.get());
        a.put("b", ModBlocks.EMBOSSED_CRYSTALLINE_STONE.get());
        a.put("e", ModBlocks.CRYSTALLINE_STONE_BEAM.get());
        a.put("c", ModBlocks.CRYSTALLINE_STONE_COLUMN.get());
        a.put("C", Blocks.COAL_BLOCK);
        a.put("l", Blocks.LAPIS_BLOCK);

        return a;
    }
  
    static Map<String, TagKey<Block>> getBlockTagMapMyStructure(){
        Map<String,TagKey<Block>> a = new HashMap<>();

        a.put("s",ModTags.Blocks.CRYSTALLINE_STONE_LIKE);

        return a;
    }

И в конечном итоге написал класс структуры который принимает двумерный массив и словари на блоки и теги. После чего написал в нём жутко громоздкий метод для перебора и проверки этого двумерного(по сути трёхмерного, тк строка в каждом массиве в конечном итоге представляется в виде массива символов). Такое решение конечно туповатое, но лучше уж хотя бы заполнить 3-х мерный массив чем писать кучу строк с проверкой каждого блока, а и ещё это проще отлаживать. Но мне всё равно не очень нравится это решение, ибо построить что-то в самой игре и сохранить через структурный блок - это и интереснее, и нагляднее, и проще
 
Последнее редактирование:
Создаёшь мапу <BlockPos, IBlockState> подгружаешь в нее структуру из NBT,
потом как надо проверить построенную структуру, циклом перебираешь область в мире где должна быть структура,
локализуешь координаты относительно структуры, по этим координатам получаешь IBlockState из мапы и сверяешь с IBlockState в мире,
как то так. (не вижу смысла мучатся со стрингами)

Алгоритм загрузки из 1.12.2 (он древний и возможно сломанный но у меня работает),
формат NBT'шек структур вроде на всех версиях одинаковый, так что логика будет такая же.
1.12.2:
public class Structure {
    protected final Map<BlockPos, IBlockState> blocks = new HashMap<>();

    public void load(String structureName) {
        NBTTagCompound structureNBT = readStructureAsName(structureName);
        NBTTagList palette = structureNBT.getTagList("palette", 10);
        NBTTagList blocksNBT = structureNBT.getTagList("blocks", 10);

        IBlockState[] blocksNames = new IBlockState[palette.tagCount()];
        for (int i = 0; i != palette.tagCount(); i++) {
            blocksNames[i] = getBlockByString(palette.getCompoundTagAt(i).getString("Name")).getDefaultState();
        }

        for (int i = 0; i != blocksNBT.tagCount(); i++) {
            NBTTagCompound compound = blocksNBT.getCompoundTagAt(i);
            NBTTagList pos = compound.getTagList("pos", 3);
            int state = compound.getInteger("state");
            blocks.put(new BlockPos(pos.getIntAt(0), pos.getIntAt(1), pos.getIntAt(2)), blocksNames[state]);
        }
    }

    private static NBTTagCompound readStructureAsName(String structureName) {
        InputStream inputstream = MinecraftServer.class.getResourceAsStream("/assets/" + Referense.MODID + "/structures/" + structureName + ".nbt");
        try {
            assert inputstream != null;
            return CompressedStreamTools.readCompressed(inputstream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(inputstream);
        }
    }

    protected Block getBlockByString(String block) {
        ResourceLocation resourcelocation = new ResourceLocation(block);
        if (!Block.REGISTRY.containsKey(resourcelocation)) {
            throw new RuntimeException(block);
        } else {
            return Block.REGISTRY.getObject(resourcelocation);
        }
    }
}
 
Последнее редактирование:
Назад
Сверху