Poke at stuff, documentation especially
This commit is contained in:
parent
80910e38f5
commit
e034fae532
30
README.md
30
README.md
@ -18,11 +18,35 @@ Template blocks can be placed in the world, then right-clicked with a full-size
|
|||||||
|
|
||||||
* Evaluate whether I need to keep the `Supplier` in TemplatesModelProvider, or whether I can reuse my `UnbakedModel`s indefinitely
|
* Evaluate whether I need to keep the `Supplier` in TemplatesModelProvider, or whether I can reuse my `UnbakedModel`s indefinitely
|
||||||
* `templates:block/slope_base` needs a suspicious amount of custom rotations. Maybe the model is pointing the wrong way.
|
* `templates:block/slope_base` needs a suspicious amount of custom rotations. Maybe the model is pointing the wrong way.
|
||||||
|
* `uvlock` in a blockstate will not work for `RetexturedMeshTemplateUnbakedModel`s. Can it be fixed?
|
||||||
* Upside-down slopes would be nice...
|
* Upside-down slopes would be nice...
|
||||||
* More templates !!
|
* More templates !!
|
||||||
|
|
||||||
## Notes for addon developers
|
## For addon developers
|
||||||
|
|
||||||
To create your block, instantiate or extend `TemplateBlock`. Pass your `Block.Settings` through `TemplateBlock.configureSettings` to wire up the "click for glowstone" feature. Create an `ItemBlock` as normal, and create a `BlockEntityType` by instantiating or extending `TemplateEntity`.
|
You may create your block any way you like, just make sure it has a block entity that returns a `BlockState` object from `RenderAttachmentBlockEntity.getRenderAttachmentData` and implements `ThemeableBlockEntity`. If you don't already have a block, the stock implementations in `TemplateBlock` and `TemplateEntity` are considered public API - they also implement the light- and redstone-emission features, just remember to feed the `AbstractBlock.Settings` through `TemplateBlock.configureSettings`.
|
||||||
|
|
||||||
Next, wire up the custom model todo document this, it's easy
|
(Really the important part is implementing `RenderAttachmentBlockEntity` with a `BlockState`; that's the only thing Templates's bakedmodels assume. `ThemeableBlockEntity` opts-in to a couple more things such as overriding the break/sprint/fall particles.)
|
||||||
|
|
||||||
|
## `Mesh`-based models
|
||||||
|
|
||||||
|
We will construct a `RetexturedMeshTemplateUnbakedModel`. You need two things - the ID of a parent model, and a `Supplier<Mesh>` to retexture.
|
||||||
|
|
||||||
|
Fill in the parent model field with the ID of any model. Ideally, this model should have a parent of `block/block`, or at least define *some* non-default rotations (smokey the bear voice *Only You Can Prevent Weirdly Rotated First-Person Models*), set `"gui_light": "front"` (lest the item model look weird), and define a particle texture.
|
||||||
|
|
||||||
|
When building the `Mesh`, if you want a face to be dynamically retextured, `.tag()` it with the `.ordinal() + 1` of the `Direction` it corresponds to and give the face U/V coordinates ranging from 0 to 1. (For example, if you tag a face with `3` (`Direction.NORTH.ordinal() + 1`), it will be retextured to the north side of the template's theme.)
|
||||||
|
|
||||||
|
(TODO: implement a system for baking unchanging `Sprite`s onto the mesh, potentially by "registering" more tags; the problem is you don't have access to sprite uvs at mesh building time. Or just provide a way to get sprite UVs at mesh building time...?)
|
||||||
|
|
||||||
|
That's all you need in order to construct a `RetexturedMeshTemplateUnbakedModel`, so to finish things off:
|
||||||
|
|
||||||
|
* Come up with an ID for it
|
||||||
|
* Register it using `TemplatesClient.provider.addTemplateModel` (a thin wrapper around Fabric's `ModelResourceProvider`)
|
||||||
|
* Create a blockstate for your block, point it at your model's ID
|
||||||
|
* You may rotate the blockmodel with the `x` and `y` properties.
|
||||||
|
|
||||||
|
You may create a regular item model (JSON or otherwise), or use ours by calling `TemplatesClient.provider.assignItemModel` (a thin wrapper around Fabric's `ModelVariantProvider`) passing the same model ID the block used. (This is a bit of a kludge. The reason you have to do this, instead of simply creating a regular item model and setting its `parent`, is that `JsonUnbakedModel`s can't have non-`JsonUnbakedModel`s as their `parent`, and even a trivial item model with only the `parent` field set counts as a `JsonUnbakedModel`. Blockstates are a layer of indirection before model loading, so it's not a problem for blocks.)
|
||||||
|
|
||||||
|
## JSON models
|
||||||
|
|
||||||
|
Soon:tm:
|
@ -1,6 +1,6 @@
|
|||||||
package io.github.cottonmc.templates;
|
package io.github.cottonmc.templates;
|
||||||
|
|
||||||
import io.github.cottonmc.templates.model.RetexturedMeshTemplateModel;
|
import io.github.cottonmc.templates.model.RetexturedMeshTemplateUnbakedModel;
|
||||||
import io.github.cottonmc.templates.model.SlopeBaseMesh;
|
import io.github.cottonmc.templates.model.SlopeBaseMesh;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||||
@ -55,7 +55,7 @@ public class TemplatesClient implements ClientModInitializer {
|
|||||||
|
|
||||||
BlockRenderLayerMap.INSTANCE.putBlock(Templates.SLOPE, RenderLayer.getCutout());
|
BlockRenderLayerMap.INSTANCE.putBlock(Templates.SLOPE, RenderLayer.getCutout());
|
||||||
|
|
||||||
provider.addTemplateModel(Templates.id("slope_special"), () -> new RetexturedMeshTemplateModel(Templates.id("block/slope_base"), SlopeBaseMesh::make));
|
provider.addTemplateModel(Templates.id("slope_special"), () -> new RetexturedMeshTemplateUnbakedModel(Templates.id("block/slope_base"), SlopeBaseMesh::make));
|
||||||
provider.assignItemModel(Templates.id("slope_special"), Templates.SLOPE);
|
provider.assignItemModel(Templates.id("slope_special"), Templates.SLOPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package io.github.cottonmc.templates.api;
|
package io.github.cottonmc.templates.api;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
|
||||||
public interface ThemeableBlockEntity {
|
public interface ThemeableBlockEntity extends RenderAttachmentBlockEntity {
|
||||||
BlockState getThemeState();
|
default BlockState getThemeState() {
|
||||||
|
return (BlockState) getRenderAttachmentData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package io.github.cottonmc.templates.block.entity;
|
|||||||
|
|
||||||
import io.github.cottonmc.templates.Templates;
|
import io.github.cottonmc.templates.Templates;
|
||||||
import io.github.cottonmc.templates.api.ThemeableBlockEntity;
|
import io.github.cottonmc.templates.api.ThemeableBlockEntity;
|
||||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@ -19,7 +18,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class TemplateEntity extends BlockEntity implements RenderAttachmentBlockEntity, ThemeableBlockEntity {
|
public class TemplateEntity extends BlockEntity implements ThemeableBlockEntity {
|
||||||
protected BlockState renderedState = Blocks.AIR.getDefaultState();
|
protected BlockState renderedState = Blocks.AIR.getDefaultState();
|
||||||
|
|
||||||
//Whether the player has manually spent a redstone/glowstone item to upgrade the template.
|
//Whether the player has manually spent a redstone/glowstone item to upgrade the template.
|
||||||
@ -75,11 +74,6 @@ public class TemplateEntity extends BlockEntity implements RenderAttachmentBlock
|
|||||||
return renderedState;
|
return renderedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getThemeState() {
|
|
||||||
return renderedState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRenderedState(BlockState newState) {
|
public void setRenderedState(BlockState newState) {
|
||||||
if(!Objects.equals(renderedState, newState)) {
|
if(!Objects.equals(renderedState, newState)) {
|
||||||
renderedState = newState;
|
renderedState = newState;
|
||||||
|
@ -16,8 +16,8 @@ import java.util.function.Function;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@SuppressWarnings("ClassCanBeRecord")
|
@SuppressWarnings("ClassCanBeRecord")
|
||||||
public class RetexturedMeshTemplateModel implements UnbakedModel {
|
public class RetexturedMeshTemplateUnbakedModel implements UnbakedModel {
|
||||||
public RetexturedMeshTemplateModel(Identifier parent, Supplier<Mesh> baseMeshFactory) {
|
public RetexturedMeshTemplateUnbakedModel(Identifier parent, Supplier<Mesh> baseMeshFactory) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.baseMeshFactory = baseMeshFactory;
|
this.baseMeshFactory = baseMeshFactory;
|
||||||
}
|
}
|
@ -11,11 +11,11 @@ public class SlopeBaseMesh {
|
|||||||
/**
|
/**
|
||||||
* @see TemplateBakedModel.RetexturingTransformer for why these values were chosen
|
* @see TemplateBakedModel.RetexturingTransformer for why these values were chosen
|
||||||
*/
|
*/
|
||||||
public static final int TAG_SLOPE = Direction.UP.ordinal();
|
public static final int TAG_SLOPE = Direction.UP.ordinal() + 1;
|
||||||
public static final int TAG_LEFT = Direction.EAST.ordinal();
|
public static final int TAG_LEFT = Direction.EAST.ordinal() + 1;
|
||||||
public static final int TAG_RIGHT = Direction.WEST.ordinal();
|
public static final int TAG_RIGHT = Direction.WEST.ordinal() + 1;
|
||||||
public static final int TAG_BACK = Direction.SOUTH.ordinal();
|
public static final int TAG_BACK = Direction.SOUTH.ordinal() + 1;
|
||||||
public static final int TAG_BOTTOM = Direction.DOWN.ordinal();
|
public static final int TAG_BOTTOM = Direction.DOWN.ordinal() + 1;
|
||||||
|
|
||||||
public static Mesh make() {
|
public static Mesh make() {
|
||||||
Renderer renderer = TemplatesClient.getFabricRenderer();
|
Renderer renderer = TemplatesClient.getFabricRenderer();
|
||||||
|
@ -100,7 +100,7 @@ public final class TemplateBakedModel extends ForwardingBakedModel {
|
|||||||
quad.material(appearance.getRenderMaterial());
|
quad.material(appearance.getRenderMaterial());
|
||||||
|
|
||||||
//The quad tag numbers were selected so this magic trick works:
|
//The quad tag numbers were selected so this magic trick works:
|
||||||
Direction dir = facePermutation.get(DIRECTIONS[quad.tag()]);
|
Direction dir = facePermutation.get(DIRECTIONS[quad.tag() - 1]);
|
||||||
|
|
||||||
//TODO: this newly-simplified direction passing to hasColor is almost certainly incorrect
|
//TODO: this newly-simplified direction passing to hasColor is almost certainly incorrect
|
||||||
// I think hasColor was kinda incorrect in the first place tho
|
// I think hasColor was kinda incorrect in the first place tho
|
||||||
|
Loading…
Reference in New Issue
Block a user