-
-
Notifications
You must be signed in to change notification settings - Fork 52
Your First Instance
This wiki is a work in progress! Hopefully it can lead you in the right direction.
Start by creating an empty subclass of BlockEntityInstance
, and build it up from there.
public class MyBlockInstance extends BlockEntityInstance<MyBlockEntity> {
public MyBlockInstance(MaterialManager materialManager, MyBlockEntity blockEntity) {
super(materialManager, blockEntity);
}
@Override
public void remove() {
// You'll be doing some cleanup here later.
}
}
And you have to register the Instance
with Flywheel, so might as well get that out of the way now.
public class MyInstances {
public static void init() {
InstancedRenderRegistry.configure(MyBlockEntityTypes.MY_BLOCK_ENTITY)
.alwaysSkipRender() // Completely skip the BlockEntityRenderer.
.factory(MyBlockInstance::new) // Use our BlockEntityInstance instead.
.apply(); // Apply the instancing configuration.
}
}
And be sure to call MyInstances.init()
somewhere!
But, let's get back to the fun stuff. As it currently stands, our Instance does nothing but sit there and take up memory. So, you might ask, how can I get it to render something?
In Flywheel, BlockEntityInstance
s don't technically render models on their own. Instead, they ask the
MaterialManager
to create a parameterized instance of a model. The BlockEntityInstance
is then free to change the
parameters, and Flywheel takes care of the rest, ensuring that your copy of the model is rendered in the right place,
with the right light, etc.
So let's have your Instance ask the MaterialManager for a copy of some bricks, because why not?
public class MyBlockInstance extends BlockEntityInstance<MyBlockEntity> {
private final ModelData model;
public MyBlockInstance(MaterialManager materialManager, MyBlockEntity blockEntity) {
super(materialManager, blockEntity);
model = materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(Blocks.BRICKS.defaultBlockState()) // Feel free to use a different blockstate!
.createInstance();
// translate the model to make it appear at your BlockEntity
model.loadIdentity()
.translate(getInstancePosition());
}
...
}
And now that you've acquired resources, you have to make sure to clean up after yourself!
public class MyBlockInstance extends BlockEntityInstance<MyBlockEntity> {
...
@Override
public void remove() {
model.delete();
}
}
If you don't call InstanceData#delete()
, all the models you ask for will be left behind when
your block entity is broken.
If you were to launch your game and place down your block entity now, you'd see bricks, but they'd be very dark!
That's because you never tell Flywheel how to light the bricks!
In Flywheel, there's no need to query block and sky light every frame (like what's done for BlockEntityRenderer
s).
Instead, light data can be stored in the ModelData
, and updated as necessary. Flywheel already does most of the
heavy lifting here, it's just on you to make sure you update your parameters when Flywheel detects a light update.
You do this by overriding (drum roll...) #updateLight
.
public class MyBlockInstance extends BlockEntityInstance<MyBlockEntity> {
...
@Override
public void updateLight() {
relight(getWorldPosition(), model);
}
}
relight(...)
is a helper method that takes a BlockPos and a series of model parameters, and updates the parameters
with the light data at the given position.
And so now your class looks like this:
public class MyBlockInstance extends BlockEntityInstance<MyBlockEntity> {
private final ModelData model;
public MyBlockInstance(MaterialManager materialManager, MyBlockEntity blockEntity) {
super(materialManager, blockEntity);
model = materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(Blocks.BRICKS.defaultBlockState())
.createInstance();
model.loadIdentity()
.translate(getInstancePosition());
}
@Override
public void remove() {
model.delete();
}
@Override
public void updateLight() {
relight(getWorldPosition(), model);
}
}