readme tweaks

This commit is contained in:
quat1024 2023-08-31 22:56:48 -04:00
parent a160f68ffc
commit 7c35695924
3 changed files with 92 additions and 33 deletions

View File

@ -4,6 +4,9 @@ Versions before 2.1.2 have been backfilled; I gotta be more on top of changelogs
* Remove some unused stuff from the jar
* Code cleanups, hopefully without breaking ABI compat (i don't have an ABI checker in the pipeline tho)
* Fix a bug where templates that look like blocks with randomized models, such as stone, could reroll their blockstate on every resource load.
* Forgot to specify a random seed.
* All templated blocks still use the *same* model, so templated stone will still not be randomly rotated/flipped, but at least it's now the *same* same model.
road map:

121
README.md
View File

@ -8,72 +8,127 @@
**This mod is open source and under a permissive license.** As such, it can be included in any modpack on any platform without prior permission. We appreciate hearing about people using our mods, but you do not need to ask to use them. See the [LICENSE file](LICENSE) for more details.
Template blocks can be placed in the world, then right-clicked with a full-size block to set the textures for the template. Template blocks will inherit light and redstone values from the blocks they're given, or they can have light or redstone output added to any given block by right-clicking the template with glowstone dust or a redstone torch, respectively.
If a Template block is placed in the world and right-clicked with a full-size block, it will take on the appearance of that block. Template blocks will inherit light and redstone values from the blocks they're given. Adding a *redstone torch* will make them emit redstone power, *glowstone dust* will make them emit light, and *popped chorus fruit* will make them intangible.
While Templates itself adds a handful of common shapes, it's also not too hard for other mods to interface with Templates and add their own templatable blocks.
# quat was here
Todo move this into the main readme section
COOL RIVULET is by mev , this is the most important block in the mod & perhaps the most important block in any mod ever since `incorporeal:clearly`
## Todo
* More templates !!
While Templates itself adds a handful of common shapes, it's not too hard for other mods to interface with Templates and add their own templatable blocks.
# For addon developers
## Creating a block entity
All templates need a block entity to store what block they look like. Templates registers one under `templates:slope`[^1], but as an addon developer you can't add additional blocks to my block entity. (Don't try, please.)
To that end, nothing in Templates relies on the *specific* block entity ID, so just re-register `TemplateEntity` under your own name. You are free to extend `TemplateEntity` as well.
The only hard requirement on the block entity is that it `implements ThemeableBlockEntity`. (This implies it returns a `BlockEntity` from `getRenderAttachmentData`.)
## Creating your block
So there are various block interactions in Templates, like adding glowstone to make the block illuminate, adding redstone to make it a power source, etc.
There are various block interactions in Templates, like adding redstone to make the block emit power. To make your block fit with the other Templates, you'll want those behaviors to apply to your block as well. There's a couple options, depending on the complexity of the block you'd like to "template-ify".
In an ideal world, I'd be able to simply provide the `TemplateBlock` class implementing all those features and ask that you extend it from your block. If your block doesn't already have a superclass I recommend doing this - alas, if it does, you can't also extend `TemplateBlock`, so the implementation of everything has been farmed out to `public static` methods in `TemplateInteractionUtil` in the api package. Simply wire everything up.
If you simply registered a `Block` or a simple vanilla class like `WallBlock`, use the corresponding class in `io.github.cottonmc.templates.block`.
Don't forget to feed your `Block.Settings` through `TemplateInteractionUtil.configureSettings` too, and if there's any behaviors you'd like to tweak, try implementing some methods from `TemplateInteractionUtilExt` before resorting to copy-pasting the implementation of `TemplateInteractionUtil` methods. But copy paste away if you must.
If you registered something different (like a `MyFancyBlock`), the simplest approach is to leverage `TemplateInteractionUtil`, which is where all of the interaction code lives in a mildly "pluggable" form. Here are the suggested steps:
The only other requirement is that your block *must* have a block entity, that both returns a `BlockState` object from `RenderAttachmentBlockEntity.getRenderAttachmentData` and implements `ThemeableBlockEntity`. `TemplateEntity` is an implementation of this (and also implements the other half of the features from `TemplateInteractionUtil`); I recommend using it if you can.
* Create a `TemplateMyFancyBlock` class that extends your block class.
* Copy-paste the body of `TemplateBlock` into it; adjust the constructor as needed. (It was designed to be copy-pasted in this way; this is how i filled out most of the other classes.)
* Make sure it instantiates your block entity type.
* Check that the methods are implemented the way you'd like.
* Particularly you might want to look at the redstone emission methods; the default ones don't call `super`.
And if all else fails, just reimplement whatever interactions you'd like, or simply don't bother. None of this is important for the actual *retexturing* part of the mod, apart from returning a suitable block entity.
## Creating the custom model
(TL;DR look at `assets/templates/blockstates` and the bottom of `TemplatesClient`)
To make a model retexturable, Templates has to know which faces you want to retexture, and which side of the block they correspond to. There are currently three ways to tell Templates your intentions:
Of course Templates leverages custom baked models. All of Templates's baked model implementations find and retexture quads from an upstream source that you will need to provide.
Templates needs three pieces of information to perform retexturing:
* the quad to be retextured
* whether you actually want to retexture it or just pass it through unchanged (see the Lever Template, which doesn't change the lever arm);
* what face of the block it corresponds to (which is sometimes different from "the direction it points" - see the Door Template, the textures "stick" when you open the door)
The last piece of information is important because Templates tries hard to retain the orientation of blocks placed inside of them - you can place specifically an *east-facing* log into a Template, for example, and some faces get the cut wood while other faces get the bark. (Some other mods just use the same texture on all faces of the block, like the particle texture.)
Pick a model implementation that suits your needs:
### `UnbakedAutoRetexturedModel`
Pass the ID of a JSON model to retexture. All quads that face east will be textured with the east side of the theme, all quads that face up will be textured with the top side of the theme, etc. There is no way to skip a face.
* the quad: Sourced from a JSON model.
* whether you want to retexture it: "Yes". All quads will be retextured.
* what face of the block: Automatically determined by facing direction.
Most of Templates's blocks use this model.
To construct, pass the ID of the JSON model you want to source quads from.
There's no way to configure this, so if you want to skip retexturing a face, try the next model implementation instead.
**TODO**: this does not work well with `multipart` models with differently-rotated parts, like the fence model (consisting of 1 fence post and 1 fence-side model that gets rotated around to fill all 4 sides)
### `UnbakedJsonRetexturedModel`
Pass the ID of a JSON model to retexture. All quads textured with `templates:templates_special/east` will be textured with the east side of the theme, all quads textured with `templates:templates_special/up` will be retextured with the top side of the theme, etc. Quads textured with any other texture will be passed through unaltered.
* the quad: Sourced from a JSON model.
* whether you want to retexture it: Determined from the texture applied to the quad.
* what face of the block: Determined via the texture applied to the quad.
Templates's lever uses this model - `AutoRetexturedModel` was not appropriate because I did not want to retexture the lever arm.
To construct, pass the ID of a JSON model to retexture. All quads textured with `templates:templates_special/east` will be textured with the east side of the theme, all quads textured with `templates:templates_special/up` will be retextured with the top side of the theme, etc. Quads textured with any other texture will be passed through unaltered.
(This works better with multipart models.)
<details><summary>Regarding texture variables:</summary>
On the off-chance your blockmodel already has texture variables for `north`, `south`, etc, you can simply apply Templates's special textures to it:
```json
{
"parent": "mymod:block/my_model",
"textures": {
"north": "templates:templates_special/north",
"east": "templates:templates_special/east",
"south": "templates:templates_special/south",
"west": "templates:templates_special/west",
"up": "templates:templates_special/up",
"down": "templates:templates_special/down",
}
}
```
Sadly, many models don't specify *completely* separate textures for all six sides. If you have a setup like an "ends" variable which gets applied to "the top and bottom" or something, please don't use the texture-variables approach. Instead, see if the `UnbakedAutoRetexturedModel` suits your needs, or make a second copy of the json model that does separately fill in all faces.
</details>
(This one works better with multipart models.)
### `UnbakedMeshRetexturedModel`
Pass either a `Supplier<Mesh>` or a `Function<Function<SpriteIdentifier, Sprite>, Mesh>` (i.e. a function with an optional `Function<SpriteIdentifier, Sprite>` argument, and a return type of `Mesh`). All quads `.tag()`ged with `Direction.EAST.ordinal() + 1` will be textured with the east side of the theme, all quads tagged with `Direction.UP.ordinal() + 1` will be retextured with the top side of the theme, etc. Give these faces UV coordinates ranging from 0 to 1.
* the quad: Sourced from a `Mesh`.
* whether you want to retexture it: Quads with a nonzero `tag`.
* what face of the block: Determined from the `tag`.
Quads with the tag `0` will be passed through unaltered (hence the `+ 1` bias), and they expect UV coordinates that already point to an appropriate region of the block atlas (which is where the `Function<SpriteIdentifier, Sprite>` argument comes in - query it for sprites and put their UV coordinates on the model)
To construct, pass a `Supplier<Mesh>`. To mark a face "retexture this with the EAST side of the block", call `.tag(Direction.EAST.ordinal() + 1)` on it; same for the other directions. (So, the valid tags are 1, 2, 3, 4, 5, and 6, corresponding to down, up, north, south, west, east.) Give these faces UV coordinates ranging from 0 to 1.
(To construct this type, you will also need to pass the identifier of a "base model", which can be a regular JSON model. Miscellaneous `BakedModel` properties like rotations, AO, `isSideLit`, etc will be sourced from it.)
A `.tag` of 0 (the default) will be passed through unchanged. This is a little useless since you still need to provide UV coordinates, so instead of passing a `Supplier<Mesh>` you can also pass a `Function<Function<SpriteIdentifier, Sprite>, Mesh>`; you will be provided with a `Function<SpriteIdentifier, Sprite>` that you can query for sprite information, including their UVs.
Templates's slope blocks use this model, because it's otherwise impossible to make triangle-shaped faces in a JSON model.
(To construct this type, you will also need to pass the identifier of a "base model", which can be a regular JSON model. Miscellaneous `BakedModel` properties like rotations, AO, `isSideLit`, etc will be sourced from it. See Template's `models/block/slope_base`. You may need to set `"gui_light": "front"` to avoid a flat look in the ui.)
### A secret fourth thing
Templates doesn't actually care about the block model you pass in. It won't *work* unless you reimplement the retexturing, but if you have your needs I won't stop you.
All the models are supposed to be extensible (if i left a stray `private` let me know). All the `UnbakedModels` are backed by the same abstract class called `RetexturingBakedModel` which actually does the retexturing; feel free to extend it.
## Registering your model
1. Decide on an ID for your special model that's *different* from the ID used for the base model.
* If your base model lives at `yourmod:block/awesome_template`, something like `yourmod:awesome_template_special` would do.
2. Register it using `TemplatesClient.provider.addTemplateModel`.
3. Create a blockstate json for your block, and point it at the ID you decided for your special model in 1).
* You may use the `x`, `y`, and `uvlock` properties as normal.
After you've decided on and constructed your special model, you should tell Templates about it. Pick an ID that's different from the base model. (If your base model is `mymod:block/awesome_template`, a good name might be `mymod:awesome_template_special`). Register your special model under that ID using `TemplatesClient.provider.addTemplateModel`.
Ambient occlusion now defaults to "on" (since 2.1.1). If this looks bad on your model, you can reset it with a `.disableAo()` call on your UnbakedModel.
To assign the block model, using a vanilla blockstate file, simply point your block at that model ID as normal. (See this mod's `blockstates` folder.) You may also use the `x`, `y`, and `uvlock` properties.
You may create a regular item model, or use ours by calling `TemplatesClient.provider.assignItemModel`, passing the ID of the special model & the items you want to assign it to. (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`. This isn't a problem for block models because blockstates are a layer of indirection before model loading.)
To assign the item model, since items don't have the "blockstate file" level of indirection, call `TemplatesClient.provider.assignItemModel`, passing your special model's ID and the items it should be assigned to. Or if you'd rather use a vanilla json model (that won't be retextured) just make one the vanilla way.
# Most important attribution in the whole wide world
COOL RIVULET is by mev, this is the most important block in the mod & perhaps the most important block in any mod ever since `incorporeal:clearly`
# License
MIT, which is unusual for me (usually i write LGPL) - this is inherited from a [CottonMC project](https://github.com/CottonMC/Templates), which inherited [the ElytraDev template](https://github.com/elytra/Concrete), which might explain if the readme layout looks familiar.
[^1]: Yes, even the blocks other than slopes use `templates:slope`. The slope was the first block added to Templates and I forgot to change the block entity ID, and now I can't change it without breaking worlds. At least it demonstrates how the block entity can be used for more than one template?

View File

@ -90,6 +90,7 @@ public class Templates implements ModInitializer {
SLOPE = registerTemplate("slope" , new TemplateSlopeBlock(TemplateInteractionUtil.makeSettings()));
TINY_SLOPE = registerTemplate("tiny_slope" , new TemplateSlopeBlock.Tiny(TemplateInteractionUtil.makeSettings()));
//The block entity is still called templates:slope; this is a bit of a legacy mistake.
TEMPLATE_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("slope"),
FabricBlockEntityTypeBuilder.create((pos, state) -> new TemplateEntity(TEMPLATE_BLOCK_ENTITY, pos, state), INTERNAL_TEMPLATES.toArray(new Block[0])).build(null)
);