Цветочный горшок (1.7.10 - решено), (1.8 - решено)

Статус
В этой теме нельзя размещать новые ответы.
4,046
63
645
Здравствуйте всем!
Перейду сразу к делу:
Сажаю своё растение в цветочный горшок (даже разобрался как это делать). Беда в том, что есть блок растения, а есть семя. Сажаю через метод в самом семечке:
Код:
public boolean onItemUse(...
Код:
if (world.getTileEntity(x, y, z) != null && world.getTileEntity(x, y, z) instanceof TileEntityFlowerPot) {
    TileEntityFlowerPot te = (TileEntityFlowerPot) world.getTileEntity(x, y, z);
    te.func_145964_a(Item.getItemFromBlock(ModBlocks.saltWort), 1);
    te.markDirty();
    world.playSoundEffect((double) x + 0.5D, (double) y + 1.0D, (double) z + 0.5D, ModBlocks.saltWort.stepSound.getBreakSound(), 1.0F, 0.8F);
    --item.stackSize;
     if (!world.setBlockMetadataWithNotify(x, y, z, 1, 2))
     {
         world.markBlockForUpdate(x, y, z);
     }
    return true;        
}
То есть, через семя пихаю в горшок нужный блок.
А вот как заставить горшок дропать не этот блок, а семя?
В этом и вопрос.

В самом горшке есть ещё какие-то форджовские методы... Возможно, всё решается через них, а может быть и через BlockEvent. Но чо-та я туплю.

Как лучше поступить?
Спасибо )
 
643
6
14
Вот тебе наводку, это в блок пихни, а дальше сам.
Код:
    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    {
        if (hasTileEntity(par6) && !(this instanceof BlockContainer))
        {
            par1World.removeBlockTileEntity(par2, par3, par4);
        }
    }
 
4,046
63
645
Ну, как бы... Думаю, наводка сработала.
Решил через BreakEvent =)

Но есть ещё задачка...
Пытаюсь рандомно запихнуть в горшок растения с разной метадатой.
Код:
if (world.getTileEntity(x, y, z) != null && world.getTileEntity(x, y, z) instanceof TileEntityFlowerPot) {
    TileEntityFlowerPot te = (TileEntityFlowerPot) world.getTileEntity(x, y, z);
    if (te.getFlowerPotItem() == null)
    {
        int i = new Random().nextInt(2);
        te.func_145964_a(Item.getItemFromBlock(ModBlocks.saltWort), i);
        te.markDirty();
        world.markBlockForUpdate(x, y, z);
        --item.stackSize;
        return true;
     }

     else {return false;}
}
А получается так:
сажаю первое, затем сажаю рядом второе, и первое меняет мету...

Моё предположение: на клиенте и на сервере создаётся разное рандомное число О_о
Посадка рядом с горшком второго растения заставляет первое обновится и показать истинный серверный вариант.

Если делать проверку на сервер, то в горшок (до обновления) вообще ничего не сажается.

Как это можно побороть?
Спасибо )
 

timaxa007

Модератор
5,831
409
672
Liahim, можно из world брать рандом.
Если используешь "new Random()", то на клиентской и серверной стороне будут показывать разные числа (но не всегда). Если будешь использовать "new Random()", то чтобы увидит на клиентской стороне, то что на серверной стороне - надо с серверной стороны отправлять пакет на клиентскую сторону.
[merge_posts_bbcode]Добавлено: 08.03.2016 10:09:08[/merge_posts_bbcode]

Код:
int i = world.rand.nextInt(2);
 
4,046
63
645
Пробую пихнуть цветок на серверной стороне. А как потом обновить блок на клиенте?
Чо-т я всё уже перепробовал...
Код:
if (!world.isRemote)
{te.func_145964_a(Item.getItemFromBlock(ModBlocks.saltWort), world.rand.nextInt(2));}
world.markBlockForUpdate(x, y, z);
te.markDirty();
te.updateEntity();

Всё равно, сперва ничего не видно... И только если установить какой-нибудь блок рядом, горшок обновляется...
Может, это как-нибудь сэмитировать можно?
 

timaxa007

Модератор
5,831
409
672
Нет, клиент, точнее клиентская сторона. Даже с использованием:
Код:
int i = world.rand.nextInt(2);
это всё равно рандом. Пока-что нормального способа не нашёл. А вот с отправкой пакета, ещё не испробовал.
[merge_posts_bbcode]Добавлено: 08.03.2016 12:46:44[/merge_posts_bbcode]

Liahim, у меня тоже самое.
 

timaxa007

Модератор
5,831
409
672
Вроде, да и ещё надо использовать IMessage.
 
4,046
63
645
Тимаха, что-то не могу найти на клиентской стороне мира как такового. Он вообще есть?
Пока пакет выглядит так:
Код:
public static class Handler implements IMessageHandler<SaltWortSeedMessage, IMessage> {

        @Override
        public IMessage onMessage(SaltWortSeedMessage message, MessageContext ctx) {
            World world = ctx.getServerHandler().playerEntity.worldObj;

            TileEntity te = world.getTileEntity(message.x, message.y, message.z);
и т.д.

Но в этом случает он работает только если посылать от клиента серверу...
И в сингле это даже работает... Обновляется и там и там.
Но, я боюсь, на сервере, посаженный цветок будет видеть только тот, кто его сажает...

Помню, и в ваниле был подобный глюк...
Но как с этим быть?
 

timaxa007

Модератор
5,831
409
672
Эвентом с помощью своего предмета добавлял в ванильный горшок ванильные ростки дерева (так как других примеров блоков для этого не было).
Код:
    @SubscribeEvent
    public void place(PlayerInteractEvent event) {
        ItemStack is = event.entityPlayer.getCurrentEquippedItem();
        if (is != null) {
            if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
                if (is.getItem() == SMTPhytology.item.itemsPhytology && event.world.getTileEntity(event.x, event.y, event.z) != null && event.world.getTileEntity(event.x, event.y, event.z) instanceof TileEntityFlowerPot) {
                    TileEntityFlowerPot tileentityflowerpot = (TileEntityFlowerPot)event.world.getTileEntity(event.x, event.y, event.z);
                    if (tileentityflowerpot.getFlowerPotItem() == null) {

                        if (!event.world.isRemote) {
                            int i = event.world.rand.nextInt(2);
                            tileentityflowerpot.func_145964_a(Item.getItemFromBlock(Blocks.sapling), i);
                            SMTPhytology.network.sendToDimension(new MessageFlowerPotClient(event.x, event.y, event.z, i),
                                    event.world.provider.dimensionId);
                        }
                        tileentityflowerpot.markDirty();
                        event.world.markBlockForUpdate(event.x, event.y, event.z);

                        if (!event.entityPlayer.capabilities.isCreativeMode && --is.stackSize <= 0) {
                            event.entityPlayer.inventory.setInventorySlotContents(event.entityPlayer.inventory.currentItem, (ItemStack)null);
                        }

                    }
                }
            }
        }
    }
SMTPhytology
Код:
    public static SimpleNetworkWrapper network;

    @Mod.EventHandler
    public void preInit(FMLPreInitializationEvent event) {
        network = NetworkRegistry.INSTANCE.newSimpleChannel(MODID);
        network.registerMessage(MessageFlowerPotClient.Handler.class, MessageFlowerPotClient.class, 0, Side.CLIENT);
    }
MessageFlowerPotClient
Код:
public class MessageFlowerPotClient implements IMessage {

    private static int x, y, z, metadata;

    public MessageFlowerPotClient() {}

    public MessageFlowerPotClient(int x, int y, int z, int metadata) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.metadata = metadata;
    }

    @Override
    public void toBytes(ByteBuf buf) {
        buf.writeInt(x);
        buf.writeInt(y);
        buf.writeInt(z);
        buf.writeInt(metadata);
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        x = buf.readInt();
        y = buf.readInt();
        z = buf.readInt();
        metadata = buf.readInt();
    }

    @SideOnly(Side.CLIENT)
    public static class Handler implements IMessageHandler<MessageFlowerPotClient, IMessage> {

        @Override
        public IMessage onMessage(MessageFlowerPotClient packet, MessageContext message) {
            act(packet.x, packet.y, packet.z, packet.metadata);
            return null;
        }

        @SideOnly(Side.CLIENT)
        private void act(int x, int y, int z, int metadata) {
            Minecraft mc = Minecraft.getMinecraft();
            if (mc.theWorld.getTileEntity(x, y, z) != null && mc.theWorld.getTileEntity(x, y, z) instanceof TileEntityFlowerPot) {
                TileEntityFlowerPot tileentityflowerpot = (TileEntityFlowerPot)mc.theWorld.getTileEntity(x, y, z);
                tileentityflowerpot.func_145964_a(Item.getItemFromBlock(Blocks.sapling), metadata);
                //tileentityflowerpot.markDirty();
                mc.theWorld.markBlockForUpdate(x, y, z);
            }
        }

    }

}
Написал для примера, так как я точно не знаю что именно надо было написать.
 
4,046
63
645
О! Спасибо!
Думаю, что как раз этого:
Код:
Minecraft mc = Minecraft.getMinecraft();
if (mc.theWorld.getTileEntity(x, y, z)...

мне и не хватало )))

Проверить смогу только вечером ) Но ты, как всегда крут!
P.S. цветок сажаю через сам айтем... По правому клику )
 

timaxa007

Модератор
5,831
409
672
Объяснить не смогу. Только понимаю, что так он устроен.
Типа, декодер netty пакетов пытается инициализировать класс этого пакета для Instance. Знаю, что без подобного он не может (пока-что) обойтись. Другого способа обхода не пробовал, так как этот мне не мешает.
 
4,046
63
645
Тимах, спасибо! Всё работает... С пакетами разобрался...
Но, блин! Обнаружилась ещё одна проблемка =)

Теперь с дропом...
Для дропа я использую BreakEvent.
Код:
@SubscribeEvent
public void breakBlock(BreakEvent event) {
    if (event.world.getTileEntity(event.x, event.y, event.z) != null &&
        event.world.getTileEntity(event.x, event.y, event.z) instanceof TileEntityFlowerPot)
    {
        TileEntityFlowerPot te = (TileEntityFlowerPot) event.world.getTileEntity(event.x, event.y, event.z);
        if (te.getFlowerPotItem() == Item.getItemFromBlock(ModBlocks.saltWort))
            te.func_145964_a(ModItems.saltWortSeed, 0);
    }
}
Выясняю, когда горшок добывается игроком и подменяю блок айтемом...
Но! Это не работает, если горшок выпадает при разрушения блока под ним...
Есть ли какой-нибудь эвент для этого?

Спасибо )
[merge_posts_bbcode]Добавлено: 10.03.2016 00:22:11[/merge_posts_bbcode]

Всё! Разобрался )))
Изменил эвент на такой:
Код:
@SubscribeEvent
public void breakBlock(HarvestDropsEvent event) {
    if (event.world.getTileEntity(event.x, event.y, event.z) != null &&
        event.world.getTileEntity(event.x, event.y, event.z) instanceof TileEntityFlowerPot)
    {
        TileEntityFlowerPot te = (TileEntityFlowerPot) event.world.getTileEntity(event.x, event.y, event.z);
        if (te.getFlowerPotItem() == Item.getItemFromBlock(ModBlocks.saltWort))
            event.drops.set(1, new ItemStack(ModItems.saltWortSeed));
    }
}

Всем спасибо, тему можно закрывать )
 
4,046
63
645
Народ! Всем привет ещё раз...
С горшком 1.7.10 я разобрался... Настало время 1.8+

И вот тут как-раз таки засада...
А дело вот в чём: через тайл горшка цветок сажается аналогично версии 1.7.10. Но! Теперь же они все модельки загнали в .json! И мой цветок в горшке просто не виден, ибо в классе EnumFlowerType для него, естественно, нет варианта модели.
Ну, это моё предположение, от чего не может быть виден цветок... Возможно, вы знаете правильное решение.

Однако, у меня есть 2 варианта, как это можно побороть:
1 - создать свой блок горшка с собственной моделькой цветка... Чего делать не хочется, ибо криво. Да и, походе, что общих моделей именно для горшка с цветком не существует.
2 - отсюда 2-й вариант: подпихнуть свою модель цветка в класс EnumFlowerType.

Но как это сделать?
Мои кривые попытки:
Код:
int i = world.rand.nextInt(2);
te.setFlowerPotData(Item.getItemFromBlock(ModBlocks.saltWort), i); //пихаю цветок в тайл
                    
String str = new String(SaltWort.EnumType.byMetadata(i).toString()); //узнаю название нужного варианта моего цветка
IBlockState state = world.getBlockState(pos).withProperty(BlockFlower.EnumFlowerType.valueOf(SaltWort.EnumType.class, str), i); //пытаюсь создать BlockState на основе EnumFlowerType, но с подставленным моим цветком (не получается, подчёркивает withProperty)
world.setBlockState(pos, state, 3); //заменяю BlockState на свою

Знатоки 1.8 отзовитесь! )))
 
4,046
63
645
Итак! Пытаюсь добавить кастомный EnumFlowerType в цветочный горшок.
Нашёл такую тему. Однако, что-то не могу толком разобраться что, да как...
Попытки:
Код:
public static EnumFlowerType SALTWORT = EnumHelper.addEnum(BlockFlowerPot.EnumFlowerType.class, SaltMod.MODID + ":" + "SALTWORT", new Class<?>[] { String.class }, new Object[] { "saltwort" });
Здесь я, вроде как, просто регистрирую имя нового EnumType.

Ну, и тупо заменяю BlockState горшка:
Код:
int i = world.rand.nextInt(2);
IBlockState state = world.getBlockState(pos).withProperty(BlockFlowerPot.CONTENTS, ModBlocks.SALTWORT).withProperty(BlockFlowerPot.LEGACY_DATA, Integer.valueOf(i));
world.setBlockState(pos, state, 3);
te.setFlowerPotData(Item.getItemFromBlock(ModBlocks.saltWort), i);

Однако, ничего не выходит.
Во-первых, при запуске пишет такое:
Код:
Cannot set property PropertyEnum{name=contents, clazz=class net.minecraft.block.BlockFlowerPot$EnumFlowerType, values=[empty, rose, blue_orchid, allium, houstonia, red_tulip, orange_tulip, white_tulip, pink_tulip, oxeye_daisy, dandelion, oak_sapling, spruce_sapling, birch_sapling, jungle_sapling, acacia_sapling, dark_oak_sapling, mushroom_red, mushroom_brown, dead_bush, fern, cactus]} to saltwort on block minecraft:flower_pot, it is not an allowed value

Во-вторых, в этот EnumType как-то нужно запихнуть мой блок... По идее, никаких новых моделей создавать не надо, ибо модель он должен брать с самого блока... Где это прописать?

Пока что, ни с первым, ни со вторым не могу разобраться...

P.S. Нашёл, так же, это: pastebin.com/XrrSJbih.
Но там как-то всё сложно, через рефлексию, и вообще я не уверен, что это то самое )))

Где ж знатоки-то?
Хелп!
 
4,046
63
645
Охох...
Этот горшок меня доканает... Настоло время мне не понимать ничего в EnumTypes.

В общем! Поспрашивал народ на заграничных форумах, говорят, никак в 1.8 свой цветок в ванильный горшок не посадить, какая-то там странная система у него. Если интересно, ответы можно посмотреть по ссылке выше.

Однако! Можно создать свой горшок и уже в него сажать, что вздумается...

Начал... Вылетает собака!
Создал блок extends BlockFlowerPot.
Код:
public class SaltPot extends BlockFlowerPot {    

    public static final PropertyInteger LEGACY_DATA = PropertyInteger.create("legacy_data", 0, 15);
    public static final PropertyEnum CONTENTS = PropertyEnum.create("contents", SaltPot.EnumFlowerType.class);
    
    public SaltPot(String name, CreativeTabs tab) {
        this.setUnlocalizedName(name);
        this.setCreativeTab(tab);
        this.setDefaultState(this.blockState.getBaseState().withProperty(CONTENTS, SaltPot.EnumFlowerType.EMPTY).withProperty(LEGACY_DATA, Integer.valueOf(0)));
    }
    
    @Override
    public TileEntity createNewTileEntity(World worldIn, int meta)
    {
        Object object = null;
        int j = 0;

        switch (meta)
        {
            case 1:
                object = ModBlocks.saltWort;
                j = SaltWort.EnumType.STAGE_0.getMetadata();
                break;
            case 2:
                object = ModBlocks.saltWort;
                j = SaltWort.EnumType.STAGE_1.getMetadata();
                break;
        }

        return new TileEntityFlowerPot(Item.getItemFromBlock((Block)object), j);
    }
    
    @Override
    public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos)
    {
        SaltPot.EnumFlowerType enumflowertype = SaltPot.EnumFlowerType.EMPTY;
        TileEntity tileentity = worldIn.getTileEntity(pos);

        if (tileentity instanceof TileEntityFlowerPot)
        {
            TileEntityFlowerPot tileentityflowerpot = (TileEntityFlowerPot)tileentity;
            Item item = tileentityflowerpot.getFlowerPotItem();

            if (item instanceof ItemBlock)
            {
                int i = tileentityflowerpot.getFlowerPotData();
                Block block = Block.getBlockFromItem(item);

                if (block == ModBlocks.saltWort)
                {
                    switch (i)
                    {
                        case 0:
                            enumflowertype = SaltPot.EnumFlowerType.SALTWORT_0;
                            break;
                        case 1:
                            enumflowertype = SaltPot.EnumFlowerType.SALTWORT_1;
                            break;
                        default:
                            enumflowertype = SaltPot.EnumFlowerType.EMPTY;
                    }
                }
            }
        }

        return state.withProperty(CONTENTS, enumflowertype);
    }
    
    public static enum EnumFlowerType implements IStringSerializable
    {
        EMPTY("empty"),
        SALTWORT_0("saltwort_0"),
        SALTWORT_1("saltwort_1");
        private final String name;

        private EnumFlowerType(String name)
        {
            this.name = name;
        }

        public String toString()
        {
            return this.name;
        }

        public String getName()
        {
            return this.name;
        }
    }

    static final class SwitchEnumType
        {
            static final int[] FLOWER_TYPE_LOOKUP = new int[SaltWort.EnumType.values().length];

            static
            {
                try
                {
                    FLOWER_TYPE_LOOKUP[SaltWort.EnumType.STAGE_0.ordinal()] = 1;
                }
                catch (NoSuchFieldError var1)
                {
                    ;
                }

                try
                {
                    FLOWER_TYPE_LOOKUP[SaltWort.EnumType.STAGE_1.ordinal()] = 2;
                }
                catch (NoSuchFieldError var2)
                {
                    ;
                }
            }
        }
}

Просто переопределяю все те методы, которые отвечают за PropertyEnum CONTENTS.

При запуске пишет:
Код:
Cannot set property PropertyEnum{name=contents, clazz=class ru.liahim.saltmod.block.SaltPot$EnumFlowerType, values=[empty, saltwort_0, saltwort_1]} as it does not exist in BlockState{block=null, properties=[contents, legacy_data]}
и указывает на строчку this.setDefaultState...

Что я забыл?
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху