v2.0 Refactor - copycats-plus/copycats GitHub Wiki
Copycats+ version 2.0 includes a complete refactor of the copycat API to separate from Create's messy implementation and create a unified interface for all types of copycat blocks. Due to the massive amount of breaking changes, here's a dedicated document to explain what has changed.
Term | Meaning |
---|---|
Material | The block state that the copycat is copying, not the state of the copycat itself |
Simple copycats | Copycats that can only accept one material and extends ICopycatBlock , not IMultiStateCopycatBlock
|
Multi-state copycats | Copycats that can accept multiple materials and extends IMultiStateCopycatBlock , not ICopycatBlock
|
Kinetic copycats | Copycats with moving parts, such as shafts and cogs, that accept materials and are rendered with block entity renderers or with Flywheel instances |
Block space | A value of 1 equals the length of a whole block |
Voxel space | A value of 1 equals 1/16 of a block (because most texture packs are 16x16) |
Interface with implementation | Interfaces such as ICopycatBlock and ICopycatBlockEntity which contain most of the implementation code as default methods. The documentation of these interfaces details the steps to implementing them. |
Assembly API | A set of helpers to assemble a new model using a given block model and calls to the assemblePiece function. Was called simple copycat API |
Obsolete: used to refer to copycats that do not extend from Create's CopycatBlock . |
All copycat blocks, including multi-state copycats and copycats that extend from Create's CopycatBlock
class, now implement ICopycatBlock
, so this is the recommended way to check for a copycat block. Multi-state copycats implement ICopycatBlock
indirectly via IMultiStateCopycatBlock
, which implements copycat block methods with reasonable defaults and provides multi-state specific methods.
When implementing a copycat with a base class other than CCCopycatBlock
or MultiStateCopycatBlock
, follow the documentation on ICopycatBlock
or IMultiStateCopycatBlock
interfaces for implementation requirements.
Platform-specific implementations of block events, such as getExplosionResistance
, getFriction
, addLandingEffects
, etc are now handled with mixins. If a copycat block does not inherit from CCCopycatBlock
/MultiStateCopycatBlock
, it should be registered as a target class for the Forge/Fabric CopycatBlockMixin
/MultiStateCopycatBlockMixin
.
All copycat block entities, including multi-state copycats and copycats that extend from Create's CopycatBlockEntity
, now implement ICopycatBlockEntity
. Multi-state copycats implement ICopycatBlockEntity
indirectly via IMultiStateCopycatBlockEntity
.
When implementing a copycat with a base class other than CCCopycatBlockEntity
or MultiStateCopycatBlockEntity
, follow the documentation on ICopycatBlockEntity
or IMultiStateCopycatBlockEntity
interfaces for implementation requirements.
Platform-specific implementations of block entity render data are now handled with mixins. If a copycat block does not inherit from CCCopycatBlockEntity
/MultiStateCopycatBlockEntity
, it should be registered as a target class for the Forge/Fabric CopycatBlockEntityMixin
/MultiStateCopycatBlockEntityMixin
.
Copycat models have been reworked and are now separate from Create. There are 2 parts in each copycat model, a platform-specific but block-independent foundation which is named CopycatModelForge
/ CopycatModelFabric
, and a block-specific but platform-independent core which is named Copycat<Block>ModelCore
and extends from CopycatModelCore
.
Compared with 1.3:
SimpleCopycatModel
has been merged withCopycatModel
, andSimpleCopycatPart
has been expanded to becomeCopycatModelCore
.
All copycat models must now use the assembly API exposed by CopycatRenderContext
to assemble models. Each CopycatModelCore
can specify multiple models to be rendered, with a model getter and an assembly function for each model.
For simple copycats, the API is largely unchanged. You only need to implement emitCopycatQuads
like in SimpleCopycatPart
:
public class CopycatSimpleModelCore extends CopycatModelCore {
@Override
public void emitCopycatQuads(String key, BlockState state, CopycatRenderContext context, BlockState material) {
AssemblyTransform transform = t -> t.rotateX(90);
context.assemblePiece(
transform,
vec3(0, 0, 12),
aabb(16, 1, 4).move(0, 0, 12),
cull(UP | NORTH)
);
}
}
For multi-state copycats, you only need to override registerModels
with the provided multi-state helper function, and then assemble the model like in SimpleCopycatPart
:
public class YourCopycatMultiStateModelCore extends CopycatModelCore {
@Override
public void registerModels(List<ModelEntry> entries) {
registerForMultiState(entries, CCBlocks.YOUR_COPYCAT_MULTI_STATE.get());
}
@Override
public void emitCopycatQuads(String key, BlockState state, CopycatRenderContext context, BlockState material) {
context.assemblePiece(
transform,
vec3(0, 0, 0),
aabb(4, layer, 16),
cull(EAST | UP)
);
}
}
You have two choices if you need to render additional models which are not part of the copied material. You can either do it the vanilla way, where you register the model in the block state of the copycat block using Registrate, or do it with Flywheel partial models.
For the vanilla method, you should first register your model in the block state:
public static final BlockEntry<CopycatGlassFluidPipeBlock> COPYCAT_GLASS_FLUID_PIPE =
REGISTRATE.block("copycat_glass_fluid_pipe", CopycatGlassFluidPipeBlock::new)
/ /...
.blockstate(CCBlockStateGen::glassPipe)
// ...
.register();
and then use the model in the copycat model core:
@Override
public void registerModels(List<ModelEntry> entries) {
super.registerModels(entries);
entries.add(SUPER); // render the block state model without modifications
}
For the Flywheel PartialModel method, you should first register your model as a partial model (ref Create's AllPartialModels
), and then specify it in the copycat model core:
@Override
public void registerModels(List<ModelEntry> entries) {
entries.add(new ModelEntry(
"my_partial_model", // a custom key to identify your partial model
(state, mat) -> AllPartialModels.ANALOG_LEVER_HANDLE.get(), // get the BakedModel from the partial model
null, // render the model without modifications
false // use the model's logic for culling and CT
));
}
In both cases, provide an implementation of CopycatModelPart
if you wish to modify the model using the copycat model assembly API.
To facilitate caching, copycat models for kinetic copycats should be decomposed into reusable parts so that each part can be cached separately. For example, the shaft in a copycat cogwheel should be implemented in a separate CopycatModelCore
so that it can be reused in copycat shafts.
To render moving parts for kinetic copycats, first implement a CopycatModelCore
for those parts like normal.
Then, instead of registering it with Registrate, add your model core to CopycatPartialModel
and specify the block state properties that it requires.
Finally, render the moving parts using KineticCopycatRenderer
in your renderer/instance implementation. Take a look at the implementation of copycat shaft for more details.
- All classes from
content.copycat.base
are moved tofoundation.copycat
. APIs in thefoundation
package are considered public and stable. - The
multiloader
package is removed, with utilities moved to theutility
package. -
GlobalTransform
is now renamed toAssemblyTransform
. Usage is unchanged. - You should now write
context.assemblePiece(...)
instead ofassemblePiece(context, ...)
. -
CopycatRenderContext
is now an interface with no type arguments, so you can just writeCopycatRenderContext
instead ofCopycatRenderContext<?, ?>
. - Several variants of
assembleQuad
are no longer available because they use platform-specific quad classes. - Support for block transformations (rotations, mirroring) has been improved. All copycat blocks should implement
rotate
,mirror
andtransform
. Multi-state copycats should also implementtransformStorage
.