I'm working on a power systems mod similar to BuildCraft for Minecraft 1.8 and I wanted to share my progress and disprove that silly myth that the MC 1.8 blockstate rendering system prevents dynamic blocks.
As you can see in the screenshot above, I have created a pipe block that connects to itself and other "energy" blocks. I did this using only blockstates and models. The code makes no reference to the rendering engine or OpenGL.
How does it work?
In the block class for the pipe, I first create 6 block properties (one boolean per face) like this:
public static final PropertyBool SOUTH = PropertyBool.create("south");
public static final PropertyBool NORTH = PropertyBool.create("north");
public static final PropertyBool EAST = PropertyBool.create("east");
public static final PropertyBool WEST = PropertyBool.create("west");
public static final PropertyBool UP = PropertyBool.create("up");
public static final PropertyBool DOWN = PropertyBool.create("down");
Then I created a canConnectTo(...) function that is used to check whether a given adjacent block should connect to this one. I do this by checking that the adjacent block implements an interface so that I can have the pipes connect to machines as well as eachother:
There's a few other functions in the pipe's block class, but the only other one I will highlight here is the getActualState(...) function. This is how Minecraft 1.8 calculates the blockstate.
I discovered that it is critically important that the blockstate parameters must be in alphabetic order! It doesn't work if you do it in a different order (e.g. "up=false,down=false,north=false,south=false,east=false,west=false" fails whereas "down=false,east=false,north=false,south=false,up=false,west=false" works).
You'll notice that each entry in the blockstate file has an "x" parameter and a "y" parameter. These are model rotation parameters. Minecraft 1.8 gives you the ability to rotate a model around the x-axis and y-axis (but not the z-axis, sadly). However, the rotations are clockwise (left-handed vectors), which is the opposite of standard geometry. Also, the rotations must be multiples of 90 degrees (angled blocks must use the model file to create the angle, see the jsons for the vanilla torch as an example).
The number of possible pipe connections is 64 (2^6), but thanks to the axis rotation parameters, I only need 11 model files to cover all 64 connection possiblities. I won't go into the details of these model files here, but I will point out that I made a generic pipe json for each connector type that specifies only the shape (not the texture) and then made a block-specific model json for each that simply looks like this: assets/poweradvantage/models/block/powercable_nuw.json
This file simply specifies the texture and inherits the shape from a pipe model json (north-up-west connector).
And that's all there is to it! For an experienced java programmer, this probably seems like more work, but if you're not a seasoned programmer, then this method is a bit easier to learn than learning OpenGL programming (which is the alternative to using blockstates). My code is open source and you are welcome (and I even encourage you) to copy my code and JSON files for use in your own mods (and repost this in tutorials and such). Minecraft 1.8 needs more pipes!
My mods: Base Metals, Power Advantage, Steam Advantage, Electric Advantage, Minecraft Mineralogy, Dr. Cyano's Lootable Bodies, Dr. Cyano's Wonderful Wands & Wizarding Robes
I overcame the lack of Z rotation by putting a lot of thought into the basic orientation of the model and adding two models for right-angle two-way pipe (and I think the 4-way as well).
My mods: Base Metals, Power Advantage, Steam Advantage, Electric Advantage, Minecraft Mineralogy, Dr. Cyano's Lootable Bodies, Dr. Cyano's Wonderful Wands & Wizarding Robes
I overcame the lack of Z rotation by putting a lot of thought into the basic orientation of the model and adding two models for right-angle two-way pipe (and I think the 4-way as well).
I'm working on a power systems mod similar to BuildCraft for Minecraft 1.8 and I wanted to share my progress and disprove that silly myth that the MC 1.8 blockstate rendering system prevents dynamic blocks.
As you can see in the screenshot above, I have created a pipe block that connects to itself and other "energy" blocks. I did this using only blockstates and models. The code makes no reference to the rendering engine or OpenGL.
How does it work?
In the block class for the pipe, I first create 6 block properties (one boolean per face) like this:
Then I created a canConnectTo(...) function that is used to check whether a given adjacent block should connect to this one. I do this by checking that the adjacent block implements an interface so that I can have the pipes connect to machines as well as eachother:
There's a few other functions in the pipe's block class, but the only other one I will highlight here is the getActualState(...) function. This is how Minecraft 1.8 calculates the blockstate.
Okay, now for the JSON files. Here's the blockstate json:
"__comment": "blockstate parameters MUST be in alphabetical order!",
"variants": {
"down=false,east=false,north=false,south=false,up=false,west=false": { "model": "poweradvantage:powercable_0", "x": 0, "y": 0, "uvlock": true },
"down=true,east=false,north=false,south=false,up=false,west=false": { "model": "poweradvantage:powercable_n", "x": 90, "y": 0, "uvlock": true },
"down=false,east=true,north=false,south=false,up=false,west=false": { "model": "poweradvantage:powercable_n", "x": 0, "y": 90, "uvlock": true },
"down=false,east=false,north=true,south=false,up=false,west=false": { "model": "poweradvantage:powercable_n", "x": 0, "y": 0, "uvlock": true },
"down=false,east=false,north=false,south=true,up=false,west=false": { "model": "poweradvantage:powercable_n", "x": 0, "y": 180, "uvlock": true },
"down=false,east=false,north=false,south=false,up=true,west=false": { "model": "poweradvantage:powercable_n", "x": 270, "y": 0, "uvlock": true },
"down=false,east=false,north=false,south=false,up=false,west=true": { "model": "poweradvantage:powercable_n", "x": 0, "y": 270, "uvlock": true },
"down=true,east=true,north=false,south=false,up=false,west=false": { "model": "poweradvantage:powercable_nw", "x": 90, "y": 180, "uvlock": true },
"down=true,east=false,north=true,south=false,up=false,west=false": { "model": "poweradvantage:powercable_nw", "x": 90, "y": 90, "uvlock": true },
"down=true,east=false,north=false,south=true,up=false,west=false": { "model": "poweradvantage:powercable_nw", "x": 90, "y": 270, "uvlock": true },
"down=true,east=false,north=false,south=false,up=true,west=false": { "model": "poweradvantage:powercable_ns", "x": 90, "y": 0, "uvlock": true },
"down=true,east=false,north=false,south=false,up=false,west=true": { "model": "poweradvantage:powercable_nw", "x": 90, "y": 0, "uvlock": true },
"down=false,east=true,north=true,south=false,up=false,west=false": { "model": "poweradvantage:powercable_nw", "x": 0, "y": 90, "uvlock": true },
"down=false,east=true,north=false,south=true,up=false,west=false": { "model": "poweradvantage:powercable_nw", "x": 0, "y": 180, "uvlock": true },
"down=false,east=true,north=false,south=false,up=true,west=false": { "model": "poweradvantage:powercable_nw", "x": 270, "y": 180, "uvlock": true },
"down=false,east=true,north=false,south=false,up=false,west=true": { "model": "poweradvantage:powercable_ns", "x": 0, "y": 90, "uvlock": true },
"down=false,east=false,north=true,south=true,up=false,west=false": { "model": "poweradvantage:powercable_ns", "x": 0, "y": 0, "uvlock": true },
"down=false,east=false,north=true,south=false,up=true,west=false": { "model": "poweradvantage:powercable_nw", "x": 270, "y": 90, "uvlock": true },
"down=false,east=false,north=true,south=false,up=false,west=true": { "model": "poweradvantage:powercable_nw", "x": 0, "y": 0, "uvlock": true },
"down=false,east=false,north=false,south=true,up=true,west=false": { "model": "poweradvantage:powercable_nw", "x": 270, "y": 270, "uvlock": true },
"down=false,east=false,north=false,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nw", "x": 0, "y": 270, "uvlock": true },
"down=false,east=false,north=false,south=false,up=true,west=true": { "model": "poweradvantage:powercable_nw", "x": 270, "y": 0, "uvlock": true },
"down=true,east=true,north=true,south=false,up=false,west=false": { "model": "poweradvantage:powercable_nuw", "x": 90, "y": 90, "uvlock": true },
"down=true,east=true,north=false,south=true,up=false,west=false": { "model": "poweradvantage:powercable_nuw", "x": 90, "y": 180, "uvlock": true },
"down=true,east=true,north=false,south=false,up=true,west=false": { "model": "poweradvantage:powercable_dnu", "x": 0, "y": 90, "uvlock": true },
"down=true,east=true,north=false,south=false,up=false,west=true": { "model": "poweradvantage:powercable_dnu", "x": 90, "y": 90, "uvlock": true },
"down=true,east=false,north=true,south=true,up=false,west=false": { "model": "poweradvantage:powercable_dnu", "x": 90, "y": 0, "uvlock": true },
"down=true,east=false,north=true,south=false,up=true,west=false": { "model": "poweradvantage:powercable_dnu", "x": 0, "y": 0, "uvlock": true },
"down=true,east=false,north=true,south=false,up=false,west=true": { "model": "poweradvantage:powercable_nuw", "x": 90, "y": 0, "uvlock": true },
"down=true,east=false,north=false,south=true,up=true,west=false": { "model": "poweradvantage:powercable_dnu", "x": 0, "y": 180, "uvlock": true },
"down=true,east=false,north=false,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nuw", "x": 90, "y": 270, "uvlock": true },
"down=true,east=false,north=false,south=false,up=true,west=true": { "model": "poweradvantage:powercable_dnu", "x": 0, "y": 270, "uvlock": true },
"down=false,east=true,north=true,south=true,up=false,west=false": { "model": "poweradvantage:powercable_nsw", "x": 0, "y": 180, "uvlock": true },
"down=false,east=true,north=true,south=false,up=true,west=false": { "model": "poweradvantage:powercable_nuw", "x": 0, "y": 90, "uvlock": true },
"down=false,east=true,north=true,south=false,up=false,west=true": { "model": "poweradvantage:powercable_nsw", "x": 0, "y": 90, "uvlock": true },
"down=false,east=true,north=false,south=true,up=true,west=false": { "model": "poweradvantage:powercable_nuw", "x": 0, "y": 180, "uvlock": true },
"down=false,east=true,north=false,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nsw", "x": 0, "y": 270, "uvlock": true },
"down=false,east=true,north=false,south=false,up=true,west=true": { "model": "poweradvantage:powercable_dnu", "x": 270, "y": 90, "uvlock": true },
"down=false,east=false,north=true,south=true,up=true,west=false": { "model": "poweradvantage:powercable_dnu", "x": 270, "y": 0, "uvlock": true },
"down=false,east=false,north=true,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nsw", "x": 0, "y": 0, "uvlock": true },
"down=false,east=false,north=true,south=false,up=true,west=true": { "model": "poweradvantage:powercable_nuw", "x": 0, "y": 0, "uvlock": true },
"down=false,east=false,north=false,south=true,up=true,west=true": { "model": "poweradvantage:powercable_nuw", "x": 0, "y": 270, "uvlock": true },
"down=true,east=true,north=true,south=true,up=false,west=false": { "model": "poweradvantage:powercable_nsuw", "x": 180, "y": 180, "uvlock": true },
"down=true,east=true,north=true,south=false,up=true,west=false": { "model": "poweradvantage:powercable_nsuw", "x": 90, "y": 90, "uvlock": true },
"down=true,east=true,north=true,south=false,up=false,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 180, "y": 90, "uvlock": true },
"down=true,east=true,north=false,south=true,up=true,west=false": { "model": "poweradvantage:powercable_nsuw", "x": 90, "y": 180, "uvlock": true },
"down=true,east=true,north=false,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 180, "y": 270, "uvlock": true },
"down=true,east=true,north=false,south=false,up=true,west=true": { "model": "poweradvantage:powercable_ensw", "x": 90, "y": 0, "uvlock": true },
"down=true,east=false,north=true,south=true,up=true,west=false": { "model": "poweradvantage:powercable_ensw", "x": 90, "y": 90, "uvlock": true },
"down=true,east=false,north=true,south=true,up=false,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 180, "y": 0, "uvlock": true },
"down=true,east=false,north=true,south=false,up=true,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 90, "y": 0, "uvlock": true },
"down=true,east=false,north=false,south=true,up=true,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 90, "y": 270, "uvlock": true },
"down=false,east=true,north=true,south=true,up=true,west=false": { "model": "poweradvantage:powercable_nsuw", "x": 0, "y": 180, "uvlock": true },
"down=false,east=true,north=true,south=true,up=false,west=true": { "model": "poweradvantage:powercable_ensw", "x": 0, "y": 0, "uvlock": true },
"down=false,east=true,north=true,south=false,up=true,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 0, "y": 90, "uvlock": true },
"down=false,east=true,north=false,south=true,up=true,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 0, "y": 270, "uvlock": true },
"down=false,east=false,north=true,south=true,up=true,west=true": { "model": "poweradvantage:powercable_nsuw", "x": 0, "y": 0, "uvlock": true },
"down=true,east=true,north=true,south=true,up=true,west=false": { "model": "poweradvantage:powercable_desuw", "x": 0, "y": 270, "uvlock": true },
"down=true,east=true,north=true,south=true,up=false,west=true": { "model": "poweradvantage:powercable_desuw", "x": 270, "y": 0, "uvlock": true },
"down=true,east=true,north=true,south=false,up=true,west=true": { "model": "poweradvantage:powercable_desuw", "x": 0, "y": 180, "uvlock": true },
"down=true,east=true,north=false,south=true,up=true,west=true": { "model": "poweradvantage:powercable_desuw", "x": 0, "y": 0, "uvlock": true },
"down=true,east=false,north=true,south=true,up=true,west=true": { "model": "poweradvantage:powercable_desuw", "x": 0, "y": 90, "uvlock": true },
"down=false,east=true,north=true,south=true,up=true,west=true": { "model": "poweradvantage:powercable_desuw", "x": 90, "y": 0, "uvlock": true },
"down=true,east=true,north=true,south=true,up=true,west=true": { "model": "poweradvantage:powercable_densuw", "x": 0, "y": 0, "uvlock": true }
}
}
You'll notice that each entry in the blockstate file has an "x" parameter and a "y" parameter. These are model rotation parameters. Minecraft 1.8 gives you the ability to rotate a model around the x-axis and y-axis (but not the z-axis, sadly). However, the rotations are clockwise (left-handed vectors), which is the opposite of standard geometry. Also, the rotations must be multiples of 90 degrees (angled blocks must use the model file to create the angle, see the jsons for the vanilla torch as an example).
The number of possible pipe connections is 64 (2^6), but thanks to the axis rotation parameters, I only need 11 model files to cover all 64 connection possiblities. I won't go into the details of these model files here, but I will point out that I made a generic pipe json for each connector type that specifies only the shape (not the texture) and then made a block-specific model json for each that simply looks like this:
assets/poweradvantage/models/block/powercable_nuw.json
This file simply specifies the texture and inherits the shape from a pipe model json (north-up-west connector).
And that's all there is to it! For an experienced java programmer, this probably seems like more work, but if you're not a seasoned programmer, then this method is a bit easier to learn than learning OpenGL programming (which is the alternative to using blockstates). My code is open source and you are welcome (and I even encourage you) to copy my code and JSON files for use in your own mods (and repost this in tutorials and such). Minecraft 1.8 needs more pipes!
Try it yourself: https://github.com/cyanobacterium/PowerAdvantageAPI/releases/tag/v0.0.1. Note that this is a super-early alpha build and crashes on a dedicated server (I haven't clean-up the code yet).
My mods:
Base Metals, Power Advantage, Steam Advantage, Electric Advantage, Minecraft Mineralogy, Dr. Cyano's Lootable Bodies, Dr. Cyano's Wonderful Wands & Wizarding Robes
Since z rotation of models isn't supported, how did you overcome this?
I overcame the lack of Z rotation by putting a lot of thought into the basic orientation of the model and adding two models for right-angle two-way pipe (and I think the 4-way as well).
You can see it in action in my new Power Advantage mod: http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/2428782-power-advantage-power-systems-mod-and-api-for
(source code: https://github.com/cyanobacterium/PowerAdvantageAPI)
My mods:
Base Metals, Power Advantage, Steam Advantage, Electric Advantage, Minecraft Mineralogy, Dr. Cyano's Lootable Bodies, Dr. Cyano's Wonderful Wands & Wizarding Robes
Thanks. I ended up doing the same thing, making a new model for the orientation group. And now I have a block with connected textures!!!