Jump to content
  • Home
  • Files
  • Docs
Topics
  • All Content

  • This Topic
  • This Forum

  • Advanced Search
  • Existing user? Sign In  

    Sign In



    • Not recommended on shared computers


    • Forgot your password?

  • Sign Up
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.12.2] MissingVariantException when making a custom sign with TESR
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 1
Major Squirrel

[1.12.2] MissingVariantException when making a custom sign with TESR

By Major Squirrel, May 14, 2019 in Modder Support

  • Reply to this topic
  • Start new topic

Recommended Posts

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 14, 2019

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.

 

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

V0idWa1k3r    391

V0idWa1k3r

V0idWa1k3r    391

  • World Shaper
  • V0idWa1k3r
  • Members
  • 391
  • 1773 posts
Posted May 14, 2019
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
  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 14, 2019

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.

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

V0idWa1k3r    391

V0idWa1k3r

V0idWa1k3r    391

  • World Shaper
  • V0idWa1k3r
  • Members
  • 391
  • 1773 posts
Posted May 14, 2019
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

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 14, 2019

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 ?
 

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

V0idWa1k3r    391

V0idWa1k3r

V0idWa1k3r    391

  • World Shaper
  • V0idWa1k3r
  • Members
  • 391
  • 1773 posts
Posted May 14, 2019
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

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 14, 2019 (edited)
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:

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

 

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 May 14, 2019 by Major Squirrel
  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

desht    91

desht

desht    91

  • Creeper Killer
  • desht
  • Members
  • 91
  • 244 posts
Posted May 15, 2019

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) ?

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 15, 2019
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 ?

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

desht    91

desht

desht    91

  • Creeper Killer
  • desht
  • Members
  • 91
  • 244 posts
Posted May 15, 2019
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.

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 15, 2019 (edited)
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 May 15, 2019 by Major Squirrel
  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

V0idWa1k3r    391

V0idWa1k3r

V0idWa1k3r    391

  • World Shaper
  • V0idWa1k3r
  • Members
  • 391
  • 1773 posts
Posted May 15, 2019

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

 

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

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 16, 2019
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.

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

Cadiboo    365

Cadiboo

Cadiboo    365

  • Reality Controller
  • Cadiboo
  • Members
  • 365
  • 3624 posts
Posted May 16, 2019

TRSRTransformationa can achieve any rotation

  • Quote

About Me

Spoiler

My Discord - Cadiboo#8887

My Website - Cadiboo.github.io

My Mods - Cadiboo.github.io/projects

My Tutorials - Cadiboo.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)

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 16, 2019
2 hours ago, Cadiboo said:

TRSRTransformationa can achieve any rotation

 

Well I don’t understand the behavior shown on my screenshot above. Did I do something wrong in my blockstate file ? I can’t figure out.

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

V0idWa1k3r    391

V0idWa1k3r

V0idWa1k3r    391

  • World Shaper
  • V0idWa1k3r
  • Members
  • 391
  • 1773 posts
Posted May 16, 2019
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

  • Quote

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 16, 2019 (edited)
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 May 16, 2019 by Major Squirrel
  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
Share on other sites

Major Squirrel    2

Major Squirrel

Major Squirrel    2

  • Creeper Killer
  • Major Squirrel
  • Members
  • 2
  • 117 posts
Posted May 21, 2019

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 !

  • Quote

Squirrel ! Squirrel ! Squirrel !

Share this post


Link to post
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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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.

    • Insert image from URL
×
  • Desktop
  • Tablet
  • Phone
Sign in to follow this  
Followers 1
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • diesieben07
      [1.16.4] Creating Sub items through NBT from config

      By diesieben07 · Posted 1 minute ago

      Don't just blindly do it in fillitemGroup either. You probably want to do it in FMLCommonSetupEvent.
    • BeardlessBrady
      [1.16.4] Creating Sub items through NBT from config

      By BeardlessBrady · Posted 5 minutes ago

      Alright, I will abstain from doing any config stuff in the constructor.
    • diesieben07
      [1.16.4] Creating Sub items through NBT from config

      By diesieben07 · Posted 7 minutes ago

      Which you do in fillItemGroup. You are doing stuff in the Item constructor.
    • BeardlessBrady
      [1.16.4] Creating Sub items through NBT from config

      By BeardlessBrady · Posted 8 minutes ago

      To make them appear in the creative menu?
    • diesieben07
      [1.16.4] Creating Sub items through NBT from config

      By diesieben07 · Posted 8 minutes ago

      Sub items are fine, I don't know why you need to initialize them that early.
  • Topics

    • BeardlessBrady
      7
      [1.16.4] Creating Sub items through NBT from config

      By BeardlessBrady
      Started 27 minutes ago

    • Aviator737
      1
      [1.16] Large collision box is not working correctly

      By Aviator737
      Started 29 minutes ago

    • Hubmac
      3
      The item given to the player disappears

      By Hubmac
      Started 1 hour ago

    • Seika85
      0
      [1.16.5-forge-36.0.43] Error: "Failed to synchronize registry data, closing connection"

      By Seika85
      Started 30 minutes ago

    • Deadlocked47
      0
      Can't get into forge discord

      By Deadlocked47
      Started 39 minutes ago

  • Who's Online (See full list)

    • Kaiser Frederick
    • Remay_0
    • Remay
    • diesieben07
    • NullDev
    • Aviator737
    • BeardlessBrady
    • Seika85
    • Hubmac
    • Deadlocked47
    • JackRaidenPH
    • loordgek
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.12.2] MissingVariantException when making a custom sign with TESR
  • Theme

Copyright © 2019 ForgeDevelopment LLC · Ads by Longitude Ads LLC Powered by Invision Community