Jump to content

SuperGeniusZeb

Forge Modder
  • Posts

    70
  • Joined

  • Last visited

Everything posted by SuperGeniusZeb

  1. Well, you can't do either, so I guess the answer to your question is... yes? Your first example resembles the vanilla format, but that format is rather difficult-to-read/messy-looking, hence my use of a "conditions" group to make things more structured and organized. I'm not sure its the best solution to the problem, though. The problem with the current Forge blockstates format is that you can't have a model/texture applied based on if 2 or more conditions are true. Changes can only be applied on a single-condition basis. This is where the vanilla format has an advantage over the Forge format. (Though the way it handles it is somewhat clunky.)
  2. In my previous topic, I discovered that the Forge blockstates format still doesn't support models like stairs, mainly due to the fact that multiple-condition-tests are not possible. (They're possible in the vanilla format.) See my previous topic here: http://www.minecraftforge.net/forum/index.php?topic=43581.0 And so, I decided to try and fix the problem with a new blockstates format. Here is my first draft/concept: { //This format is intended to be capable of everything the current format is capable of, as well as what the vanilla format can currently do that the Forge format cannot "forge_marker": 2, "defaults": { //Required (as opposed to optional in the current Forge format) because "variants" system does not force every possible combination of values to be defined "model": "mymod:model1", "textures": { "texture1": "mymod:block/texture_name", "texture2": "mymod:block/another_texture", "a_submodel_texture": "mymod:block/default_texture_for_a_submodel_if_present" }, "uvlock": false }, "variants": [ //Optional { "conditions": { //Allows for checking multiple conditions, which is necessary for things like STAIRS to be possible without using the vanilla format "property1": "this_value", //value can be string, int, or bool, depending on the property's type "property2": "this_other_value" }, "model": "mymod:model2", //replaces default model "textures": { "texture1": "mymod:block/texture_name", "texture2": "mymod:block/another_texture" }, "x": 90 }, { //Condition-sets are tested and variations are applied in sequence/order, so the sets defined last have highest priority and can override previous values "conditions": { "property1": "this_value", "property3": true }, "submodel": "mymod:model2", //is added to existing model, like in current Forge blockstate format "textures": { "example_texture_param": "mymod:block/texture_name" }, "y": 180, "uvlock": true }, { //Since this condition/model-set is defined last, and can override anything set by the previous sets, like the main model's x-rotation' "conditions": { "property4": "another_value" }, "submodel": { //Demonstration of multiple submodels "a_submodel_name": { "model": "mymod:the_model_used_by_the_submodel", "x": 180 } }, "textures": { "texture2": "mymod:block/placeholder_texture_name", "submodel_texture:": "mymod:block/texture_used_by_submodel" }, "x": 270, "uvlock": true } ] } I am almost certain I've made some mistake or overlooked something important (and even if I haven't, I'd like to make sure), so that's why I'm posting it here to get some feedback. What do you think should be improved/changed? Would this be possible to actually implement into Forge, or is there some internal code limitation I'm not aware of? Please let me know what you think so I can revise this conceptual format as needed. My goal was to make a format that does everything the current Forge blockstates format does, as well as everything the vanilla format is capable of that the Forge format is not. I've based this format off of the current Forge blockstates format, which you can see in the official Forge docs, as well as the vanilla format, which you can see an example of by looking through the vanilla assets and opening the stairs and fence blockstate files, which give examples of the "variants" & "multipart" system that vanilla uses in its blockstates format. Thank you ahead of time for your help & feedback!
  3. Awww. I was hoping there had been some change/addition to the format in 1.10/1.11... I guess it's time to try and think of a better/improved format and post it here to take suggestions, then. (Maybe this is why vanilla still uses its current format and didn't switch to something like the Forge on...)
  4. You mean like... http://mcforge.readthedocs.io/en/latest/blockstates/forgeBlockstates/#sub-models ? The "submodels" part of that section not being the relevant part, look at mossy and pillarcount. I'm well-aware of the submodels system. (See my previous discussion linked in the main post.) But it's not enough for stairs. To see what I mean, just TRY and make stairs using the Forge blockstate format. You can divide the stairs into submodels, but it won't be enough to handle all the possible rotations and shapes the stairs can have. You'll run into rotation problems pretty quickly.
  5. So a little while back I was trying to make custom stairs using the Forge blockstate JSON format. (See: http://www.minecraftforge.net/forum/index.php?topic=39104 ) I concluded that it must be impossible to do so, and resorted to using the vanilla format. So my question is... is it possible now? Is there any way to define a block like stairs in the Forge blockstate format? The key problem seems to be that the vanilla format supports multiple conditions per model, like "facing=east,half=bottom,shape=straight" being one example. I can't find a way to do this with the Forge format... but this is required for a model like stairs. It also seems that you can't rotate a model more than 2 times, and rotation of an axis cannot be handled by 2 different properties simultaneously. Is there a way to do this now? It's been a while, and I would expect the Forge blockstate format to be capable of anything that the vanilla format can do. Has there been any discussion on this, or is this even known about?
  6. See title. Specifically, I want to be able to override just 1 method in BlockPistonStructureHelper... addBlockLine() to be specific. I'm trying to increase the piston push limit from 12 to 16, and having taken a look at the vanilla code, I can see that it's literally a 2-line change to do it. I am well aware that coremodding is by far no easy task (especially for someone with as little experience as myself), and is one of the most complex and hated aspects of modding. But I want to try anyway and hopefully learn something and gain some experience, even if I fail. Where do I start, and also, what are the alternatives to using a coremod? I know Forge replaces vanilla buckets with custom ones, but I'm not sure how I would do something like that and ensure compatiblity with mods requiring pistons in recipes and stuff like that, or how difficult it would be in comparison to coremodding.
  7. Thanks for the helpful link and explanation, Choonster! I understand the format a whole lot better now.
  8. I was able to get it working and have a rough idea of how to do it now, but I still don't quite understand. (I have no prior experience with Maven.) Should I organize all the mods into folders based off of their actual repository formats or can I make up my own organization? In the example, how does it know that "universal" refers to the "ironchest-6.1.10-universal.jar" file? How exactly does a Maven-style locator work? I'm also curious as to why the mod_list.json uses this format and what the advantages are. Basically, I've got it working, but I don't know why or how it works.
  9. I've already read that. That's how I knew how to format the mod_list.json in the first place. But thanks anyway. Ok, I changed the mod_list.json, and here is what it looks like, complete with all the mods I have listed: And now Forge just crashes when I try to start the game. Here's what the launcher logs say: I'm not sure why it seems to think I'm running Windows 8.1. (Is it just a minor bug with Forge, the new launcher, or what?) Also, in case you're wondering what's up with the .minecraft folder, I actually have a symbolic link in the normal location where the .minecraft folder would be. The symlink links to the actual location of my .minecraft folder, which is in my Dropbox, so I can use the same Minecraft installation on other computers or on my Ubuntu partition. (Also in case my laptop dies, so I don't have to worry about losing my worlds.) I'm not sure if I'm doing something wrong, if it is a bug with Forge, or if it is a problem with the new launcher & Forge. Also, no, my username is not literally [uSERNAME].
  10. I've placed all my mods in a central location, and I'm trying to load them using a mod_list.json in ".minecraft/mods/1.10.2". I'm not sure how to specify an absolute path, though. I tried doing what the Github page said, and my .json looks like: { "repositoryRoot": "absolute:C:/Users/[MY-USERNAME]/Documents/Minecraft/Mods/1.10.2", "modRef": [ //lots of mods here ], "parentList": "" } When I start up the game, however, none of the mods load. The launcher logs say: Possibly relevant: I'm using the latest version of the new beta native Minecraft launcher, using the latest version of Forge for 1.10.2, and I'm running Windows 10 64-bit. Do you have to type the absolute path differently? Or is the mod_list.json thing just broken with the new launcher?
  11. In addition to what pWn3d said, keep in mind that even 1.8 mods will usually not work with 1.8.9, and likewise many 1.9 mods don't work with 1.9.4. A lot of 1.9.4 mods DO work with 1.10.2, though. This is a relatively rare case, though, as not many internal changes affecting mods were made between the 2 versions in either Minecraft or Forge. 1.11 is expected to have several changes which will probably affect at least several mods, causing at least some, if not complete incompatibility with 1.9.4 and/or 1.10.2 mods.
  12. The current up-to-date version of the mod with all the latest features (1.2) is available for Minecraft 1.10 & 1.9.4. The previous version of the mod (1.1) was made for MC 1.8.9 and 1.9, and the original 1.0.0 version of the mod was made for Minecraft 1.8. You can see a changelog on the mod's page on my website. http://supergeniuszeb.com/project/colore/
  13. Are you sure that registerSounds() is being called in the proxies? Forgetting to actually call registration methods has tripped me up before in the past.
  14. Forge for 1.10 came out, and now Colore 1.2 for MC1.10 has come out too! There's no new features in this update... it's literally identical to the 1.9.4 version except for the version number. So enjoy playing the mod on 1.10!
  15. The Pocket Edition devs have been working on this:
  16. The new parameters (equip sound and armor toughness) are exactly what's causing your problem. (The ArmorMaterial constructors were broken in Forge 1.9 because they didn't have the new parameters which were added in 1.9 and 1.9.2, but this was fixed in Forge 1.9.4.) Just use one of the armor equip sounds (or the generic one, ITEM_ARMOR_EQUIP_GENERIC, or a custom sound, or just null for no sound) and add in a 0.0F for the toughness parameter. (Unless, of course, you want your custom armor to have extra toughness.) Not really much to discuss here.
  17. My signature has a link to some pretty helpful resources I've found over time, and in addition to those, I've recently discovered these tutorials by Darkhax, which contain some good information about some less-commonly discussed modding aspects like loot tables.
  18. The 1.2 update has been released for Minecraft 1.9.4! In this update, I've added a crazy total of 700 blocks, ranging from stairs to fences to transparent blocks and more! I've also rebalanced the tools & armor for 1.9, so they're not too OP anymore. I'm probably going to take a break from adding stuff to this mod for a while and start working on something else, but in the future I plan on adding bows, shields, transparent tools & armor, and fluids. I might also backport this update to 1.9, but with 1.10 now out and with most mods having already moved to 1.9.4 and skipping that version, I probably won't bother, but we'll see.
  19. I did another run-through of my stair-rendering logic and optimized it some more, combining several if-statements with &&, abstracting others that applied to multiple shapes, and removing unnecessary if-statements. I also made the stair-side-rendering work properly with the other stairs so that sides will render if the color & shade of the stairs don't match. Hopefully this code will benefit other people trying to make translucent stairs. package com.supergeniuszeb.colore.utility; import com.supergeniuszeb.colore.common.blocks.BlockColore; import com.supergeniuszeb.colore.common.blocks.BlockColoreSlab; import com.supergeniuszeb.colore.common.blocks.BlockColoreStairs; import com.supergeniuszeb.colore.common.blocks.BlockColoreTrans; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabDouble; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabHalf; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransStairs; import com.supergeniuszeb.colore.common.blocks.EnumShade; import com.supergeniuszeb.colore.common.blocks.IColorMatcher; import net.minecraft.block.BlockSlab.EnumBlockHalf; import net.minecraft.block.BlockStairs.EnumHalf; import net.minecraft.block.BlockStairs.EnumShape; import net.minecraft.block.state.IBlockState; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; public class StairsSideRenderLogic implements IColorMatcher { //Used to get the side of a stairs relative to its FACING property. //Also used to get the FACING of an adjacent stairs relative to the block it is adjacent to. public static EnumFacing getRelativeFacing(EnumFacing facing1, EnumFacing facing2) { if (facing2.getAxis() == Axis.X || facing2.getAxis() == Axis.Z) { if (facing1 == EnumFacing.EAST) { return facing2.rotateYCCW(); } if (facing1 == EnumFacing.SOUTH) { return facing2.getOpposite(); } if (facing1 == EnumFacing.WEST) { return facing2.rotateY(); } } return facing2; } //Logic method that decides whether or not to render a side of a stairs block depending on //what block is adjacent to it and what their blockstates are. public static boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { IBlockState adjBlockState = blockAccess.getBlockState(pos.offset(side)).getActualState(blockAccess, pos.offset(side)); EnumFacing blockFacing = blockState.getValue(BlockColoreStairs.FACING); EnumFacing blockRelativeSide = getRelativeFacing(blockFacing, side); EnumHalf blockHalf = blockState.getValue(BlockColoreTransStairs.HALF); EnumShape blockShape = blockState.getValue(BlockColoreTransStairs.SHAPE); if (doShadeAndColorMatch(blockState, adjBlockState)) { if (adjBlockState.getBlock() instanceof BlockColoreTransStairs) { EnumFacing adjBlockRelativeFacing = getRelativeFacing(blockFacing, adjBlockState.getValue(BlockColoreTransStairs.FACING)); EnumHalf adjBlockHalf = adjBlockState.getValue(BlockColoreTransStairs.HALF); EnumShape adjBlockShape = adjBlockState.getValue(BlockColoreTransStairs.SHAPE); if (side == EnumFacing.UP) { if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM) { return false; } if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP && blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } if (side == EnumFacing.DOWN) { if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP) { return false; } if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM && blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } for (EnumFacing facing : EnumFacing.HORIZONTALS) { if (blockRelativeSide == facing) { if (adjBlockRelativeFacing == facing.rotateY() && adjBlockShape == EnumShape.INNER_RIGHT) { return false; } if (adjBlockRelativeFacing == facing.getOpposite() && (adjBlockShape == EnumShape.STRAIGHT || adjBlockShape == EnumShape.INNER_LEFT || adjBlockShape == EnumShape.INNER_RIGHT)) { return false; } if (adjBlockRelativeFacing == facing.rotateYCCW() && adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockHalf == adjBlockHalf) { if (blockRelativeSide == EnumFacing.SOUTH && adjBlockRelativeFacing == EnumFacing.SOUTH) { return false; } if (blockShape == EnumShape.STRAIGHT) { if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST && adjBlockShape == EnumShape.INNER_LEFT) { return false; } if (adjBlockRelativeFacing == EnumFacing.WEST && adjBlockShape == EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST && adjBlockShape == EnumShape.OUTER_LEFT) { return false; } if (adjBlockRelativeFacing == EnumFacing.WEST && adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockShape == EnumShape.INNER_LEFT) { if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST && adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (blockRelativeSide == EnumFacing.SOUTH && adjBlockShape != EnumShape.OUTER_LEFT) { return false; } } if (blockShape == EnumShape.INNER_RIGHT) { if (blockRelativeSide == EnumFacing.SOUTH && adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.WEST && adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockShape == EnumShape.OUTER_LEFT) { if (blockRelativeSide == EnumFacing.NORTH && adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } if (blockRelativeSide == EnumFacing.EAST || blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST && adjBlockShape == EnumShape.OUTER_LEFT) { return false; } if (adjBlockRelativeFacing == EnumFacing.WEST && adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockShape == EnumShape.OUTER_RIGHT) { if (blockRelativeSide == EnumFacing.NORTH && adjBlockShape != EnumShape.OUTER_LEFT) { return false; } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST && adjBlockShape == EnumShape.INNER_LEFT) { return false; } if (adjBlockRelativeFacing == EnumFacing.WEST && adjBlockShape == EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.SOUTH || blockRelativeSide == EnumFacing.WEST) { return false; } } } } if (adjBlockState.getBlock() instanceof BlockColoreTrans || adjBlockState.getBlock() instanceof BlockColoreTransSlabDouble) { return false; } if (adjBlockState.getBlock() instanceof BlockColoreTransSlabHalf) { if ((side == EnumFacing.UP && adjBlockState.getValue(BlockColoreSlab.HALF) == EnumBlockHalf.BOTTOM) || (side == EnumFacing.DOWN && adjBlockState.getValue(BlockColoreSlab.HALF) == EnumBlockHalf.TOP)) { return false; } if ((blockHalf == EnumHalf.BOTTOM && adjBlockState.getValue(BlockColoreSlab.HALF) == EnumBlockHalf.BOTTOM) || (blockHalf == EnumHalf.TOP && adjBlockState.getValue(BlockColoreSlab.HALF) == EnumBlockHalf.TOP)) { if (blockShape != EnumShape.INNER_LEFT && blockShape != EnumShape.INNER_RIGHT && blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockShape == EnumShape.OUTER_LEFT && blockRelativeSide == EnumFacing.EAST) { return false; } if (blockShape == EnumShape.OUTER_RIGHT && blockRelativeSide == EnumFacing.WEST) { return false; } } } } return true; } //Used to check if the shade & color of the stairs matches that of the adjacent normal block, half-slab, or double-slab. public static boolean doShadeAndColorMatch(IBlockState blockState, IBlockState adjBlockState) { if (IColorMatcher.isSameColor(blockState, adjBlockState)) { for (String shade : UtilityLists.shadeList) { if (adjBlockState.getBlock() instanceof BlockColoreStairs) { if (blockState.getBlock().getRegistryName().toString().contains(shade) && adjBlockState.getBlock().getRegistryName().toString().contains(shade)) { return true; } } else if (blockState.getBlock().getRegistryName().toString().contains(shade) && adjBlockState.getValue(BlockColore.SHADE) == EnumShade.valueOf(shade.toUpperCase())) { return true; } } } return false; } } Still curious if there's anything I can do to improve it even more, though. Also, there's this other problem(?) I'm having with my mod. Whenever I start up the game, I get a bunch of identical errors saying: But I can't find any problems with any of my item or block models, and they all work and look as intended. Is this a Forge bug or am I doing something wrong? EDIT: Updated the code above again - simplified the functions used to convert an EnumFacing to one relative to the stairs being rendered.
  20. Thanks, that's a very useful description. Given that context, it makes sense why a lot of methods that take an IBlockAccess as a parameter call the parameter "world".
  21. Thanks! Changing my code to get the actual-state fixed the problem! The stairs now render entirely as intended. It actually makes a lot of sense that since IBlockAccess is implemented and used by World, you wouldn't be able to directly get the full blockstate of a block from it, since the actual/extended state isn't saved to the world. (While fixing it I also discovered another minor unrelated problem where I accidentally mis-nested some of the if statements, which I've fixed now.) Abastro, could you explain how I could use for loops and maps to make the code cleaner? I'm not sure what you mean. As for optimizing the logic, I've already made it relative to the orientation of the stairs being rendered, which has reduced the size of the logic to be 4x smaller than what it would be otherwise. (A north-facing stairs with an east-facing stairs on its east side = an east-facing stairs with a south-facing stairs on its south side.) If you take a look at the code you'll see I check for the most general cases (like bottom-half-stairs on top of top-half stairs) which should always return false before I check for more specific cases that are more difficult to determine, and I don't think there are any redundant checks left in the logic that could be abstracted, but correct me if I'm wrong. The updated StairsSideRenderLogic.java package com.supergeniuszeb.colore.utility; import com.supergeniuszeb.colore.common.blocks.BlockColore; import com.supergeniuszeb.colore.common.blocks.BlockColoreStairs; import com.supergeniuszeb.colore.common.blocks.BlockColoreTrans; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabDouble; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabHalf; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransStairs; import com.supergeniuszeb.colore.common.blocks.EnumShade; import com.supergeniuszeb.colore.common.blocks.IColorMatcher; import net.minecraft.block.BlockSlab.EnumBlockHalf; import net.minecraft.block.BlockStairs.EnumHalf; import net.minecraft.block.BlockStairs.EnumShape; import net.minecraft.block.state.IBlockState; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraftforge.common.property.IExtendedBlockState; public class StairsSideRenderLogic implements IColorMatcher { //Used to get the side of a stairs relative to its FACING property. public static EnumFacing getRelativeSide(EnumFacing facing1, EnumFacing facing2) { if (facing1 == EnumFacing.EAST) { switch (facing2) { case NORTH: return EnumFacing.WEST; case EAST: return EnumFacing.NORTH; case SOUTH: return EnumFacing.EAST; case WEST: return EnumFacing.SOUTH; default: break; //Assuming this method is used right, this should never happen. } } if (facing1 == EnumFacing.SOUTH) { switch (facing2) { case NORTH: return EnumFacing.SOUTH; case EAST: return EnumFacing.WEST; case SOUTH: return EnumFacing.NORTH; case WEST: return EnumFacing.EAST; default: break; } } if (facing1 == EnumFacing.WEST) { switch (facing2) { case NORTH: return EnumFacing.EAST; case EAST: return EnumFacing.SOUTH; case SOUTH: return EnumFacing.WEST; case WEST: return EnumFacing.NORTH; default: break; } } return facing2; } //Used to get which way the adjacent stairs is facing, relative to the block it is adjacent to. public static EnumFacing getRelativeFacing(EnumFacing facing1, EnumFacing facing2) { if (facing1 == EnumFacing.EAST) { switch (facing2) { case NORTH: return EnumFacing.WEST; case EAST: return EnumFacing.NORTH; case SOUTH: return EnumFacing.EAST; case WEST: return EnumFacing.SOUTH; default: break; //Assuming this method is used right, this should never happen. } } if (facing1 == EnumFacing.SOUTH) { switch (facing2) { case NORTH: return EnumFacing.SOUTH; case EAST: return EnumFacing.WEST; case SOUTH: return EnumFacing.NORTH; case WEST: return EnumFacing.EAST; default: break; } } if (facing1 == EnumFacing.WEST) { switch (facing2) { case NORTH: return EnumFacing.EAST; case EAST: return EnumFacing.SOUTH; case SOUTH: return EnumFacing.WEST; case WEST: return EnumFacing.NORTH; default: break; } } return facing2; } //Logic method that decides whether or not to render a side of a stairs block depending on //what block is adjacent to it and what their blockstates are. public static boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { IBlockState adjBlockState = blockAccess.getBlockState(pos.offset(side)).getActualState(blockAccess, pos.offset(side)); if (adjBlockState.getBlock() instanceof BlockColoreTransStairs) { EnumFacing blockFacing = blockState.getValue(BlockColoreTransStairs.FACING); EnumFacing adjBlockRelativeFacing = getRelativeFacing(blockFacing, adjBlockState.getValue(BlockColoreTransStairs.FACING)); EnumFacing blockRelativeSide = getRelativeSide(blockFacing, side); EnumHalf blockHalf = blockState.getValue(BlockColoreTransStairs.HALF); EnumHalf adjBlockHalf = adjBlockState.getValue(BlockColoreTransStairs.HALF); EnumShape blockShape = blockState.getValue(BlockColoreTransStairs.SHAPE); EnumShape adjBlockShape = adjBlockState.getValue(BlockColoreTransStairs.SHAPE); if (side == EnumFacing.UP) { if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM) { return false; } if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP) { if (blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } } if (side == EnumFacing.DOWN) { if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP) { return false; } if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM) { if (blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } } for (EnumFacing facing : EnumFacing.HORIZONTALS) { if (blockRelativeSide == facing && adjBlockRelativeFacing == facing.getOpposite()) { if (adjBlockShape == EnumShape.STRAIGHT || adjBlockShape == EnumShape.INNER_LEFT || adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockHalf == adjBlockHalf) { if (blockRelativeSide == EnumFacing.SOUTH && adjBlockRelativeFacing == EnumFacing.SOUTH) { return false; } if (blockShape == EnumShape.STRAIGHT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.OUTER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.OUTER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } } if (blockShape == EnumShape.INNER_LEFT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { if (adjBlockShape != EnumShape.OUTER_LEFT) { return false; } } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } } if (blockShape == EnumShape.INNER_RIGHT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } } if (blockShape == EnumShape.OUTER_LEFT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.EAST || blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.OUTER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } } if (blockShape == EnumShape.OUTER_RIGHT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockShape != EnumShape.OUTER_LEFT) { return false; } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH || blockRelativeSide == EnumFacing.WEST) { return false; } } } } if (adjBlockState.getBlock() instanceof BlockColoreTrans || adjBlockState.getBlock() instanceof BlockColoreTransSlabDouble) { if (doShadeAndColorMatch(blockState, adjBlockState)) { return false; } } if (adjBlockState.getBlock() instanceof BlockColoreTransSlabHalf) { if ((side == EnumFacing.UP && adjBlockState.getValue(BlockColoreTransSlabHalf.HALF) == EnumBlockHalf.BOTTOM) || (side == EnumFacing.DOWN && adjBlockState.getValue(BlockColoreTransSlabHalf.HALF) == EnumBlockHalf.TOP)) { if (doShadeAndColorMatch(blockState, adjBlockState)) { return false; } } } return true; } //Used to check if the shade & color of the stairs matches that of the adjacent normal block, half-slab, or double-slab. public static boolean doShadeAndColorMatch(IBlockState blockState, IBlockState adjBlockState) { for (String shade : UtilityLists.shadeList) { if (blockState.getBlock().getRegistryName().toString().contains(shade) && adjBlockState.getValue(BlockColore.SHADE) == EnumShade.valueOf(shade.toUpperCase())) { if (IColorMatcher.isSameColor(blockState, adjBlockState)) { return true; } } } return false; } }
  22. Warning: This is kind of complex to explain, so get ready for some lengthy paragraphs and lots of code to read. I'm trying to add transparent stairs to my mod. They work flawlessly functionally, but rendering them properly has been a bit difficult. I've written the code properly to prevent x-raying and stuff like that, but the challenge I'm dealing with is determining when to render a side of a stairs. I'm basically taking the same approach as vanilla glass blocks, so that only the front textures render and you get a clear view through several stairs. Obviously, due to the many different shapes of stairs there are some combinations for which this is not possible and you are forced to render the sides, but I wanted to do as much as I could to make the transparent stairs as seamless as possible. I've written out all the logic for rendering of sides based on the orientation, shape, and half (right-side-up or upside-down) of the stairs and the stairs or other blocks adjacent to that side and their rotations, shapes, and etc. and I've checked the logic multiple times and I believe it is fully robust and perfected. However, the actual implementation of that logic is where my problem is. Below you can see all the relevant classes, with StairsSideRenderLogic being the utility class I created to keep all the rendering logic outside of the custom stairs class (for readability's sake). This is where the flaw in my code (or Forge, but I'll get to that later) shows up. Through debugging I believe I have narrowed down the core of the problem being this: trying to get the value of the SHAPE property from the stairs is not giving the expected results. I'm basically taking an IBlockAccess, getting an IBlockState from it, and trying to get the value of the SHAPE property from it. But it keeps returning either the lowest possible value (STRAIGHT) or the highest possible value (OUTER_RIGHT), which of course makes the majority of my checks in the rendering logic fail. When I try to get the values of the FACING or HALF properties of either the stairs being rendered or the adjacent block, it works without a problem. When I try to get the shape of the stairs being rendered, it works. But when I try to get the shape of the adjacent block, it never returns anything other than the aforementioned values. The only differences I can think of is that: [*]I have an IBlockState for the block whose sides are being rendered, but only an IBlockAccess for the adjacent block, and... [*]The SHAPE property is not saved to the metadata like the other 2 properties, as it is determined based on adjacent blocks. I don't have a complete understanding of what the difference between an IBlockAccess and an IBlockState is, but I have heard that the former is more limiting, which leads me to believe that an IBlockAccess doesn't know what its complete blockstate is, and only knows what is saved to metadata. If this is the case then I'm not sure what I should do in order to determine the info I need. I should also mention and clarify that all the cases for rendering that don't involve trying to get the SHAPE of the adjacent block work entirely as expected, that everything else concerning rendering works fine and the problem only involves deciding when to render the side of one of the blocks, and this problem, as stated before, does not affect trying to get the SHAPE of the block to be rendered, but only the adjacent block, which is the one I only have an IBlockAccess for. Any ideas? Here are all the classes you'd need to look at to fully understand how my stairs work. Again, StairsSideRenderLogic is the most important one as it is where the problem is, with the others included for context. As I've said before, I believe the logic for rendering is correct, but the ways in which I obtain the info used in the logic is flawed. StairsSideRenderLogic.java (the logic for rendering the sides of stairs.) package com.supergeniuszeb.colore.utility; import com.supergeniuszeb.colore.common.blocks.BlockColore; import com.supergeniuszeb.colore.common.blocks.BlockColoreStairs; import com.supergeniuszeb.colore.common.blocks.BlockColoreTrans; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabDouble; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransSlabHalf; import com.supergeniuszeb.colore.common.blocks.BlockColoreTransStairs; import com.supergeniuszeb.colore.common.blocks.EnumShade; import com.supergeniuszeb.colore.common.blocks.IColorMatcher; import net.minecraft.block.BlockSlab.EnumBlockHalf; import net.minecraft.block.BlockStairs.EnumHalf; import net.minecraft.block.BlockStairs.EnumShape; import net.minecraft.block.state.IBlockState; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; public class StairsSideRenderLogic implements IColorMatcher { //Used to get the side of a stairs relative to its FACING property. public static EnumFacing getRelativeSide(EnumFacing facing1, EnumFacing facing2) { if (facing1 == EnumFacing.EAST) { switch (facing2) { case NORTH: return EnumFacing.WEST; case EAST: return EnumFacing.NORTH; case SOUTH: return EnumFacing.EAST; case WEST: return EnumFacing.SOUTH; default: break; //Assuming this method is used right, this should never happen. } } if (facing1 == EnumFacing.SOUTH) { switch (facing2) { case NORTH: return EnumFacing.SOUTH; case EAST: return EnumFacing.WEST; case SOUTH: return EnumFacing.NORTH; case WEST: return EnumFacing.EAST; default: break; } } if (facing1 == EnumFacing.WEST) { switch (facing2) { case NORTH: return EnumFacing.EAST; case EAST: return EnumFacing.SOUTH; case SOUTH: return EnumFacing.WEST; case WEST: return EnumFacing.NORTH; default: break; } } return facing2; } //Used to get which way the adjacent stairs is facing, relative to the block it is adjacent to. public static EnumFacing getRelativeFacing(EnumFacing facing1, EnumFacing facing2) { if (facing1 == EnumFacing.EAST) { switch (facing2) { case NORTH: return EnumFacing.WEST; case EAST: return EnumFacing.NORTH; case SOUTH: return EnumFacing.EAST; case WEST: return EnumFacing.SOUTH; default: break; //Assuming this method is used right, this should never happen. } } if (facing1 == EnumFacing.SOUTH) { switch (facing2) { case NORTH: return EnumFacing.SOUTH; case EAST: return EnumFacing.EAST; case SOUTH: return EnumFacing.NORTH; case WEST: return EnumFacing.WEST; default: break; } } if (facing1 == EnumFacing.WEST) { switch (facing2) { case NORTH: return EnumFacing.EAST; case EAST: return EnumFacing.SOUTH; case SOUTH: return EnumFacing.WEST; case WEST: return EnumFacing.NORTH; default: break; } } return facing2; } //Logic method that decides whether or not to render a side of a stairs block depending on //what block is adjacent to it and what their blockstates are. public static boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { IBlockState adjBlockState = blockAccess.getBlockState(pos.offset(side)); if (adjBlockState.getBlock() instanceof BlockColoreTransStairs) { EnumFacing blockFacing = blockState.getValue(BlockColoreTransStairs.FACING); EnumFacing adjBlockRelativeFacing = getRelativeFacing(blockFacing, adjBlockState.getValue(BlockColoreTransStairs.FACING)); EnumFacing blockRelativeSide = getRelativeSide(blockFacing, side); EnumHalf blockHalf = blockState.getValue(BlockColoreTransStairs.HALF); EnumHalf adjBlockHalf = adjBlockState.getValue(BlockColoreTransStairs.HALF); EnumShape blockShape = blockState.getValue(BlockColoreTransStairs.SHAPE); EnumShape adjBlockShape = adjBlockState.getValue(BlockColoreTransStairs.SHAPE); System.out.println(adjBlockShape); if (side == EnumFacing.UP) { if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM) { return false; } if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP) { if (blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } } if (side == EnumFacing.DOWN) { if (blockHalf == EnumHalf.BOTTOM && adjBlockHalf == EnumHalf.TOP) { return false; } if (blockHalf == EnumHalf.TOP && adjBlockHalf == EnumHalf.BOTTOM) { if (blockShape == adjBlockShape && adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } } } if (blockRelativeSide == EnumFacing.NORTH && adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.STRAIGHT || adjBlockShape == EnumShape.INNER_LEFT || adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (blockHalf == adjBlockHalf) { if (blockRelativeSide == EnumFacing.SOUTH && adjBlockRelativeFacing == EnumFacing.SOUTH) { return false; } if (blockShape == EnumShape.STRAIGHT) { //Tested with debugging and this works. if (blockRelativeSide == EnumFacing.NORTH) { //This also works. if (adjBlockRelativeFacing == EnumFacing.EAST) { //This does too. if (adjBlockShape == EnumShape.INNER_RIGHT) { //This doesn't. return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { //When called, this always prints out "straight" or "outer_right", which makes no sense. System.out.println(blockAccess.getBlockState(pos.offset(side)).getValue(BlockColoreTransStairs.SHAPE).toString()); if (adjBlockShape == EnumShape.INNER_LEFT) { System.out.println("2Test successful! BLAH BLAH BLAH!"); return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockShape == EnumShape.INNER_LEFT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { if (adjBlockShape != EnumShape.OUTER_LEFT) { return false; } } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } } if (blockShape == EnumShape.INNER_RIGHT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } } if (blockShape == EnumShape.OUTER_LEFT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockShape != EnumShape.OUTER_RIGHT) { return false; } } if (blockRelativeSide == EnumFacing.EAST || blockRelativeSide == EnumFacing.SOUTH) { return false; } if (blockRelativeSide == EnumFacing.WEST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.WEST) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } } if (blockShape == EnumShape.OUTER_RIGHT) { if (blockRelativeSide == EnumFacing.NORTH) { if (adjBlockShape != EnumShape.OUTER_LEFT) { return false; } } if (blockRelativeSide == EnumFacing.EAST) { if (adjBlockRelativeFacing == EnumFacing.NORTH) { return false; } if (adjBlockRelativeFacing == EnumFacing.EAST) { if (adjBlockShape == EnumShape.INNER_LEFT) { return false; } } if (adjBlockRelativeFacing == EnumFacing.SOUTH) { if (adjBlockShape == EnumShape.INNER_RIGHT) { return false; } } } if (blockRelativeSide == EnumFacing.SOUTH || blockRelativeSide == EnumFacing.WEST) { return false; } } } } } if (adjBlockState.getBlock() instanceof BlockColoreTrans || adjBlockState.getBlock() instanceof BlockColoreTransSlabDouble) { if (doShadeAndColorMatch(blockState, adjBlockState)) { return false; } } if (adjBlockState.getBlock() instanceof BlockColoreTransSlabHalf) { if ((side == EnumFacing.UP && adjBlockState.getValue(BlockColoreTransSlabHalf.HALF) == EnumBlockHalf.BOTTOM) || (side == EnumFacing.DOWN && adjBlockState.getValue(BlockColoreTransSlabHalf.HALF) == EnumBlockHalf.TOP)) { if (doShadeAndColorMatch(blockState, adjBlockState)) { return false; } } } return true; } //Used to check if the shade & color of the stairs matches that of the adjacent normal block, half-slab, or double-slab. public static boolean doShadeAndColorMatch(IBlockState blockState, IBlockState adjBlockState) { for (String shade : UtilityLists.shadeList) { if (blockState.getBlock().getRegistryName().toString().contains(shade) && adjBlockState.getValue(BlockColore.SHADE) == EnumShade.valueOf(shade.toUpperCase())) { if (IColorMatcher.isSameColor(blockState, adjBlockState)) { return true; } } } return false; } } BlockColoreTransStairs.java package com.supergeniuszeb.colore.common.blocks; import com.supergeniuszeb.colore.utility.StairsSideRenderLogic; import net.minecraft.block.state.IBlockState; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class BlockColoreTransStairs extends BlockColoreStairs { public BlockColoreTransStairs(String name, EnumColor color) { super(name, color); this.setLightOpacity(0); } @SideOnly(Side.CLIENT) public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.TRANSLUCENT; } /** * Used to determine ambient occlusion and culling when rebuilding chunks for render */ @Override public boolean isOpaqueCube(IBlockState state) { return false; } //Determines whether or not a side of the stairs should be rendered. @Override @SideOnly(Side.CLIENT) public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { return StairsSideRenderLogic.shouldSideBeRendered(blockState, blockAccess, pos, side); } @Override public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) { return false; } } BlockColoreStairs.java (regular opaque custom stairs class that is extended by BlockColoreTransStairs) package com.supergeniuszeb.colore.common.blocks; import com.supergeniuszeb.colore.common.init.ModCreativeTabs; import net.minecraft.block.BlockStairs; import net.minecraft.init.Blocks; public class BlockColoreStairs extends BlockStairs implements IBlockName, IColoreColor { private EnumColor color; public BlockColoreStairs(String name, EnumColor color) { super(Blocks.COBBLESTONE.getDefaultState()); //Just getting the most generic state I can think of. this.setHardness(1.5f); this.setHarvestLevel("pickaxe", 0); this.setResistance(10.0f); this.useNeighborBrightness = true; IBlockName.setBlockName(this, name); this.color = color; this.setCreativeTab(ModCreativeTabs.stairsTab); } @Override public EnumColor getColor() { return color; } } Thanks in advance for your help, and once this is sorted out, hopefully this rendering code will help others who want to make transparent stairs in their mods! (Transparency + non-full-cubes + different shapes depending on blockstates = really difficult! )
  23. Honestly, I think that the Pocket/Win10/Gear VR Edition will get an official mod/plugin API within a couple years, once the 2 teams working on the edition (Mojang's PE team and the Win10 Edition team from MS) have achieved feature-parity with the Java edition and they can shift their priority to something else. I'd almost be willing to bet that it gets its mod API before the Java edition, much like BUD blocks, fixed boats, pistons-pushing-block-entities, etc.) At that point, depending on how powerful the official API is, the community for the C++ edition might build their own API on top of the official one to allow for more complex changes/additions. As for right now, the C++ edition is not yet ready to replace the Java edition and to do so needs to achieve feature parity, get ported to OS X & Linux, and get a mod API. The modding community for PE is pretty small right now, due to a lack of modding tools as powerful as Forge and lack of proper dedicated server software. C++ is also considerably more difficult to mod without an existing official API (which is why one is so essential), and the majority of the Minecraft modding community has experience in Java, which is mainly due to the fact that up until recently, the only edition worth modding was written in that language. (It was only a couple years ago that PE had finite worlds, no hunger/experience, no Redstone mechanics, and only a couple mobs.) So basically, the Java edition's modding community is either not experienced enough or not going to want to bother making an API for the C++ edition, seeing as that an official one is not too far on the horizon. One day the C++ edition will become the dominant platform, but there needs to be feature parity, the official API, and Mac/Linux support first, and it will take time for the existing community to move over and for new people with C++ experience to start modding.
  24. Here are some up-to-date tutorials for basic modding in 1.9.4 which should come in handy in the future: https://shadowfacts.net/tutorials/ http://modwiki.temporal-reality.com/mw/index.php/Main_Page I'd also recommend reading this (it was written for 1.8 but is still mostly relevant), this and this to get a good understanding of how Minecraft Forge works.
×
×
  • Create New...

Important Information

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