Meta Блока просто убивает меня...

Версия Minecraft
1.12.2
API
Forge
122
4
6
Здорово. Пишу блок у которого должно быть несколько состояний в зависимости от которых будет меняться текстура. Но эта мета это что-то с чем-то, с одной стороны она работает когда одна на блоке, если их несколько, то перестает работать, и выдает ошибку, порой и краш. Вообщем у блока должно быть 27 состояний, но так как майн такое количество не принимает я разделил на две меты.
Java:
public class Runes extends BasisBlock {
    public static final PropertyInteger VARIANT_1 = PropertyInteger.create("variant_1", 0, 2);
    public static final PropertyInteger VARIANT_2 = PropertyInteger.create("variant_2", 0, 8);
    private static final AxisAlignedBB BOX = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.0025D, 1.0D);

    public Runes() {
        super("runes", Material.CIRCUITS, 340.0f, 0.0f, "pickaxe", 0, SoundType.STONE);
        this.setCreativeTab(null);
        this.setDefaultState(this.blockState.getBaseState().withProperty(VARIANT_1, 0).withProperty(VARIANT_2, 0));
    }

    @Override
    public IBlockState getStateFromMeta(int meta) {
//        int variant1 = meta & 0x3;
//        int variant2 = (meta >> 2) & 0x7;
        return this.getDefaultState();
    }

    @Override
    public int getMetaFromState(IBlockState state) {
        int variant1 = state.getValue(VARIANT_1);
        int variant2 = state.getValue(VARIANT_2);
        return variant1 | variant2;
    }

    @Override
    protected BlockStateContainer createBlockState() {
        return new BlockStateContainer(this, VARIANT_1, VARIANT_2);
    }

    @Override
    public boolean isReplaceable(IBlockAccess world, BlockPos pos) {
        return world.getBlockState(pos).getBlock() != this /*|| world.getBlockState(pos).getValue(VARIANT) != 0*/;
    }

    @Override
    public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos) {
        return BOX;
    }

    @Override
    public AxisAlignedBB getCollisionBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos) {
        return NULL_AABB;
    }

    @Override
    public boolean canPlaceBlockAt(World world, BlockPos pos) {
        return super.canPlaceBlockAt(world, pos) && world.getBlockState(pos.down()).getBlockFaceShape(world, pos, EnumFacing.UP) == BlockFaceShape.SOLID;
    }

    @Override
    public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos) {
        world.scheduleUpdate(pos, this, 0);
    }

    @SideOnly(Side.CLIENT)
    @Override
    public BlockRenderLayer getBlockLayer() {
        return BlockRenderLayer.CUTOUT;
    }

    @Override
    public ItemStack getPickBlock(IBlockState state, RayTraceResult result, World world, BlockPos pos, EntityPlayer player) {
        return new ItemStack(ItemsInit.RITUAL_CHALK);
    }

    @Override
    public Item getItemDropped(IBlockState state, Random rand, int fortune) {
        return ItemsInit.RITUAL_CHALK;
    }

    @Override
    protected ItemStack getSilkTouchDrop(IBlockState state) {
        return new ItemStack(ItemsInit.RITUAL_CHALK);
    }

    @Override
    public boolean isOpaqueCube(IBlockState state) {
        return false;
    }

    @Override
    public boolean isFullCube(IBlockState state) {
        return false;
    }

    @Override
    public boolean canPlaceBlockOnSide(World world, BlockPos pos, EnumFacing side) {
        return world.isSideSolid(pos.down(), EnumFacing.UP);
    }
}
короче вот этот код, от части рабочий вариант, но как только я пытаюсь прикрутить в blockstates текстуру зависящую от меты
Java:
{
  "forge_marker": 1,
  "defaults": {
    "model": "lots_of_recipes:chalk",
    "textures": {
      "down": "lots_of_recipes:blocks/ritual_accessories/runes/rune_null",
      "up": "lots_of_recipes:blocks/ritual_accessories/runes/rune_empty",
      "particle": "lots_of_recipes:blocks/ritual_accessories/runes/rune_particle"
    }
  },
  "variants": {
    "normal": [{}],
    "inventory": [{
      "transform": "forge:default-block"
    }],
    "variant_1=0,variant_2=0": {
      "textures": { "up": "lots_of_recipes:blocks/ritual_accessories/runes/b" }
    }
  }
}
то появляется ломаная текстура, а если вместо текстуры прописываю зависимость от модели то она не появляется, а появляется стандартная. Перепробовал огромное множество разнообразных вариантов, сил уже нет, хз что делать, подскажите или дайте совет как сделать рабочий вариант. Буду очень признателен...
 
Решение
Я решил проблему с данным кодом решил все таки воспользоваться обычным методом рендера тайла, если кому понадобится то вот решение проблемы:
Tile:
public class TileRunes extends TileEntity implements ITickable {
    private int typeRune = 0;
    private int creationTime = 0;

    public int getTypeRune() { return typeRune; }
    public int setTypeRune(int type) { this.typeRune = type; return this.typeRune; }

    public int getCreationTime() { return creationTime; }
    public int setCreationTime(int time) { this.creationTime = time; return creationTime; }

    @Override public void update() {}

    @Nonnull @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
        NBTTagCompound ret = super.writeToNBT(nbt)...
435
41
110
но так как майн такое количество не принимает я разделил на две меты.
делай через TileEntity
Для примера можешь взять нотный блок - при желании ему можно дать почти 1к различных текстур

Размер меты - 4 бита = т.е максимум 16 вариантов.
 
122
4
6
+делай через TileEntity
я изначально так и думал делать но меня остановило, то что я хз как через тайл можно удобно привязывать огромное множество текстур на сам блок, без доп рендера тайла. Если знаешь как я буду рад если поделишься знаниями, просто текстур реально много и не хочется для каждой пилить модель файл с ними не удобно возиться хочется чтобы все в одном месте.
 
Последнее редактирование:
435
41
110
для каждой пилить модель файл с ними не удобно возиться хочется чтобы все в одном месте.
Используй датагенератор(ы) (не знаю что это такое и с чем едят, об их существовании узнал по коментам)

Или мой набор костылей для быстрой генерации всех нужных файлов. Останется только потом открыть модель блока в BlockBench и указать путь к текстуре (или вручную)

По умолчанию (уже сам забыл) "block.json" будет ссылаться на текстуру "textures/block/block.png"
 

necauqua

когда-то был anti344
Администратор
1,216
27
172
огромное множество текстур на сам блок
Просто делай кучу блоков, duh, так сам майнкрафт и решил делать со всякими там вариантами, типа шерсти, вместо меты, посмотри определения в Blocks
с ними не удобно возиться хочется чтобы все в одном месте
Таки датагенераторы, да, они там сами поняли что миллиард файлов это запарно. Правда хз шо там с датагенераторами в 1.12..

Блокстейты это способ привязать какие-то условия в коде к каким-то моделям/текстурам, самих блокстейтов в рантайме (то бишь без сохранения на диск, а в заисимости от условий) может быть сколько хочешь - типа для всяких там заборчиков и прочих кабелей - а сохранять 4 бита в мету это таки когда 4 бит достаточно и такие блоки часто ставятся в мир (и тайл, даже нетикаемый, сильно жирно было бы им делать), вроде растений.

Хотя в 1.16 вроде меты уже не существует в принципе, и ты просто регистрируешь какие параметры блокстейта ты хочешь сохранять на диске и оно само как-то разбирается.
 
122
4
6
Я решил проблему с данным кодом решил все таки воспользоваться обычным методом рендера тайла, если кому понадобится то вот решение проблемы:
Tile:
public class TileRunes extends TileEntity implements ITickable {
    private int typeRune = 0;
    private int creationTime = 0;

    public int getTypeRune() { return typeRune; }
    public int setTypeRune(int type) { this.typeRune = type; return this.typeRune; }

    public int getCreationTime() { return creationTime; }
    public int setCreationTime(int time) { this.creationTime = time; return creationTime; }

    @Override public void update() {}

    @Nonnull @Override public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
        NBTTagCompound ret = super.writeToNBT(nbt);
        writePacketNBT(ret);
        return ret;
    }

    @Nonnull @Override public final NBTTagCompound getUpdateTag() {
        return writeToNBT(new NBTTagCompound());
    }

    @Override public void readFromNBT(NBTTagCompound nbt) {
        super.readFromNBT(nbt);
        readPacketNBT(nbt);
    }

    public void writePacketNBT(NBTTagCompound nbt) {
        nbt.setInteger("typeRune", typeRune);
        nbt.setInteger("creationTime", creationTime);
    }
    public void readPacketNBT(NBTTagCompound nbt) {
        typeRune = nbt.getInteger("typeRune");
        creationTime = nbt.getInteger("creationTime");
    }

    @Override
    public final SPacketUpdateTileEntity getUpdatePacket() {
        NBTTagCompound tag = new NBTTagCompound();
        writePacketNBT(tag);
        return new SPacketUpdateTileEntity(pos, getBlockMetadata(), tag);
    }

    @Override
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity packet) {
        super.onDataPacket(net, packet);
        readPacketNBT(packet.getNbtCompound());
    }
}
Render Tile:
@SideOnly(Side.CLIENT)
public class RendererTileRunes extends TileEntitySpecialRenderer<TileRunes> {
    private static final ResourceLocation[] TEXTURES = new ResourceLocation[26];

    public RendererTileRunes() {
        for (int i = 0; i < 26; i++) {
            char letter = (char) (i + 'a');
            TEXTURES[i] = new ResourceLocation("lots_of_recipes", "textures/blocks/ritual_accessories/runes/" + letter + ".png");
        }
    }

    @Override
    public void render(TileRunes tile, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
        if(!tile.getWorld().isBlockLoaded(tile.getPos(), false)
                || tile.getWorld().getBlockState(tile.getPos()).getBlock() != BlocksInit.RUNES) return;

        boolean base = tile.getWorld().getBlockState(tile.getPos()).getValue(Runes.BASE);
        EnumFacing facing = tile.getWorld().getBlockState(tile.getPos()).getValue(Runes.FACING);

        if (tile.getTypeRune() >= 0 && tile.getTypeRune() < 26 && !base) {
            ResourceLocation texture = TEXTURES[tile.getTypeRune()];
            GlStateManager.pushMatrix();
            GlStateManager.translate(x, y, z);
            GlStateManager.disableLighting();
            GlStateManager.enableBlend();

            Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
            Tessellator tessellator = Tessellator.getInstance();
            BufferBuilder buffer = tessellator.getBuffer();

            buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);

            if (facing == EnumFacing.NORTH) {
                buffer.pos(0, 0.025d, 1).tex(0, 1).endVertex();
                buffer.pos(1, 0.025d, 1).tex(1, 1).endVertex();
                buffer.pos(1, 0.025d, 0).tex(1, 0).endVertex();
                buffer.pos(0, 0.025d, 0).tex(0, 0).endVertex();
            } else if (facing == EnumFacing.SOUTH) {
                buffer.pos(0, 0.025d, 1).tex(0, 0).endVertex();
                buffer.pos(1, 0.025d, 1).tex(1, 0).endVertex();
                buffer.pos(1, 0.025d, 0).tex(1, 1).endVertex();
                buffer.pos(0, 0.025d, 0).tex(0, 1).endVertex();
            } else if (facing == EnumFacing.WEST) {
                buffer.pos(1, 0.025d, 1).tex(0, 1).endVertex();
                buffer.pos(1, 0.025d, 0).tex(1, 1).endVertex();
                buffer.pos(0, 0.025d, 0).tex(1, 0).endVertex();
                buffer.pos(0, 0.025d, 1).tex(0, 0).endVertex();
            } else if (facing == EnumFacing.EAST) {
                buffer.pos(1, 0.025d, 1).tex(0, 0).endVertex();
                buffer.pos(1, 0.025d, 0).tex(1, 0).endVertex();
                buffer.pos(0, 0.025d, 0).tex(1, 1).endVertex();
                buffer.pos(0, 0.025d, 1).tex(0, 1).endVertex();
            }

            tessellator.draw();

            GlStateManager.disableBlend();
            GlStateManager.enableLighting();
            GlStateManager.popMatrix();
        }
    }
}
blockstate:
{
  "forge_marker": 1,
  "defaults": {
    "model": "lots_of_recipes:chalk",
    "textures": {
      "down": "lots_of_recipes:blocks/ritual_accessories/runes/rune_null",
      "up": "lots_of_recipes:blocks/ritual_accessories/runes/rune_empty",
      "particle": "lots_of_recipes:blocks/ritual_accessories/runes/rune_particle"
    }
  },
  "variants": {
    "normal": [{}],
    "inventory": [{
      "transform": "forge:default-block"
    }],
    "base": {
      "true": { "textures": { "up": "lots_of_recipes:blocks/ritual_accessories/runes/rune_empty" } },
      "false": { "textures": { "up": "lots_of_recipes:blocks/ritual_accessories/runes/rune_null" } }
    },
    "facing": {
      "north": { "y": 0 },
      "south": { "y": 180 },
      "east": { "y": 90 },
      "west": { "y": 270 }
    }
  }
}
2023-10-23_22.55.28.png
 

necauqua

когда-то был anti344
Администратор
1,216
27
172
Так и на кой декоративные тайлы у тебя тикающие?)

Ну кстати мне кажется что таки можно было бы без тайла обойтись, своим рендером для блокстейтов или чем-то эдаким похожим, но это ковырять там надо, да и смысл только если таки много этих твоих рун будет ставиться в мир и это прям будет влиять на перформанс
 
Сверху