Major Squirrel Posted May 14, 2019 Posted May 14, 2019 Good evening, I'm modding a custom sign which is translucent and smaller than the Vanilla's one. Reveal hidden contents 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) Reveal hidden contents 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) Reveal hidden contents 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) Reveal hidden contents 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) Reveal hidden contents 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) Reveal hidden contents @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) Reveal hidden contents @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) Reveal hidden contents @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) Reveal hidden contents 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 !
V0idWa1k3r Posted May 14, 2019 Posted May 14, 2019 On 5/14/2019 at 3:57 PM, Major Squirrel said: I haven't created any blockstate file for both standing and wall signs Expand On 5/14/2019 at 3:57 PM, Major Squirrel said: I'm getting a net.minecraft.client.renderer.block.model.ModelBlockDefinition$MissingVariantException Expand 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. On 5/14/2019 at 3:57 PM, 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. Expand 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. On 5/14/2019 at 3:57 PM, 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. Expand 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. On 5/14/2019 at 3:57 PM, 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 ? Expand That's fine. Your code is an insane mess though: On 5/14/2019 at 3:57 PM, Major Squirrel said: return (null); Expand 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. On 5/14/2019 at 3:57 PM, Major Squirrel said: protected BlockRPSign() Expand 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. On 5/14/2019 at 3:57 PM, Major Squirrel said: extends BlockContainer Expand Don't. There is no need to extend BlockContainer, just extend Block and override Block#createTileEntity and Block#hasTileEntity. On 5/14/2019 at 3:57 PM, Major Squirrel said: if (!worldIn.isRemote) { Minecraft.getMinecraft().displayGuiScreen(new GuiRolePlayScreen()); Expand 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. On 5/14/2019 at 3:57 PM, Major Squirrel said: Integer.valueOf(0) Expand On 5/14/2019 at 3:57 PM, Major Squirrel said: Integer.valueOf(meta) Expand ...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. On 5/14/2019 at 3:57 PM, Major Squirrel said: Integer.valueOf(rot.rotate(((Integer)state.getValue(ROTATION)).intValue(), 16))) Expand 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. On 5/14/2019 at 3:57 PM, Major Squirrel said: new IProperty[] {ROTATION} Expand There is no need to explicitly create a new array here. The input variable is a params one already(... modifier). On 5/14/2019 at 3:57 PM, Major Squirrel said: @SubscribeEvent @SideOnly(Side.CLIENT) Expand Don't abuse SideOnly. Have dedicated client-side only event handlers. On 5/14/2019 at 3:57 PM, Major Squirrel said: if ("standing_rp_sign".equals(block.getUnlocalizedName().substring(5))) { Expand Dear lord, why? Just compare the block you have to the constant you have in the MyModBlocks. Don't ever do stuff like this. On 5/14/2019 at 3:57 PM, Major Squirrel said: int k = te.getBlockMetadata(); Expand 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. 1 Quote
Major Squirrel Posted May 14, 2019 Author Posted May 14, 2019 Good evening, Thank you @V0idWa1k3r for your answer. On 5/14/2019 at 4:25 PM, 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. Expand 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. On 5/14/2019 at 4:25 PM, V0idWa1k3r said: Use forge's method(EntityPlayer#openGui) to opeen GUI's. Expand 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 !
V0idWa1k3r Posted May 14, 2019 Posted May 14, 2019 On 5/14/2019 at 9:25 PM, 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. Expand In that case use a proxy. You can't reference client-only classes(Minecraft, Gui) in common code anyways Quote
Major Squirrel Posted May 14, 2019 Author Posted May 14, 2019 I've added "empty" blockstate files and model files like so : (blockstates/standing_rp_sign.json) Reveal hidden contents { "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) Reveal hidden contents { "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) Reveal hidden contents { "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. On 5/14/2019 at 10:15 PM, V0idWa1k3r said: In that case use a proxy. You can't reference client-only classes(Minecraft, Gui) in common code anyways Expand What do you mean by proxy ? Sending a packet to the server and the server opens a player GUI ? Quote Squirrel ! Squirrel ! Squirrel !
V0idWa1k3r Posted May 14, 2019 Posted May 14, 2019 On 5/14/2019 at 10:56 PM, Major Squirrel said: Instead, I've made my class extend to Block, implementing ITileEntityProvider. It works now. Expand Don't do that either. That class is legacy code that won't work properly. Show your code(without extending ITileEntityProvider) On 5/14/2019 at 10:56 PM, Major Squirrel said: What do you mean by proxy ? Sending a packet to the server and the server opens a player GUI ? Expand https://mcforge.readthedocs.io/en/latest/concepts/sides/#sidedproxy Quote
Major Squirrel Posted May 14, 2019 Author Posted May 14, 2019 (edited) On 5/14/2019 at 10:59 PM, V0idWa1k3r said: Show your code(without extending ITileEntityProvider) Expand (BlockRPSign.java) Reveal hidden contents 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. On 5/14/2019 at 10:59 PM, V0idWa1k3r said: https://mcforge.readthedocs.io/en/latest/concepts/sides/#sidedproxy Expand 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 !
desht Posted May 15, 2019 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
Major Squirrel Posted May 15, 2019 Author Posted May 15, 2019 On 5/15/2019 at 11:16 AM, 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) ? Expand 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 !
desht Posted May 15, 2019 Posted May 15, 2019 On 5/15/2019 at 1:28 PM, 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 ? Expand 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
Major Squirrel Posted May 15, 2019 Author Posted May 15, 2019 (edited) On 5/15/2019 at 1:47 PM, 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. Expand 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 : Reveal hidden contents The original model for the block (the uniform face is purposely complete beige so I could see where it faces) : Reveal hidden contents (blockstates/standing_rp_sign.json) Reveal hidden contents { "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) Reveal hidden contents { "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 !
V0idWa1k3r Posted May 15, 2019 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
Major Squirrel Posted May 16, 2019 Author Posted May 16, 2019 On 5/15/2019 at 11:50 PM, V0idWa1k3r said: You'd need to use a TESR anyway to render the text, so... Expand I don't want to render any text on the sign, that is why I would like to avoid using TESR. On 5/15/2019 at 11:50 PM, V0idWa1k3r said: Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270). Expand 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 !
Cadiboo Posted May 16, 2019 Posted May 16, 2019 TRSRTransformationa can achieve any rotation Quote About Me Reveal hidden contents 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)
Major Squirrel Posted May 16, 2019 Author Posted May 16, 2019 On 5/16/2019 at 7:26 AM, Cadiboo said: TRSRTransformationa can achieve any rotation Expand 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 !
V0idWa1k3r Posted May 16, 2019 Posted May 16, 2019 On 5/16/2019 at 7:26 AM, Cadiboo said: TRSRTransformationa can achieve any rotation Expand Yes, but look at my comment: On 5/15/2019 at 11:50 PM, V0idWa1k3r said: Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270). Expand 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
Major Squirrel Posted May 16, 2019 Author Posted May 16, 2019 (edited) On 5/16/2019 at 1:53 PM, V0idWa1k3r said: Yes, but look at my comment: On 5/15/2019 at 11:50 PM, V0idWa1k3r said: Rotation in the blockstates file can only be done by 90 degrees(0, 90, 180, 270). Expand https://minecraft.gamepedia.com/Model#Block_states Expand This is why I use the Forge blockstate format, with Forge marker set as 1. On 5/16/2019 at 1:53 PM, V0idWa1k3r said: or i think you can use a transform key Expand 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 : Edited May 16, 2019 by Major Squirrel Quote Squirrel ! Squirrel ! Squirrel !
Major Squirrel Posted May 21, 2019 Author 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 !
Recommended Posts
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.