Skip to content

Instantly share code, notes, and snippets.

@AlexIIL
Last active November 13, 2019 10:32
Show Gist options
  • Save AlexIIL/3c1ee0072b5bce0e99f5 to your computer and use it in GitHub Desktop.
Save AlexIIL/3c1ee0072b5bce0e99f5 to your computer and use it in GitHub Desktop.
Minecraft Forge- Animated block models

Animated Block Models

This would allow simple blocks to be animated by extension of the current block model system. Essentially, this would change block model loading to split up rendering into both the current rendering system, and a TESR hook to be called by a mod's TESR.

All of the examples are partial implementations of what an engine renderer looks like (copied mostly from buildcraft, but ignoring the different types and stages).

The first changed part would be the block state loading, which would have an additional "variables" object (containing a list of the variables used and their default values). In each of the variants an additional "animated" tag would determine whether it should render via a TESR (and get the values for the variables on each frame) or in nortmal block rendering (getting the values from the defaults given above).

// Insert engine_blockstate.json

The second change would be to the model loading system, which would have to be changed to allow for expressions in place of both the positions and UV coordinates.

// Insert engine_model.json

The final addition would be a hooking class to allow any TESR object to get the animated section, change the variables, and render off the animated model.

// Insert EngineRenderTESR

I am going to make a pull request for this, however I would like to check to see what the current direction forge is going in terms of block rendering, and whether I should wait for forge for 1.8.8 to start implementing it.

A seperate (but related) suggestion is a way to get an entire model from a location and render it off inside both a TESR and a custom block model (so, provide a way to get the list of the block models, and apply arbitary rotation to all of them). However I have not tried (very hard) to find this, so you can probably ignore this.

Also if this is NOT wanted in forge it would be great to know quickly, so I can implement this now for BuildCraft, rather than waiting for a "no".

{
"forge_marker": 1,
"variables": {
"progress": 0
},
"variants": {
"facing":{
"up": { },
"down": { "x":180 },
"east": { "x":90, "y":90 },
"west": { "x":90, "y":270 },
"north": { "x":90 },
"south": { "x":90, "y":180 }
},
"moving":{
"false": { "model":"example:engine_model" },
"true": { "model":"example:engine_model", "animated":true }
}
}
}
{
"elements": [
{
"from": [ 0, 0, 0 ],
"to": [ 16, 4, 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture":"#base" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture":"#base" },
"north": { "uv": [ 0, 0, 16, 4 ], "texture":"#front" },
"south": { "uv": [ 0, 0, 16, 4 ], "texture":"#front" },
"west": { "uv": [ 0, 0, 16, 4 ], "texture":"#front" },
"east": { "uv": [ 0, 0, 16, 4 ], "texture":"#front" }
}
},
{
"from": [ 0, "progress + 4", 0 ],
"to": [ 16, "progress + 8", 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture":"#base" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture":"#base" },
"north": { "uv": [ 0, 4, 16, 8 ], "texture":"#front" },
"south": { "uv": [ 0, 4, 16, 8 ], "texture":"#front" },
"west": { "uv": [ 0, 4, 16, 8 ], "texture":"#front" },
"east": { "uv": [ 0, 4, 16, 8 ], "texture":"#front" }
}
},
{
"from": [ 4, 4, 4 ],
"to": [8, "progress + 4", 8 ],
"faces": {
"north": { "uv": [ 4, 0, 12, "progress" ], "texture":"#chamber" },
"south": { "uv": [ 4, 0, 12, "progress" ], "texture":"#chamber" },
"west": { "uv": [ 4, 0, 12, "progress" ], "texture":"#chamber" },
"east": { "uv": [ 4, 0, 12, "progress" ], "texture":"#chamber" }
}
},
{
"from": [ 4, 4, 4 ],
"to": [ 12, 16, 12 ],
"faces": {
"down": { "uv": [ 0, 0, 8, 8 ], "texture":"#trunk" },
"up": { "uv": [ 0, 0, 8, 8 ], "texture":"#trunk" },
"north": { "uv": [ 8, 4, 16, 12 ], "texture":"#trunk" },
"south": { "uv": [ 8, 4, 16, 12 ], "texture":"#trunk" },
"west": { "uv": [ 8, 4, 16, 12 ], "texture":"#trunk" },
"east": { "uv": [ 8, 4, 16, 12 ], "texture":"#trunk" }
}
}
]
}
package example;
// Imports missing for the sake of an example.
public class EngineRenderTESR extends TileEntitySpecialRenderer {
private final AnimatedBlockRenderer engineRenderer;
private final Variable progressVariable;
public EngineRenderTESR() {
// An example class would get the model by its blockstate resource location
engineRenderer = BlockModelHandler.getAnimatedModelRenderer("example:blockstates/engine_blockstate");
/* Note that "progress" is the same as in engine_model.json.
In this example usage, variable are obtained by their names first, and then updated each time the renderer is called.
I'm not sure about actual speeds, but this would probably be faster than looking up a string every render tick,
and safer than using an underlying double array. */
progressVariable = engineModel.getVariable("progress");
/* The above calls would probably throw an exception if either of them did not have the correct arguments (either the
block model file did not exist, or the varaible did not exist) as it would probably be a coding error to pass
incorrect arguments. However, it is possible that a resource pack creator doesn't use some of the variables in their
model file, so it would might be better to just print an error message, and return null. */
}
@Override
public void renderTileEntityAt(TileEntity tile, double x, double y, double z, float f, int wtfIsThis) {
TileEngine engine = (TileEngine) tile;
// This would obviously be handled differently depending on the mod
double progress = engine.getProgress();
IBlockState state = tile.getWorld().getBlockState(tile.getPos());
/* Because the example implementation of "moving" block state is likely to be outside of the metadata, we probably
need to get it */
state = state.getBlock().getActualState(state, tile.getWorld(), tile.getPos());
/* For simplicity, all variables are double's, I currently can't think of a situation where they would need to be
intergers, however an integer cast function could be created. */
progressVariable.set(progress);
/* Manual translation with OpenGL. This translation could be done by the forge renderer itself, but as this suggestion is
about making things accessable to resource pack creators and pulling block models together with the animated parts,
I am not suggesting to remove direct OpenGL usage. A seperate method called renderOffset() could take in the state and
the positional offset to make things simpler if all the TESR needs to to is render off the animated block model. */
GL11.glTranslated(x, y, z);
// The renderer needs the block state to determine what should be animated
// (Note the "animated":true property in the blockstate file)
engineRenderer.render(state);
GL11.glTranslated(-x, -y, -z);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment