Jump to content

[1.12.2] MissingVariantException when making a custom sign with TESR


Major Squirrel

Recommended Posts

Good evening,

I'm modding a custom sign which is translucent and smaller than the Vanilla's one.

 

Spoiler

image.png.d86dae174175b75cee3e0543c9ebee6e.png


I've looked for Vanilla classes to mimic the existing BlockSign and its children BlockStandingSign and BlockWallSign. I've also made a custom TileEntitySpecialRenderer and registered it.

(BlockRPSign.java)

Spoiler

public class    BlockRPSign extends BlockContainer {

    private static final AxisAlignedBB  RP_SIGN_AABB = new AxisAlignedBB(0.25D, 0.0D, 0.25D, 0.75D, 0.8125D, 0.75D);

    protected   BlockRPSign() {
        super(Material.WOOD);
    }

    @Override
    public AxisAlignedBB    getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
        return (BlockRPSign.RP_SIGN_AABB);
    }

    @Nullable
    @Override
    public AxisAlignedBB    getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos) {
        return (NULL_AABB);
    }

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

    @Override
    @SideOnly(Side.CLIENT)
    public boolean hasCustomBreakingProgress(IBlockState state) {
        return (true);
    }

    @Override
    public boolean  isPassable(IBlockAccess worldIn, BlockPos pos) {
        return (true);
    }

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

    @Override
    public boolean  canSpawnInBlock() {
        return (true);
    }

    @Nullable
    @Override
    public TileEntity   createNewTileEntity(World worldIn, int meta) {
        return (new TileEntityRPSign());
    }

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

    @Override
    public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) {
        return (new ItemStack(MyModItems.roleplay_sign));
    }

    @Override
    public boolean  onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
        if (!worldIn.isRemote) {
            Minecraft.getMinecraft().displayGuiScreen(new GuiRolePlayScreen());
            return (true);
        } else
            return (true);
    }

    @Override
    public boolean  canPlaceBlockAt(World worldIn, BlockPos pos) {
        return (!this.hasInvalidNeighbor(worldIn, pos) && super.canPlaceBlockAt(worldIn, pos));
    }

    @Override
    public BlockFaceShape   getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face) {
        return (BlockFaceShape.UNDEFINED);
    }
}

 

 

(BlockStandingRPSign.java)

Spoiler

public final class  BlockStandingRPSign extends BlockRPSign {

    public static final PropertyInteger ROTATION = PropertyInteger.create("rotation", 0, 15);

    public  BlockStandingRPSign() {
        super();

        this.setHardness(1.0F);
        this.setSoundType(SoundType.WOOD);
        this.disableStats();

        this.setDefaultState(this.blockState.getBaseState().withProperty(ROTATION, Integer.valueOf(0)));
    }

    @Override
    public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) {
        if (!worldIn.getBlockState(pos.down()).getMaterial().isSolid()) {
            this.dropBlockAsItem(worldIn, pos, state, 0);
            worldIn.setBlockToAir(pos);
        }

        super.neighborChanged(state, worldIn, pos, blockIn, fromPos);
    }

    @Override
    public IBlockState getStateFromMeta(int meta) {
        return (this.getDefaultState().withProperty(ROTATION, Integer.valueOf(meta)));
    }

    @Override
    public int getMetaFromState(IBlockState state) {
        return (state.getValue(ROTATION).intValue());
    }

    @Override
    public IBlockState  withRotation(IBlockState state, Rotation rot) {
        return (state.withProperty(ROTATION, Integer.valueOf(rot.rotate(((Integer)state.getValue(ROTATION)).intValue(), 16))));
    }

    @Override
    public IBlockState  withMirror(IBlockState state, Mirror mirrorIn) {
        return (state.withProperty(ROTATION, Integer.valueOf(mirrorIn.mirrorRotation(((Integer)state.getValue(ROTATION)).intValue(), 16))));
    }

    @Override
    protected BlockStateContainer   createBlockState() {
        return (new BlockStateContainer(this, new IProperty[] {ROTATION}));
    }
}

 

 

(BlockWallRPSign.java)

Spoiler

public final class  BlockWallRPSign extends BlockRPSign {

    public static final PropertyDirection   FACING = BlockHorizontal.FACING;
    protected static final AxisAlignedBB    RP_SIGN_EAST_AABB = new AxisAlignedBB(0.0D, 0.3125D, 0.125D, 0.0625D, 0.6875D, 0.875D);
    protected static final AxisAlignedBB    RP_SIGN_WEST_AABB = new AxisAlignedBB(0.9375D, 0.3125D, 0.125D, 1.0D, 0.6875D, 0.875D);
    protected static final AxisAlignedBB    RP_SIGN_SOUTH_AABB = new AxisAlignedBB(0.125D, 0.3125D, 0.0D, 0.875D, 0.6875D, 0.0625D);
    protected static final AxisAlignedBB    RP_SIGN_NORTH_AABB = new AxisAlignedBB(0.125D, 0.3125D, 0.9375D, 0.875D, 0.6875D, 1.0D);

    public  BlockWallRPSign() {
        super();

        this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));

        this.setHardness(1.0F);
        this.setSoundType(SoundType.WOOD);
        this.disableStats();
    }

    @Override
    public AxisAlignedBB    getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
        switch ((EnumFacing)state.getValue(FACING)) {
            case NORTH:
            default:
                return (RP_SIGN_NORTH_AABB);
            case SOUTH:
                return (RP_SIGN_SOUTH_AABB);
            case WEST:
                return (RP_SIGN_WEST_AABB);
            case EAST:
                return (RP_SIGN_EAST_AABB);
        }
    }

    @Override
    public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) {
        EnumFacing  enumfacing = (EnumFacing)state.getValue(FACING);

        if (!worldIn.getBlockState(pos.offset(enumfacing.getOpposite())).getMaterial().isSolid()) {
            this.dropBlockAsItem(worldIn, pos, state, 0);
            worldIn.setBlockToAir(pos);
        }

        super.neighborChanged(state, worldIn, pos, blockIn, fromPos);
    }

    @Override
    public IBlockState  getStateFromMeta(int meta) {
        EnumFacing  enumfacing = EnumFacing.getFront(meta);

        if (enumfacing.getAxis() == EnumFacing.Axis.Y) {
            enumfacing = EnumFacing.NORTH;
        }

        return (this.getDefaultState().withProperty(FACING, enumfacing));
    }

    @Override
    public int getMetaFromState(IBlockState state) {
        return (((EnumFacing)state.getValue(FACING)).getIndex());
    }

    @Override
    public IBlockState  withRotation(IBlockState state, Rotation rot) {
        return (state.withProperty(FACING, rot.rotate((EnumFacing)state.getValue(FACING))));
    }

    @Override
    public IBlockState  withMirror(IBlockState state, Mirror mirrorIn) {
        return (state.withRotation(mirrorIn.toRotation((EnumFacing)state.getValue(FACING))));
    }

    @Override
    protected BlockStateContainer createBlockState() {
        return (new BlockStateContainer(this, new IProperty[] {FACING}));
    }
}

 

 

(ItemRPSign.java)

Spoiler

public class    ItemRPSign extends Item {

    public  ItemRPSign() {
        super();

        this.maxStackSize = 1;
        this.setCreativeTab(CreativeTabs.DECORATIONS);
    }

    @Override
    public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
        IBlockState iblockstate = worldIn.getBlockState(pos);
        boolean     flag = iblockstate.getBlock().isReplaceable(worldIn, pos);

        if (facing != EnumFacing.DOWN && (iblockstate.getMaterial().isSolid() || flag) && (!flag || facing == EnumFacing.UP)) {
            pos = pos.offset(facing);
            ItemStack   itemstack = player.getHeldItem(hand);

            if (player.canPlayerEdit(pos, facing, itemstack) && MyModBlocks.standing_rp_sign.canPlaceBlockAt(worldIn, pos)) {
                if (worldIn.isRemote) {
                    return (EnumActionResult.SUCCESS);
                } else {
                    pos = flag ? pos.down() : pos;

                    if (facing == EnumFacing.UP) {
                        int i = MathHelper.floor((double)((player.rotationYaw + 180.0F) * 16.0F / 360.0F) + 0.5D) & 15;

                        worldIn.setBlockState(pos, MyModBlocks.standing_rp_sign.getDefaultState().withProperty(BlockStandingRPSign.ROTATION, Integer.valueOf(i)), 11);
                    } else {
                        worldIn.setBlockState(pos, MyModBlocks.wall_rp_sign.getDefaultState().withProperty(BlockWallRPSign.FACING, facing), 11);
                    }

                    //  TODO: Implement custom sign edit here

                    if (player instanceof EntityPlayerMP) {
                        CriteriaTriggers.PLACED_BLOCK.trigger((EntityPlayerMP)player, pos, itemstack);
                    }

                    itemstack.shrink(1);
                    return (EnumActionResult.SUCCESS);
                }
            } else {
                return (EnumActionResult.FAIL);
            }
        } else {
            return (EnumActionResult.FAIL);
        }
    }
}

 

 

(TileEntityRPSignRenderer.java)

Spoiler

@SideOnly(Side.CLIENT)
public final class  TileEntityRPSignRenderer extends TileEntitySpecialRenderer<TileEntityRPSign> {

    private static final ResourceLocation   RP_SIGN_TEXTURE = new ResourceLocation(MyModMenu.MODID + ":textures/entity/roleplay_sign.png");

    private final ModelSign model = new ModelSign();

    public void render(TileEntityRPSign te, double x, double y, double z, float partialTicks, int destroyStage, float alpha) {
        Block   block = te.getBlockType();

        GlStateManager.pushMatrix();
        if ("standing_rp_sign".equals(block.getUnlocalizedName().substring(5))) {
            GlStateManager.translate((float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F);
            GlStateManager.translate(0.0F, -0.125F, 0.0F);
            float   f1 = (float)(te.getBlockMetadata() * 360) / 16.0F;
            GlStateManager.rotate(-f1, 0.0F, 1.0F, 0.0F);
            this.model.signStick.showModel = true;
        } else {
            int     k = te.getBlockMetadata();
            float   f2 = 0.0F;

            if (k == 2) {
                f2 = 180.0F;
            }

            if (k == 4) {
                f2 = 90.0F;
            }

            if (k == 5) {
                f2 = -90.0F;
            }

            GlStateManager.translate((float)x + 0.5F, (float)y + 0.5F, (float)z + 0.5F);
            GlStateManager.rotate(-f2, 0.0F, 1.0F, 0.0F);
            GlStateManager.translate(0.0F, -0.25F, -0.46875F);
            this.model.signStick.showModel = false;
        }

        if (destroyStage >= 0) {
            this.bindTexture(DESTROY_STAGES[destroyStage]);
            GlStateManager.matrixMode(5890);
            GlStateManager.pushMatrix();
            GlStateManager.scale(4.0F, 2.0F, 1.0F);
            GlStateManager.translate(0.0625F, 0.0625F, 0.0625F);
            GlStateManager.matrixMode(5888);
        } else {
            this.bindTexture(RP_SIGN_TEXTURE);
        }

        GlStateManager.enableRescaleNormal();
        GlStateManager.pushMatrix();
        GlStateManager.scale(0.5F, -0.5F, -0.5F);
        GlStateManager.enableBlend();
        GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
        this.model.renderSign();
        GlStateManager.disableBlend();
        GlStateManager.popMatrix();

        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
        GlStateManager.popMatrix();

        if (destroyStage >= 0) {
            GlStateManager.matrixMode(5890);
            GlStateManager.popMatrix();
            GlStateManager.matrixMode(5888);
        }
    }
}

 

 

(MyModBlocks.java)

Spoiler

@GameRegistry.ObjectHolder(MyModMenu.MODID)
public final class  MyModBlocks {

    public static final BlockStandingRPSign standing_rp_sign = null;
    public static final BlockWallRPSign     wall_rp_sign = null;

    @Mod.EventBusSubscriber(modid = MyModMenu.MODID)
    public static class RegistrationHandler {

        @SubscribeEvent
        public static void  registerBlocks(final RegistryEvent.Register<Block> event) {
            System.out.println("Registering blocks...");

            final IForgeRegistry<Block> registry = event.getRegistry();

            registry.register(NameUtils.setBlockName(new BlockStandingRPSign(), "standing_rp_sign"));
            registry.register(NameUtils.setBlockName(new BlockWallRPSign(), "wall_rp_sign"));
        }

        @SubscribeEvent
        public static void  registerItemBlocks(final RegistryEvent.Register<Item> event) {
            System.out.println("Registering itemblocks...");

            final IForgeRegistry<Item>  registry = event.getRegistry();
        }

        @SubscribeEvent
        @SideOnly(Side.CLIENT)
        public static void  registerModels(final ModelRegistryEvent event) {
            System.out.println("Registering blocks' models...");

            //RegistrationHandler.registerBlockModel(standing_rp_sign, 0);
            //RegistrationHandler.registerBlockModel(wall_rp_sign, 0);

            System.out.println("Registering itemblocks' models...");

            RegistrationHandler.registerItemBlockModels();

            System.out.println("Registering tileentities' special renderers...");

            ClientRegistry.bindTileEntitySpecialRenderer(TileEntityRPSign.class, new TileEntityRPSignRenderer());
        }

        @SideOnly(Side.CLIENT)
        public static void  registerBlockModel(Block block, int metadata) {
            ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), metadata,
                    new ModelResourceLocation(MyModMenu.MODID + ":" + block.getUnlocalizedName().substring(5), "inventory"));
        }

        @SideOnly(Side.CLIENT)
        public static void  registerItemBlockModels() {
            
        }

        @SideOnly(Side.CLIENT)
        public static void  registerItemBlockModel(ItemBlock block, int metadata) {
            ModelLoader.setCustomModelResourceLocation(block, metadata,
                    new ModelResourceLocation(block.getRegistryName(), "inventory"));
        }
    }
}

 

 

(MyModItems.java)

Spoiler

@GameRegistry.ObjectHolder(MyModMenu.MODID)
public final class  MyModItems {

    public static final ItemRPSign  roleplay_sign = null;

    @Mod.EventBusSubscriber(modid = MyModMenu.MODID)
    public static class RegistrationHandler {

        @SubscribeEvent
        public static void  registerItems(final RegistryEvent.Register<Item> event) {
            System.out.println("Registering items...");

            final IForgeRegistry<Item>  registry = event.getRegistry();

            registry.register(NameUtils.setItemName(new ItemRPSign(), "roleplay_sign"));
        }

        @SubscribeEvent
        public static void  registerModels(final ModelRegistryEvent event) {
            System.out.println("Registering items' models...");

            RegistrationHandler.registerItemModel(roleplay_sign, 0);
        }

        @SideOnly(Side.CLIENT)
        public static void  registerItemModel(Item item, int metadata) {
            ModelLoader.setCustomModelResourceLocation(item, metadata,
                    new ModelResourceLocation(item.getRegistryName(), "inventory"));
        }
    }
}

 

 

(MyModTileEntities.java)

Spoiler

public final class  MyModTileEntities {

    public static void  registerTileEntities() {
        System.out.println("Registering tileentities...");

        GameRegistry.registerTileEntity(TileEntityRPSign.class, new ResourceLocation(MyModMenu.MODID, "tile_rp_sign"));
    }
}

 


(As you may see, I'm using @jabelar mod structure from the GitHub repo here)

I'm getting a net.minecraft.client.renderer.block.model.ModelBlockDefinition$MissingVariantException for my standing_rp_sign blockstate with rotation variants. I haven't created any blockstate file for both standing and wall signs since there is an existing TESR which handles the rendering. I've tried to look for a model loading from Vanilla's sign but I didn't find anything. My guess would be to indicate Forge to avoid handling models for those blocks but i don't know how to do that.

Also, since there is no blockstate and no model attached to the blocks, there are random particles emitted when breaking the block. Vanilla sign has woods particles but I can't see any code or model file that indicates the texture to use for particles from Vanilla.


Finally, as you can see in the TESR I'm trying to check the block type from the tileentity (this is done in Vanilla using Block#getBlockType which returns a Block). Is there a better way to do it ?

Thank you for your help.

 

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

9 minutes ago, Major Squirrel said:

I haven't created any blockstate file for both standing and wall signs

 

9 minutes ago, Major Squirrel said:

I'm getting a net.minecraft.client.renderer.block.model.ModelBlockDefinition$MissingVariantException

Well, what did you expect? If you haven't created a blockstates file for your block then the game is gonna complain that there isn't one.

Minecraft itself marks the sign as having a "built-in" model and doesn't even attempt to load it's model as a result.

 

15 minutes ago, Major Squirrel said:

My guess would be to indicate Forge to avoid handling models for those blocks but i don't know how to do that.

Why not just create an "empty" blockstates file? That would also allow you to define the breaking particle.

You could also use a custom implementation of a IStateMapper.

 

17 minutes ago, Major Squirrel said:

Also, since there is no blockstate and no model attached to the blocks, there are random particles emitted when breaking the block. Vanilla sign has woods particles but I can't see any code or model file that indicates the texture to use for particles from Vanilla.

 

Unfortuntely vanilla is pretty bad when it comes to handling exceptional cases. The particle textures for the sign are hardcoded in BlockModelShapes#getTexture. If you want a particle texture yourself then either use an "empty" model or a custom IBakedModel implementation.

 

19 minutes ago, Major Squirrel said:

Finally, as you can see in the TESR I'm trying to check the block type from the tileentity (this is done in Vanilla using Block#getBlockType which returns a Block). Is there a better way to do it ?

That's fine.

 

Your code is an insane mess though:

19 minutes ago, Major Squirrel said:

return (null);

Why re you doing (this)? There is no reason to write your code (like that) or {like that}. Don't do that, it is impossible to read and is absolutely not necessarry.

 

20 minutes ago, Major Squirrel said:

protected    BlockRPSign()

Why do you have a \t symbol between your modifiers and the names? That makes no sense and is difficult to read. Where did you get that coding style anyway? I have never seen anybody space their code like that.

 

21 minutes ago, Major Squirrel said:

extends BlockContainer

Don't. There is no need to extend BlockContainer, just extend Block and override Block#createTileEntity and Block#hasTileEntity.

 

22 minutes ago, Major Squirrel said:

if (!worldIn.isRemote) { Minecraft.getMinecraft().displayGuiScreen(new GuiRolePlayScreen());

This 

   1) Makes no sense

   2) Is reaching across logical sides

   3) Will crash on a server

 

Don't ever do that. Use forge's method(EntityPlayer#openGui) to opeen GUI's. 

Don't reference client-only classes in common code, this will crash the server.

Don't reach across logical sides, that WILL break everything possible. And will crash the server.

 

24 minutes ago, Major Squirrel said:

Integer.valueOf(0)

25 minutes ago, Major Squirrel said:

Integer.valueOf(meta)

...Why? It will just return you the said 0. There is no reason to do this. Fix all of these in your code, there are a ton.

 

25 minutes ago, Major Squirrel said:

Integer.valueOf(rot.rotate(((Integer)state.getValue(ROTATION)).intValue(), 16)))

This is the prime reason why. Do you yourselves understand what's going on here? All of these casts, valueof and stuff are making it impossible to see what's actually going on.

It also wastes CPU cycles and RAM space doing pointless boxing/unboxing operations.

 

27 minutes ago, Major Squirrel said:

new IProperty[] {ROTATION}

There is no need to explicitly create a new array here. The input variable is a params one already(... modifier).

 

28 minutes ago, Major Squirrel said:

@SubscribeEvent @SideOnly(Side.CLIENT)

Don't abuse SideOnly. Have dedicated client-side only event handlers.

 

29 minutes ago, Major Squirrel said:

if ("standing_rp_sign".equals(block.getUnlocalizedName().substring(5))) {

Dear lord, why? Just compare the block you have to the constant you have in the MyModBlocks. Don't ever do stuff like this.

 

30 minutes ago, Major Squirrel said:

int k = te.getBlockMetadata();

Don't do that, metadata is gone in 1.13 anyway. Just use the blockstate properties.

 

I am not going to complain about magic numbers in your TESR since you just copied the vanilla sign TESR, but don't use magic numbers in general.

  • Thanks 1
Link to comment
Share on other sites

Good evening,

Thank you @V0idWa1k3r for your answer.
 

4 hours ago, V0idWa1k3r said:

Minecraft itself marks the sign as having a "built-in" model and doesn't even attempt to load it's model as a result.

 

I couldn't find it in Vanilla code earlier. Is it in the BlockModelShapes#registerAllBlocks method ?


I guess I will have to create an "empty" blockstates file if I want to override emitted particles anyway.
 

4 hours ago, V0idWa1k3r said:

Use forge's method(EntityPlayer#openGui) to opeen GUI's.


Isn't this method supposed to be used when there is a Container attached to the TileEntity ? My TileEntity has no Container, it just has some data stored (TextComponents) in it.

 

For what is left, I simply copied/pasted Vanilla code. Now I've fixed the useless casts, boxing/unboxing, arrays, etc... Thank you for that.

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

53 minutes ago, Major Squirrel said:

Isn't this method supposed to be used when there is a Container attached to the TileEntity ? My TileEntity has no Container, it just has some data stored (TextComponents) in it.

In that case use a proxy. You can't reference client-only classes(Minecraft, Gui) in common code anyways

Link to comment
Share on other sites

I've added "empty" blockstate files and model files like so :

(blockstates/standing_rp_sign.json)

Spoiler

{
	"variants": {
        "rotation=0": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=1": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=2": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=3": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=4": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=5": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=6": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=7": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=8": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=9": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=10": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=11": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=12": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=13": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=14": { "model": "mymodmenu:standing_rp_sign" },
		"rotation=15": { "model": "mymodmenu:standing_rp_sign" }
    }
}

 

 

(blockstates/wall_rp_sign.json)

Spoiler

{
	"variants": {
        "facing=east": { "model": "mymodmenu:wall_rp_sign" },
		"facing=south": { "model": "mymodmenu:wall_rp_sign" },
		"facing=west": { "model": "mymodmenu:wall_rp_sign" },
		"facing=north": { "model": "mymodmenu:wall_rp_sign" }
    }
}

 

 

(models/block/standing_rp_sign.json and models/block/wall_rp_sign.json)

Spoiler

{	"textures": {
		"particle": "blocks/planks_oak"
    }
}

 

 

It does fix all MissingVariant exceptions as well as emitted particles when signs are destroyed.

 

However, when changing my BlockRPSign from BlockContainer to Block with Block#hasTileEntity and Block#createTileEntity overriden, the render() method from the TESR is not called anymore. Instead, I've made my class extend to Block, implementing ITileEntityProvider. It works now.

 

40 minutes ago, V0idWa1k3r said:

In that case use a proxy. You can't reference client-only classes(Minecraft, Gui) in common code anyways


What do you mean by proxy ? Sending a packet to the server and the server opens a player GUI ?
 

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

7 minutes ago, Major Squirrel said:

Instead, I've made my class extend to Block, implementing ITileEntityProvider. It works now.

Don't do that either. That class is legacy code that won't work properly.

Show your code(without extending ITileEntityProvider)

 

7 minutes ago, Major Squirrel said:

What do you mean by proxy ? Sending a packet to the server and the server opens a player GUI ?

https://mcforge.readthedocs.io/en/latest/concepts/sides/#sidedproxy

Link to comment
Share on other sites

53 minutes ago, V0idWa1k3r said:

Show your code(without extending ITileEntityProvider)

 

(BlockRPSign.java)

Spoiler

public class    BlockRPSign extends Block {

    private static final AxisAlignedBB  RP_SIGN_AABB = new AxisAlignedBB(0.25D, 0.0D, 0.25D, 0.75D, 0.8125D, 0.75D);

    protected   BlockRPSign() {
        super(Material.WOOD);
    }

    @Override
    public AxisAlignedBB    getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
        return (BlockRPSign.RP_SIGN_AABB);
    }

    @Nullable
    @Override
    public AxisAlignedBB    getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos) {
        return (NULL_AABB);
    }

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

    @Override
    @SideOnly(Side.CLIENT)
    public boolean hasCustomBreakingProgress(IBlockState state) {
        return (true);
    }

    @Override
    public boolean  isPassable(IBlockAccess worldIn, BlockPos pos) {
        return (true);
    }

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

    @Override
    public boolean  canSpawnInBlock() {
        return (true);
    }

    @Override
    public boolean  hasTileEntity(IBlockState state) {
        return (true);
    }

    @Nullable
    @Override
    public TileEntity   createTileEntity(World world, IBlockState state) {
        return (new TileEntityRPSign());
    }

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

    @Override
    public ItemStack getItem(World worldIn, BlockPos pos, IBlockState state) {
        return (new ItemStack(MyModItems.roleplay_sign));
    }

    @Override
    public boolean  onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
        if (!worldIn.isRemote) {
            // TODO: serverside GUI opening
            return (true);
        } else
            return (true);
    }

    @Override
    public BlockFaceShape   getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face) {
        return (BlockFaceShape.UNDEFINED);
    }
}

 


It works with the code above, I was overriding the wrong hasTileEntity method (the one without any parameter) , thank you.
 

53 minutes ago, V0idWa1k3r said:

 

Could you please explain a little more about why you indicate me to use a proxy ? I know this part of code is executed on the server thread and I'm calling clientside code with Minecraft#displayGuiScreen, but I don't find a way to open a GUI remotely of a TileEntity without any Container.

EDIT: is it as simple as using a GuiHandler and returning null in getServerGuiElement ...?

Edited by Major Squirrel

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

If you need to open a containerless GUI from the server side, you'll need to send a custom packet to the client.  But if you're doing this from onBlockActivated(), is there a reason you can't just open the GUI if called client-side (maybe you want to do some server-side validation first, I haven't examined your code too closely) ?

Link to comment
Share on other sites

2 hours ago, desht said:

If you need to open a containerless GUI from the server side, you'll need to send a custom packet to the client.  But if you're doing this from onBlockActivated(), is there a reason you can't just open the GUI if called client-side (maybe you want to do some server-side validation first, I haven't examined your code too closely) ?

 

The purpose would be to display data stored in the TileEntity, inside a GUI. Then, I guess I would call the server to retrieve the data and to pass it to the GUI ?

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

15 minutes ago, Major Squirrel said:

 

The purpose would be to display data stored in the TileEntity, inside a GUI. Then, I guess I would call the server to retrieve the data and to pass it to the GUI ?

If the data is only needed client-side for GUI display purposes (as opposed to block rendering purposes), you could just have that custom packet sync the necessary data and trigger the GUI opening client-side.  If you do it this, you might also need a way to update any already-open GUIs if any data changes server-side (that's dependent on how you intend your GUI to work).

If the data is also needed for block rendering, it needs to be sync'd in some other way whenever it changes server-side.  Either via vanilla-style TE syncing (getUpdatePacket() / onDataPacket()) or - preferably - via a custom packet.

Link to comment
Share on other sites

8 hours ago, desht said:

If the data is only needed client-side for GUI display purposes (as opposed to block rendering purposes), you could just have that custom packet sync the necessary data and trigger the GUI opening client-side.


Thank you @desht, I will give a try.

Also, I'm trying to avoid using TESR by only using Forge Blockstate format. For the wall sign it is pretty easy as Vanilla blockstate increments rotation every 90 degrees, but for the standing sign it is a little bit more complicated as it has 16 possible rotations.

I've read this post where it is advised to use the Forge Blockstate V1 specs available here but I guess I have difficulties in understanding the specs.

Here is what I got :

 

Spoiler

image.png.84239ee243f55b95a348628a58bd15e6.png

 

The original model for the block (the uniform face is purposely complete beige so I could see where it faces) :

 

Spoiler

image.png.5aaadb552e9e882518dec02b6010f962.png

 

(blockstates/standing_rp_sign.json)

Spoiler

{
	"forge_marker": 1,
	"defaults": {
		"model": "mymod:standing_rp_sign",
		"uvlock": true
	},
	"variants": {
		"rotation": {
			"0": {
				"transform": { "rotation": { "y": 180 } }
			},
			"1": {
				"transform": { "rotation": { "y": 157.5 } }
			},
			"2": {
				"transform": { "rotation": { "y": 135 } }
			},
			"3": {
				"transform": { "rotation": { "y": 112.5 } }
			},
			"4": {
				"transform": { "rotation": { "y": 90 } }
			},
			"5": {
				"transform": { "rotation": { "y": 67.5 } }
			},
			"6": {
				"transform": { "rotation": { "y": 45 } }
			},
			"7": {
				"transform": { "rotation": { "y": 22.5 } }
			},
			"8": {
				"transform": { "rotation": { "y": 0 } }
			},
			"9": {
				"transform": { "rotation": { "y": 0 } }
			},
			"10": {
				"transform": { "rotation": { "y": 0 } }
			},
			"11": {
				"transform": { "rotation": { "y": 0 } }
			},
			"12": {
				"transform": { "rotation": { "y": 0 } }
			},
			"13": {
				"transform": { "rotation": { "y": 0 } }
			},
			"14": {
				"transform": { "rotation": { "y": 0 } }
			},
			"15": {
				"transform": { "rotation": { "y": 0 } }
			}
		}
    }
}

 

 

(block/standing_rp_sign.json)

Spoiler

{
	"credit": "Made with Blockbench",
	"textures": {
		"0": "blocks/planks_oak",
		"1": "blocks/log_oak",
		"particle": "blocks/planks_oak"
	},
	"elements": [
		{
			"name": "pane",
			"from": [ 2, 6, 7.5 ],
			"to": [ 14, 12, 8.5 ],
			"faces": {
				"north": { "uv": [ 0, 0, 1, 1 ], "texture": "#0" },
				"east": { "uv": [ 0, 2, 4, 14 ], "texture": "#0" },
				"south": { "uv": [ 0, 2, 16, 14 ], "texture": "#0" },
				"west": { "uv": [ 12, 2, 16, 14 ], "texture": "#0" },
				"up": { "uv": [ 0, 0, 16, 2 ], "texture": "#0" },
				"down": { "uv": [ 0, 14, 16, 16 ], "texture": "#0" }
			}
		},
		{
			"name": "stick",
			"from": [ 7.5, 0, 7.5 ],
			"to": [ 8.5, 6, 8.5 ],
			"faces": {
				"north": { "uv": [ 0, 2, 4, 14 ], "texture": "#1" },
				"east": { "uv": [ 12, 2, 16, 14 ], "texture": "#1" },
				"south": { "uv": [ 8, 2, 12, 14 ], "texture": "#1" },
				"west": { "uv": [ 4, 2, 8, 14 ], "texture": "#1" },
				"up": { "uv": [ 0, 0, 4, 4 ], "texture": "#1" },
				"down": { "uv": [ 12, 12, 16, 16 ], "texture": "#1" }
			}
		}
	],
	"groups": [
		{
			"name": "group",
			"children": [ 0, 1 ]
		}
	]
}

 

 

I don't really understand what is going on here tbh.

Edited by Major Squirrel

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

6 hours ago, V0idWa1k3r said:

You'd need to use a TESR anyway to render the text, so...

 

I don't want to render any text on the sign, that is why I would like to avoid using TESR.
 

6 hours ago, V0idWa1k3r said:

Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270).

 

According to @diesieben07 in the link I've posted above, the TRSRTransformation rotation can achieve 22.5 degrees increments, that's why I don't really understand.

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

TRSRTransformationa can achieve any rotation

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

6 hours ago, Cadiboo said:

TRSRTransformationa can achieve any rotation

Yes, but look at my comment:

14 hours ago, V0idWa1k3r said:

Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270).

https://minecraft.gamepedia.com/Model#Block_states

 

If you want to acheive a 22.5 increment then you would need to either use a custom IBakedModel or i think you can use a transform key

https://gist.github.com/RainWarrior/0618131f51b8d37b80a6#file-forge-blockstate-v1-specs-L58

Link to comment
Share on other sites

43 minutes ago, V0idWa1k3r said:

Yes, but look at my comment:

14 hours ago, V0idWa1k3r said:

Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270).

https://minecraft.gamepedia.com/Model#Block_states

 

This is why I use the Forge blockstate format, with Forge marker set as 1.
 

43 minutes ago, V0idWa1k3r said:

or i think you can use a transform key

 

Well this is exactly what I did in my blockstates file :
 

{
	"forge_marker": 1,
	"defaults": {
		"model": "mymod:standing_rp_sign",
		"uvlock": true
	},
	"variants": {
		"rotation": {
			"0": {
				"transform": { "rotation": { "y": 180 } }
			},
			"1": {
				"transform": { "rotation": { "y": 157.5 } }
			},
			"2": {
				"transform": { "rotation": { "y": 135 } }
			},
			"3": {
				"transform": { "rotation": { "y": 112.5 } }
			},
			"4": {
				"transform": { "rotation": { "y": 90 } }
			},
			"5": {
				"transform": { "rotation": { "y": 67.5 } }
			},
			"6": {
				"transform": { "rotation": { "y": 45 } }
			},
			"7": {
				"transform": { "rotation": { "y": 22.5 } }
			},
			"8": {
				"transform": { "rotation": { "y": 0 } }
			},
			"9": {
				"transform": { "rotation": { "y": 337.5 } }
			},
			"10": {
				"transform": { "rotation": { "y": 315 } }
			},
			"11": {
				"transform": { "rotation": { "y": 292.5 } }
			},
			"12": {
				"transform": { "rotation": { "y": 270 } }
			},
			"13": {
				"transform": { "rotation": { "y": 247.5 } }
			},
			"14": {
				"transform": { "rotation": { "y": 225 } }
			},
			"15": {
				"transform": { "rotation": { "y": 202.5 } }
			}
		}
    }
}

 

Following output :

image.png.2ea5c1a1112098e4d39386ec290c804d.png

Edited by Major Squirrel

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

Good evening,

According to some modders on Discord, the only way to use 22.5° degrees rotations properly in blockstates files would be to use OBJ models.

Another solution would be to create 4 models with different rotations and to handle 4 different states per model in blockstates files so that it would handle the 16 rotations (see also this topic).

 

Thank you for helping me !

Squirrel ! Squirrel ! Squirrel !

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.