diff --git a/CHANGELOG.md b/CHANGELOG.md index fa588de..8786110 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ Versions before 2.1.2 have been backfilled; I gotta be more on top of changelogs # next version (unreleased) +* Start sketching out a proper API, accessible through `TemplatesClientApi.getInstance()`. + * Not everything has been moved into the API package yet for ABI reasons. +* Code cleanups that hopefully didn't break ABI compat * 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. diff --git a/README.md b/README.md index b883067..b5b221b 100644 --- a/README.md +++ b/README.md @@ -54,25 +54,25 @@ The last piece of information is important because Templates tries hard to retai Pick a model implementation that suits your needs: -### `UnbakedAutoRetexturedModel` +### Auto retexturing * 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. -To construct, pass the ID of the JSON model you want to source quads from. +Construct with `TemplatesClientApi.getInstance().auto`. Pass the ID of the 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` +### Special texture-based retexturing * 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. -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. +Construct with `TemplatesClientApi.getInstance().json`. Pass the ID of the model you want to source quads from. All quads textured with the *special textures* `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.
Regarding texture variables: @@ -97,31 +97,31 @@ Sadly, many models don't specify *completely* separate textures for all six side (This one works better with multipart models.) -### `UnbakedMeshRetexturedModel` +### Mesh retexturing * 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`. -To construct, pass a `Supplier`. 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. +Construct with `TemplatesClientApi.getInstance().mesh`, passing a `Supplier`. 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. 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` you can also pass a `Function, Mesh>`; you will be provided with a `Function` that you can query for sprite information, including their UVs. (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 +### 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. +Templates doesn't actually care about the implementation of the UnbakedModel 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 -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`. +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 `TemplatesClientApi.getInstance().addTemplateModel`. 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. -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. +To assign the item model, since items don't have the "blockstate file" level of indirection, call `TemplatesClientApi.getInstance().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 diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java index 3453c18..04d4d69 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java @@ -1,17 +1,12 @@ package io.github.cottonmc.templates; +import io.github.cottonmc.templates.api.TemplatesClientApi; import io.github.cottonmc.templates.model.SlopeBaseMesh; -import io.github.cottonmc.templates.model.UnbakedAutoRetexturedModel; -import io.github.cottonmc.templates.model.UnbakedJsonRetexturedModel; -import io.github.cottonmc.templates.model.UnbakedMeshRetexturedModel; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; -import net.fabricmc.fabric.api.renderer.v1.Renderer; -import net.fabricmc.fabric.api.renderer.v1.RendererAccess; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.Block; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.RenderLayer; @@ -19,15 +14,106 @@ import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import net.minecraft.util.math.ChunkSectionPos; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ApiStatus; public class TemplatesClient implements ClientModInitializer { - //2.2 note: Yes, this wasn't final before, but it should have been. - //This field is considered public api by the way, feel free to use it instead of making your own copy. + @ApiStatus.Internal //2.2 - Please use the new TemplatesClientApi.getInstance() method. public static final TemplatesModelProvider provider = new TemplatesModelProvider(); + @ApiStatus.Internal //Please use TemplatesClientApi.getInstance() instead. + public static final TemplatesClientApiImpl API_IMPL = new TemplatesClientApiImpl(provider); + @Override public void onInitializeClient() { + privateInit(); //<- Stuff you shouldn't replicate in any addon mods ;) + + //all templates mustn't be on the SOLID layer because they are not opaque! + BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), Templates.INTERNAL_TEMPLATES.toArray(new Block[0])); + + //now, assign special item models + TemplatesClientApi api = TemplatesClientApi.getInstance(); + + api.addTemplateModel(Templates.id("button_special") , api.auto(new Identifier("block/button"))); + api.addTemplateModel(Templates.id("button_pressed_special") , api.auto(new Identifier("block/button_pressed"))); + api.addTemplateModel(Templates.id("one_candle_special") , api.auto(new Identifier("block/template_candle"))); + api.addTemplateModel(Templates.id("two_candles_special") , api.auto(new Identifier("block/template_two_candles"))); + api.addTemplateModel(Templates.id("three_candles_special") , api.auto(new Identifier("block/template_three_candles"))); + api.addTemplateModel(Templates.id("four_candles_special") , api.auto(new Identifier("block/template_four_candles"))); + api.addTemplateModel(Templates.id("carpet_special") , api.auto(new Identifier("block/carpet"))); + api.addTemplateModel(Templates.id("cube_special") , api.auto(new Identifier("block/cube"))); + api.addTemplateModel(Templates.id("door_bottom_left_special") , api.auto(new Identifier("block/door_bottom_left"))); + api.addTemplateModel(Templates.id("door_bottom_right_special") , api.auto(new Identifier("block/door_bottom_right"))); + api.addTemplateModel(Templates.id("door_top_left_special") , api.auto(new Identifier("block/door_top_left"))); + api.addTemplateModel(Templates.id("door_top_right_special") , api.auto(new Identifier("block/door_top_right"))); + api.addTemplateModel(Templates.id("door_bottom_left_open_special"), api.auto(new Identifier("block/door_bottom_left_open"))); + api.addTemplateModel(Templates.id("door_bottom_right_open_special"), api.auto(new Identifier("block/door_bottom_right_open"))); //This is why we dont format code as tables kids + api.addTemplateModel(Templates.id("door_top_left_open_special") , api.auto(new Identifier("block/door_top_left_open"))); + api.addTemplateModel(Templates.id("door_top_right_open_special") , api.auto(new Identifier("block/door_top_right_open"))); + api.addTemplateModel(Templates.id("fence_post_special") , api.auto(new Identifier("block/fence_post"))); + api.addTemplateModel(Templates.id("fence_gate_special") , api.auto(new Identifier("block/template_fence_gate"))); + api.addTemplateModel(Templates.id("fence_gate_open_special") , api.auto(new Identifier("block/template_fence_gate_open"))); + api.addTemplateModel(Templates.id("fence_gate_wall_special") , api.auto(new Identifier("block/template_fence_gate_wall"))); + api.addTemplateModel(Templates.id("fence_gate_wall_open_special") , api.auto(new Identifier("block/template_fence_gate_wall_open"))); + api.addTemplateModel(Templates.id("glass_pane_post_special") , api.auto(new Identifier("block/glass_pane_post"))); + api.addTemplateModel(Templates.id("glass_pane_noside_special") , api.auto(new Identifier("block/glass_pane_noside"))); + api.addTemplateModel(Templates.id("glass_pane_noside_alt_special"), api.auto(new Identifier("block/glass_pane_noside_alt"))); + api.addTemplateModel(Templates.id("pressure_plate_up_special") , api.auto(new Identifier("block/pressure_plate_up"))); + api.addTemplateModel(Templates.id("pressure_plate_down_special") , api.auto(new Identifier("block/pressure_plate_down"))); + api.addTemplateModel(Templates.id("slab_bottom_special") , api.auto(new Identifier("block/slab"))); + api.addTemplateModel(Templates.id("slab_top_special") , api.auto(new Identifier("block/slab_top"))); + api.addTemplateModel(Templates.id("stairs_special") , api.auto(new Identifier("block/stairs"))); + api.addTemplateModel(Templates.id("inner_stairs_special") , api.auto(new Identifier("block/inner_stairs"))); + api.addTemplateModel(Templates.id("outer_stairs_special") , api.auto(new Identifier("block/outer_stairs"))); + api.addTemplateModel(Templates.id("trapdoor_bottom_special") , api.auto(new Identifier("block/template_trapdoor_bottom"))); + api.addTemplateModel(Templates.id("trapdoor_top_special") , api.auto(new Identifier("block/template_trapdoor_top"))); + api.addTemplateModel(Templates.id("vertical_slab_special") , api.auto(Templates.id("block/vertical_slab"))); //my model not vanilla + api.addTemplateModel(Templates.id("wall_post_special") , api.auto(new Identifier("block/template_wall_post"))); + + //vanilla style models (using "special-sprite replacement" method) + api.addTemplateModel(Templates.id("lever_special") , api.json(Templates.id("block/lever"))); + api.addTemplateModel(Templates.id("trapdoor_open_special") , api.json(Templates.id("block/trapdoor_open"))); + api.addTemplateModel(Templates.id("lever_on_special") , api.json(Templates.id("block/lever_on"))); + //these next five only exist because AutoRetexturedModels don't seem to rotate their textures the right way when rotated from a multipart blockstate + api.addTemplateModel(Templates.id("fence_side_special") , api.json(Templates.id("block/fence_side"))); + api.addTemplateModel(Templates.id("glass_pane_side_special") , api.json(Templates.id("block/glass_pane_side"))); + api.addTemplateModel(Templates.id("glass_pane_side_alt_special") , api.json(Templates.id("block/glass_pane_side_alt"))); + api.addTemplateModel(Templates.id("wall_side_special") , api.json(Templates.id("block/wall_side"))); + api.addTemplateModel(Templates.id("wall_side_tall_special") , api.json(Templates.id("block/wall_side_tall"))); + + //mesh models + api.addTemplateModel(Templates.id("slope_special") , api.mesh(Templates.id("block/slope_base"), SlopeBaseMesh::makeUpright).disableAo()); + api.addTemplateModel(Templates.id("slope_side_special") , api.mesh(Templates.id("block/slope_base"), SlopeBaseMesh::makeSide).disableAo()); + api.addTemplateModel(Templates.id("tiny_slope_special") , api.mesh(Templates.id("block/tiny_slope_base"), SlopeBaseMesh::makeTinyUpright).disableAo()); + api.addTemplateModel(Templates.id("tiny_slope_side_special") , api.mesh(Templates.id("block/tiny_slope_base"), SlopeBaseMesh::makeTinySide).disableAo()); + + //item only models + api.addTemplateModel(Templates.id("button_inventory_special") , api.auto(new Identifier("block/button_inventory"))); + api.addTemplateModel(Templates.id("fence_inventory_special") , api.auto(new Identifier("block/fence_inventory"))); + api.addTemplateModel(Templates.id("fence_post_inventory_special") , api.auto(Templates.id("block/fence_post_inventory"))); + api.addTemplateModel(Templates.id("wall_inventory_special") , api.auto(new Identifier("block/wall_inventory"))); + + //item model assignments (in lieu of models/item/___.json) + api.assignItemModel(Templates.id("button_inventory_special") , Templates.BUTTON); + api.assignItemModel(Templates.id("carpet_special") , Templates.CARPET); + api.assignItemModel(Templates.id("cube_special") , Templates.CUBE); + api.assignItemModel(Templates.id("fence_inventory_special") , Templates.FENCE); + api.assignItemModel(Templates.id("fence_gate_special") , Templates.FENCE_GATE); + api.assignItemModel(Templates.id("trapdoor_bottom_special") , Templates.IRON_TRAPDOOR); + api.assignItemModel(Templates.id("fence_post_inventory_special") , Templates.POST); + api.assignItemModel(Templates.id("pressure_plate_up_special") , Templates.PRESSURE_PLATE); + api.assignItemModel(Templates.id("slab_bottom_special") , Templates.SLAB); + api.assignItemModel(Templates.id("stairs_special") , Templates.STAIRS); + api.assignItemModel(Templates.id("trapdoor_bottom_special") , Templates.TRAPDOOR); + api.assignItemModel(Templates.id("vertical_slab_special") , Templates.VERTICAL_SLAB); + api.assignItemModel(Templates.id("wall_inventory_special") , Templates.WALL); + api.assignItemModel(Templates.id("slope_special") , Templates.SLOPE); + api.assignItemModel(Templates.id("tiny_slope_special") , Templates.TINY_SLOPE); + + //TODO: i could stick some kind of entrypoint here for signalling other mods that it's ok to register now? + // Dont think it rly matters though, everything's all kept in nice hash maps + } + + private void privateInit() { //set up some magic to force chunk rerenders when you change a template (see TemplateEntity) Templates.chunkRerenderProxy = (world, pos) -> { if(world == MinecraftClient.getInstance().world) { @@ -47,101 +133,5 @@ public class TemplatesClient implements ClientModInitializer { @Override public Identifier getFabricId() { return Templates.id("dump-caches"); } @Override public void reload(ResourceManager blah) { provider.dumpCache(); } }); - - //all templates mustn't be on the SOLID layer because they are not opaque by default (!) - BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), Templates.INTERNAL_TEMPLATES.toArray(new Block[0])); - - //and a big wall of fancy models - provider.addTemplateModel(Templates.id("button_special") , new UnbakedAutoRetexturedModel(new Identifier("block/button"))); - provider.addTemplateModel(Templates.id("button_pressed_special") , new UnbakedAutoRetexturedModel(new Identifier("block/button_pressed"))); - provider.addTemplateModel(Templates.id("one_candle_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_candle"))); - provider.addTemplateModel(Templates.id("two_candles_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_two_candles"))); - provider.addTemplateModel(Templates.id("three_candles_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_three_candles"))); - provider.addTemplateModel(Templates.id("four_candles_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_four_candles"))); - provider.addTemplateModel(Templates.id("carpet_special") , new UnbakedAutoRetexturedModel(new Identifier("block/carpet"))); - provider.addTemplateModel(Templates.id("cube_special") , new UnbakedAutoRetexturedModel(new Identifier("block/cube"))); - provider.addTemplateModel(Templates.id("door_bottom_left_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_bottom_left"))); - provider.addTemplateModel(Templates.id("door_bottom_right_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_bottom_right"))); - provider.addTemplateModel(Templates.id("door_top_left_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_top_left"))); - provider.addTemplateModel(Templates.id("door_top_right_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_top_right"))); - provider.addTemplateModel(Templates.id("door_bottom_left_open_special"), new UnbakedAutoRetexturedModel(new Identifier("block/door_bottom_left_open"))); - provider.addTemplateModel(Templates.id("door_bottom_right_open_special"), new UnbakedAutoRetexturedModel(new Identifier("block/door_bottom_right_open"))); //This is why we dont format code as tables kids - provider.addTemplateModel(Templates.id("door_top_left_open_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_top_left_open"))); - provider.addTemplateModel(Templates.id("door_top_right_open_special") , new UnbakedAutoRetexturedModel(new Identifier("block/door_top_right_open"))); - provider.addTemplateModel(Templates.id("fence_post_special") , new UnbakedAutoRetexturedModel(new Identifier("block/fence_post"))); - provider.addTemplateModel(Templates.id("fence_gate_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_fence_gate"))); - provider.addTemplateModel(Templates.id("fence_gate_open_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_fence_gate_open"))); - provider.addTemplateModel(Templates.id("fence_gate_wall_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_fence_gate_wall"))); - provider.addTemplateModel(Templates.id("fence_gate_wall_open_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_fence_gate_wall_open"))); - provider.addTemplateModel(Templates.id("glass_pane_post_special") , new UnbakedAutoRetexturedModel(new Identifier("block/glass_pane_post"))); - provider.addTemplateModel(Templates.id("glass_pane_noside_special") , new UnbakedAutoRetexturedModel(new Identifier("block/glass_pane_noside"))); - provider.addTemplateModel(Templates.id("glass_pane_noside_alt_special"), new UnbakedAutoRetexturedModel(new Identifier("block/glass_pane_noside_alt"))); - provider.addTemplateModel(Templates.id("pressure_plate_up_special") , new UnbakedAutoRetexturedModel(new Identifier("block/pressure_plate_up"))); - provider.addTemplateModel(Templates.id("pressure_plate_down_special") , new UnbakedAutoRetexturedModel(new Identifier("block/pressure_plate_down"))); - provider.addTemplateModel(Templates.id("slab_bottom_special") , new UnbakedAutoRetexturedModel(new Identifier("block/slab"))); - provider.addTemplateModel(Templates.id("slab_top_special") , new UnbakedAutoRetexturedModel(new Identifier("block/slab_top"))); - provider.addTemplateModel(Templates.id("stairs_special") , new UnbakedAutoRetexturedModel(new Identifier("block/stairs"))); - provider.addTemplateModel(Templates.id("inner_stairs_special") , new UnbakedAutoRetexturedModel(new Identifier("block/inner_stairs"))); - provider.addTemplateModel(Templates.id("outer_stairs_special") , new UnbakedAutoRetexturedModel(new Identifier("block/outer_stairs"))); - provider.addTemplateModel(Templates.id("trapdoor_bottom_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_trapdoor_bottom"))); - provider.addTemplateModel(Templates.id("trapdoor_top_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_trapdoor_top"))); - provider.addTemplateModel(Templates.id("vertical_slab_special") , new UnbakedAutoRetexturedModel(Templates.id("block/vertical_slab"))); //my model not vanilla - provider.addTemplateModel(Templates.id("wall_post_special") , new UnbakedAutoRetexturedModel(new Identifier("block/template_wall_post"))); - - //vanilla style models (using "special-sprite replacement" method) - provider.addTemplateModel(Templates.id("lever_special") , new UnbakedJsonRetexturedModel(Templates.id("block/lever"))); - provider.addTemplateModel(Templates.id("trapdoor_open_special") , new UnbakedJsonRetexturedModel(Templates.id("block/trapdoor_open"))); - provider.addTemplateModel(Templates.id("lever_on_special") , new UnbakedJsonRetexturedModel(Templates.id("block/lever_on"))); - //these only exist because AutoRetexturedModels don't seem to rotate their textures the right way when rotated from a multipart blockstate - provider.addTemplateModel(Templates.id("fence_side_special") , new UnbakedJsonRetexturedModel(Templates.id("block/fence_side"))); - provider.addTemplateModel(Templates.id("glass_pane_side_special") , new UnbakedJsonRetexturedModel(Templates.id("block/glass_pane_side"))); - provider.addTemplateModel(Templates.id("glass_pane_side_alt_special") , new UnbakedAutoRetexturedModel(Templates.id("block/glass_pane_side_alt"))); - provider.addTemplateModel(Templates.id("wall_side_special") , new UnbakedJsonRetexturedModel(Templates.id("block/wall_side"))); - provider.addTemplateModel(Templates.id("wall_side_tall_special") , new UnbakedJsonRetexturedModel(Templates.id("block/wall_side_tall"))); - - //mesh models - provider.addTemplateModel(Templates.id("slope_special") , new UnbakedMeshRetexturedModel(Templates.id("block/slope_base"), SlopeBaseMesh::makeUpright).disableAo()); - provider.addTemplateModel(Templates.id("slope_side_special") , new UnbakedMeshRetexturedModel(Templates.id("block/slope_base"), SlopeBaseMesh::makeSide).disableAo()); - provider.addTemplateModel(Templates.id("tiny_slope_special") , new UnbakedMeshRetexturedModel(Templates.id("block/tiny_slope_base"), SlopeBaseMesh::makeTinyUpright).disableAo()); - provider.addTemplateModel(Templates.id("tiny_slope_side_special") , new UnbakedMeshRetexturedModel(Templates.id("block/tiny_slope_base"), SlopeBaseMesh::makeTinySide).disableAo()); - - //item only models - provider.addTemplateModel(Templates.id("button_inventory_special") , new UnbakedAutoRetexturedModel(new Identifier("block/button_inventory"))); - provider.addTemplateModel(Templates.id("fence_inventory_special") , new UnbakedAutoRetexturedModel(new Identifier("block/fence_inventory"))); - provider.addTemplateModel(Templates.id("fence_post_inventory_special") , new UnbakedAutoRetexturedModel(Templates.id("block/fence_post_inventory"))); - provider.addTemplateModel(Templates.id("wall_inventory_special") , new UnbakedAutoRetexturedModel(new Identifier("block/wall_inventory"))); - - //item model assignments (in lieu of models/item/___.json) - provider.assignItemModel(Templates.id("button_inventory_special") , Templates.BUTTON); - provider.assignItemModel(Templates.id("carpet_special") , Templates.CARPET); - provider.assignItemModel(Templates.id("cube_special") , Templates.CUBE); - provider.assignItemModel(Templates.id("fence_inventory_special") , Templates.FENCE); - provider.assignItemModel(Templates.id("fence_gate_special") , Templates.FENCE_GATE); - provider.assignItemModel(Templates.id("trapdoor_bottom_special") , Templates.IRON_TRAPDOOR); - provider.assignItemModel(Templates.id("fence_post_inventory_special") , Templates.POST); - provider.assignItemModel(Templates.id("pressure_plate_up_special") , Templates.PRESSURE_PLATE); - provider.assignItemModel(Templates.id("slab_bottom_special") , Templates.SLAB); - provider.assignItemModel(Templates.id("stairs_special") , Templates.STAIRS); - provider.assignItemModel(Templates.id("trapdoor_bottom_special") , Templates.TRAPDOOR); - provider.assignItemModel(Templates.id("vertical_slab_special") , Templates.VERTICAL_SLAB); - provider.assignItemModel(Templates.id("wall_inventory_special") , Templates.WALL); - - provider.assignItemModel(Templates.id("slope_special") , Templates.SLOPE); - provider.assignItemModel(Templates.id("tiny_slope_special") , Templates.TINY_SLOPE); - } - - public static @NotNull Renderer getFabricRenderer() { - Renderer obj = RendererAccess.INSTANCE.getRenderer(); - if(obj != null) return obj; - - //Welp, not much more we can do, this mod heavily relies on frapi - String msg = "A Fabric Rendering API implementation is required to use Templates 2!"; - - if(!FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo")) - msg += "\nI noticed you don't have Indigo installed, which is a part of the complete Fabric API package."; - if(FabricLoader.getInstance().isModLoaded("sodium")) - msg += "\nI noticed you have Sodium installed - consider also installing Indium to provide a compatible renderer implementation."; - - throw new NullPointerException(msg); } } diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClientApiImpl.java b/src/main/java/io/github/cottonmc/templates/TemplatesClientApiImpl.java new file mode 100644 index 0000000..6557a94 --- /dev/null +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClientApiImpl.java @@ -0,0 +1,84 @@ +package io.github.cottonmc.templates; + +import io.github.cottonmc.templates.api.TemplatesClientApi; +import io.github.cottonmc.templates.model.TemplateAppearanceManager; +import io.github.cottonmc.templates.model.UnbakedAutoRetexturedModel; +import io.github.cottonmc.templates.model.UnbakedJsonRetexturedModel; +import io.github.cottonmc.templates.model.UnbakedMeshRetexturedModel; +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.item.ItemConvertible; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; + +public class TemplatesClientApiImpl implements TemplatesClientApi { + public TemplatesClientApiImpl(TemplatesModelProvider prov) { + this.prov = prov; + } + + private final TemplatesModelProvider prov; + + @Override + public TweakableUnbakedModel auto(Identifier parent) { + return new UnbakedAutoRetexturedModel(parent); + } + + @Override + public TweakableUnbakedModel json(Identifier parent) { + return new UnbakedJsonRetexturedModel(parent); + } + + @Override + public TweakableUnbakedModel mesh(Identifier parent, Function, Mesh> baseMeshFactory) { + return new UnbakedMeshRetexturedModel(parent, baseMeshFactory); + } + + @Override + public void addTemplateModel(Identifier id, UnbakedModel unbaked) { + prov.addTemplateModel(id, unbaked); + } + + @Override + public void assignItemModel(Identifier templateModelId, ModelIdentifier... modelIds) { + prov.assignItemModel(templateModelId, modelIds); + } + + @Override + public void assignItemModel(Identifier templateModelId, Identifier... itemIds) { + prov.assignItemModel(templateModelId, itemIds); + } + + @Override + public void assignItemModel(Identifier templateModelId, ItemConvertible... itemConvs) { + prov.assignItemModel(templateModelId, itemConvs); + } + + @Override + public TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function spriteLookup) { + return prov.getOrCreateTemplateApperanceManager(spriteLookup); + } + + @Override + public @NotNull Renderer getFabricRenderer() { + Renderer obj = RendererAccess.INSTANCE.getRenderer(); + if(obj != null) return obj; + + //Welp, not much more we can do, this mod heavily relies on frapi + String msg = "A Fabric Rendering API implementation is required to use Templates 2!"; + + if(!FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo")) + msg += "\nI noticed you don't have Indigo installed, which is a part of the complete Fabric API package."; + if(FabricLoader.getInstance().isModLoaded("sodium")) + msg += "\nI noticed you have Sodium installed - consider also installing Indium to provide a compatible renderer implementation."; + + throw new NullPointerException(msg); + } +} diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java index 90dbf2b..3e46028 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java @@ -18,7 +18,6 @@ import java.util.Map; import java.util.Objects; import java.util.function.Function; -@SuppressWarnings("unused") //this class is part of the api public class TemplatesModelProvider implements ModelResourceProvider, ModelVariantProvider { private final Map models = new HashMap<>(); private final Map itemAssignments = new HashMap<>(); @@ -74,10 +73,8 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria appearanceManager = null; //volatile write } - /// "public api" - - public void addTemplateModel(Identifier id, UnbakedModel modelFactory) { - models.put(id, modelFactory); + public void addTemplateModel(Identifier id, UnbakedModel unbaked) { + models.put(id, unbaked); } public void assignItemModel(Identifier templateModelId, ModelIdentifier... modelIds) { diff --git a/src/main/java/io/github/cottonmc/templates/api/TemplatesClientApi.java b/src/main/java/io/github/cottonmc/templates/api/TemplatesClientApi.java new file mode 100644 index 0000000..cce64ee --- /dev/null +++ b/src/main/java/io/github/cottonmc/templates/api/TemplatesClientApi.java @@ -0,0 +1,116 @@ +package io.github.cottonmc.templates.api; + +import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.model.TemplateAppearanceManager; +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.item.ItemConvertible; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Function; +import java.util.function.Supplier; + +@ApiStatus.AvailableSince("2.2") +@SuppressWarnings({"unused", "UnusedReturnValue"}) //this is all public api +public interface TemplatesClientApi { + /** + * Obtain the current API instance. + */ + static TemplatesClientApi getInstance() { + return TemplatesClient.API_IMPL; + } + + /// CONSTRUCTING UNBAKED MODELS /// + + /** + * - the quad: Sourced from the ID you pass in. It can be 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. + */ + TweakableUnbakedModel auto(Identifier parent); + + /** + * - the quad: Sourced from the ID you pass in. It can be 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. + */ + TweakableUnbakedModel json(Identifier parent); + + /** + * - 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`. + *

+ * This form doesn't give the ability to look up sprites, so it's hard to make a sensible quad that won't be retextured. + */ + default TweakableUnbakedModel mesh(Identifier parent, Supplier baseMeshFactory) { + return mesh(parent, __ -> baseMeshFactory.get()); + } + + /** + * - 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`. + *

+ * You can use the provided Function to look up sprite UVs and put them on faces with a 0 tag. + * These faces will not get retextured. + */ + TweakableUnbakedModel mesh(Identifier parent, Function, Mesh> baseMeshFactory); + + /** + * Get the TemplateAppearanceManager instance. To retexture a template, there has to be some way of determining what texture should + * go on the top, what texture should go on the north side, and the TemplateAppearanceManager is in charge of gleaning this information + * from the target blockmodels. It also caches this information. + *

+ * There is one TemplateApperanceManager per resource-load. Please obtain a new one every model bake. + * + * @param spriteLookup Something you'll find as part of UnbakedModel#bake. + */ + TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function spriteLookup); + + /// REGISTERING UNBAKED MODELS /// + + /** + * Register an UnbakedModel to be loaded behind a particular ID. + * Astute viewers will note that this is, *currently*, a thin wrapper around the fabric ModelResourceProvider system. + */ + void addTemplateModel(Identifier id, UnbakedModel unbaked); + + /** + * When the game loads this ModelIdentifier, it will instead load the UnbakedModel corresponding to the id passed to addTemplateModel. + * Astute viewers will note that this is, *currently*, a thin wrapper around the fabric ModelVariantProvider system. + */ + void assignItemModel(Identifier templateModelId, ModelIdentifier... modelIds); + + /** + * Calls assignItemModel(Identifier, ModelIdentifier) with "#inventory" appended. + * In practice: you can pass an item's ID. + */ + void assignItemModel(Identifier templateModelId, Identifier... itemIds); + + /** + * Calls assignItemModel(Identifier, Identifier) by first converting the argument to an item, then taking its ID. + * In practice: you can pass a Block (or Item), and the model will be assigned to the block's item form. + */ + void assignItemModel(Identifier templateModelId, ItemConvertible... itemConvs); + + /// OTHER STUFF LOL /// + + /** + * Simple wrapper around fabric's RenderAccess.INSTANCE.getRenderer() that throws a slightly more informative error if one is not + * present. Note that NullPointerException is not a checked exception. + */ + @NotNull Renderer getFabricRenderer() throws NullPointerException; + + interface TweakableUnbakedModel extends UnbakedModel { + TweakableUnbakedModel disableAo(); + TweakableUnbakedModel itemModelState(BlockState state); + } +} diff --git a/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java b/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java index fad2796..a431626 100644 --- a/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java +++ b/src/main/java/io/github/cottonmc/templates/model/MeshTransformUtil.java @@ -1,6 +1,6 @@ package io.github.cottonmc.templates.model; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; @@ -16,7 +16,7 @@ import java.util.Map; public class MeshTransformUtil { public static Mesh pretransformMesh(Mesh mesh, RenderContext.QuadTransform transform) { - MeshBuilder builder = TemplatesClient.getFabricRenderer().meshBuilder(); + MeshBuilder builder = TemplatesClientApi.getInstance().getFabricRenderer().meshBuilder(); QuadEmitter emitter = builder.getEmitter(); mesh.forEach(quad -> { diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java index 3439f49..330841d 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeBaseMesh.java @@ -1,6 +1,6 @@ package io.github.cottonmc.templates.model; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; @@ -20,7 +20,7 @@ public class SlopeBaseMesh { public static final int TAG_BOTTOM = Direction.DOWN.ordinal() + 1; public static Mesh makeUpright() { - Renderer renderer = TemplatesClient.getFabricRenderer(); + Renderer renderer = TemplatesClientApi.getInstance().getFabricRenderer(); MeshBuilder builder = renderer.meshBuilder(); QuadEmitter qu = builder.getEmitter(); qu.tag(TAG_SLOPE) @@ -63,7 +63,7 @@ public class SlopeBaseMesh { //looks weird since i wrote a janky script to massage a .bbmodel, some manual fixups applied public static Mesh makeTinyUpright() { - Renderer renderer = TemplatesClient.getFabricRenderer(); + Renderer renderer = TemplatesClientApi.getInstance().getFabricRenderer(); MeshBuilder builder = renderer.meshBuilder(); QuadEmitter qu = builder.getEmitter(); qu.tag(TAG_LEFT) diff --git a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java index aa150f6..9a55ed3 100644 --- a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java +++ b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearance.java @@ -5,6 +5,7 @@ import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; import org.jetbrains.annotations.NotNull; +//TODO: move to the api package public interface TemplateAppearance { @NotNull Sprite getParticleSprite(); //TODO: plug this in (particle mixins don't use it atm) diff --git a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java index a05c555..4dc1e22 100644 --- a/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java +++ b/src/main/java/io/github/cottonmc/templates/model/TemplateAppearanceManager.java @@ -1,6 +1,7 @@ package io.github.cottonmc.templates.model; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; +import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; @@ -30,9 +31,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +//TODO: extract an API for the api package public class TemplateAppearanceManager { public TemplateAppearanceManager(Function spriteLookup) { - MaterialFinder finder = TemplatesClient.getFabricRenderer().materialFinder(); + MaterialFinder finder = TemplatesClientApi.getInstance().getFabricRenderer().materialFinder(); for(BlendMode blend : BlendMode.values()) { finder.clear().disableDiffuse(false).blendMode(blend); @@ -86,8 +88,9 @@ public class TemplateAppearanceManager { BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state); //Only for parsing vanilla quads: - QuadEmitter emitter = TemplatesClient.getFabricRenderer().meshBuilder().getEmitter(); - RenderMaterial defaultMat = TemplatesClient.getFabricRenderer().materialFinder().clear().find(); + Renderer r = TemplatesClientApi.getInstance().getFabricRenderer(); + QuadEmitter emitter = r.meshBuilder().getEmitter(); + RenderMaterial defaultMat = r.materialFinder().clear().find(); Sprite[] sprites = new Sprite[7]; int[] bakeFlags = new int[6]; diff --git a/src/main/java/io/github/cottonmc/templates/model/UnbakedAutoRetexturedModel.java b/src/main/java/io/github/cottonmc/templates/model/UnbakedAutoRetexturedModel.java index 5d42691..277b4de 100644 --- a/src/main/java/io/github/cottonmc/templates/model/UnbakedAutoRetexturedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/UnbakedAutoRetexturedModel.java @@ -1,6 +1,6 @@ package io.github.cottonmc.templates.model; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; @@ -26,25 +26,31 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; -public class UnbakedAutoRetexturedModel implements UnbakedModel { +public class UnbakedAutoRetexturedModel implements UnbakedModel, TemplatesClientApi.TweakableUnbakedModel { public UnbakedAutoRetexturedModel(Identifier parent) { - this(parent, Blocks.AIR.getDefaultState()); - } - - public UnbakedAutoRetexturedModel(Identifier parent, BlockState itemModelState) { this.parent = parent; - this.itemModelState = itemModelState; } protected final Identifier parent; - protected final BlockState itemModelState; - + protected BlockState itemModelState = Blocks.AIR.getDefaultState(); protected boolean ao = true; + + /// user configuration + + @Override public UnbakedAutoRetexturedModel disableAo() { ao = false; return this; } + @Override + public TemplatesClientApi.TweakableUnbakedModel itemModelState(BlockState state) { + this.itemModelState = state; + return this; + } + + /// actual unbakedmodel stuff + @Override public Collection getModelDependencies() { return Collections.singletonList(parent); @@ -58,15 +64,15 @@ public class UnbakedAutoRetexturedModel implements UnbakedModel { @Nullable @Override public BakedModel bake(Baker baker, Function spriteLookup, ModelBakeSettings modelBakeSettings, Identifier identifier) { - ConcurrentMap jsonToMesh = new ConcurrentHashMap<>(); - return new RetexturingBakedModel( baker.bake(parent, modelBakeSettings), - TemplatesClient.provider.getOrCreateTemplateApperanceManager(spriteLookup), + TemplatesClientApi.getInstance().getOrCreateTemplateApperanceManager(spriteLookup), modelBakeSettings, itemModelState, ao ) { + final ConcurrentMap jsonToMesh = new ConcurrentHashMap<>(); + @Override protected Mesh getBaseMesh(BlockState state) { //Convert models to retexturable Meshes lazily, the first time we encounter each blockstate @@ -74,7 +80,7 @@ public class UnbakedAutoRetexturedModel implements UnbakedModel { } private Mesh convertModel(BlockState state) { - Renderer r = TemplatesClient.getFabricRenderer(); + Renderer r = TemplatesClientApi.getInstance().getFabricRenderer(); MeshBuilder builder = r.meshBuilder(); QuadEmitter emitter = builder.getEmitter(); RenderMaterial mat = tam.getCachedMaterial(state, false); @@ -94,4 +100,11 @@ public class UnbakedAutoRetexturedModel implements UnbakedModel { } }; } + + //ABI compat. + @Deprecated(forRemoval = true) //2.2 - use TemplatesClientApi.getInstance().auto, and use the builder to set this field + public UnbakedAutoRetexturedModel(Identifier parent, BlockState itemModelState) { + this(parent); + itemModelState(itemModelState); + } } diff --git a/src/main/java/io/github/cottonmc/templates/model/UnbakedJsonRetexturedModel.java b/src/main/java/io/github/cottonmc/templates/model/UnbakedJsonRetexturedModel.java index dd0c782..9b42e44 100644 --- a/src/main/java/io/github/cottonmc/templates/model/UnbakedJsonRetexturedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/UnbakedJsonRetexturedModel.java @@ -1,14 +1,13 @@ package io.github.cottonmc.templates.model; import io.github.cottonmc.templates.Templates; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.render.model.Baker; @@ -29,25 +28,31 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; -public class UnbakedJsonRetexturedModel implements UnbakedModel { +public class UnbakedJsonRetexturedModel implements UnbakedModel, TemplatesClientApi.TweakableUnbakedModel { public UnbakedJsonRetexturedModel(Identifier parent) { - this(parent, Blocks.AIR.getDefaultState()); - } - - public UnbakedJsonRetexturedModel(Identifier parent, BlockState itemModelState) { this.parent = parent; - this.itemModelState = itemModelState; } protected final Identifier parent; - protected final BlockState itemModelState; - + protected BlockState itemModelState; protected boolean ao = true; + + /// user configuration + + @Override public UnbakedJsonRetexturedModel disableAo() { ao = false; return this; } + @Override + public TemplatesClientApi.TweakableUnbakedModel itemModelState(BlockState state) { + this.itemModelState = state; + return this; + } + + /// actual unbakedmodel stuff + @Override public Collection getModelDependencies() { return Collections.singletonList(parent); @@ -69,15 +74,15 @@ public class UnbakedJsonRetexturedModel implements UnbakedModel { specialSprites[i] = Objects.requireNonNull(spriteLookup.apply(id), () -> "Couldn't find sprite " + id + " !"); } - ConcurrentMap jsonToMesh = new ConcurrentHashMap<>(); - return new RetexturingBakedModel( baker.bake(parent, modelBakeSettings), - TemplatesClient.provider.getOrCreateTemplateApperanceManager(spriteLookup), + TemplatesClientApi.getInstance().getOrCreateTemplateApperanceManager(spriteLookup), modelBakeSettings, itemModelState, ao ) { + final ConcurrentMap jsonToMesh = new ConcurrentHashMap<>(); + @Override protected Mesh getBaseMesh(BlockState state) { //Convert models to retexturable Meshes lazily, the first time we encounter each blockstate @@ -85,7 +90,7 @@ public class UnbakedJsonRetexturedModel implements UnbakedModel { } private Mesh convertModel(BlockState state) { - Renderer r = TemplatesClient.getFabricRenderer(); + Renderer r = TemplatesClientApi.getInstance().getFabricRenderer(); MeshBuilder builder = r.meshBuilder(); QuadEmitter emitter = builder.getEmitter(); RenderMaterial mat = tam.getCachedMaterial(state, false); @@ -113,4 +118,11 @@ public class UnbakedJsonRetexturedModel implements UnbakedModel { } }; } + + //ABI compat + @Deprecated(forRemoval = true) //2.2 - use TemplatesClientApi.getInstance().json, and use the builder to set this field + public UnbakedJsonRetexturedModel(Identifier parent, BlockState itemModelState) { + this(parent); + itemModelState(itemModelState); + } } diff --git a/src/main/java/io/github/cottonmc/templates/model/UnbakedMeshRetexturedModel.java b/src/main/java/io/github/cottonmc/templates/model/UnbakedMeshRetexturedModel.java index df0fc48..6dd0693 100644 --- a/src/main/java/io/github/cottonmc/templates/model/UnbakedMeshRetexturedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/UnbakedMeshRetexturedModel.java @@ -1,6 +1,6 @@ package io.github.cottonmc.templates.model; -import io.github.cottonmc.templates.TemplatesClient; +import io.github.cottonmc.templates.api.TemplatesClientApi; import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -17,11 +17,7 @@ import java.util.Collections; import java.util.function.Function; import java.util.function.Supplier; -public class UnbakedMeshRetexturedModel implements UnbakedModel { - public UnbakedMeshRetexturedModel(Identifier parent, Supplier baseMeshFactory) { - this(parent, __ -> baseMeshFactory.get()); - } - +public class UnbakedMeshRetexturedModel implements UnbakedModel, TemplatesClientApi.TweakableUnbakedModel { public UnbakedMeshRetexturedModel(Identifier parent, Function, Mesh> baseMeshFactory) { this.parent = parent; this.baseMeshFactory = baseMeshFactory; @@ -29,13 +25,23 @@ public class UnbakedMeshRetexturedModel implements UnbakedModel { protected final Identifier parent; protected final Function, Mesh> baseMeshFactory; - protected boolean ao = true; + + /// user configuration + + @Override public UnbakedMeshRetexturedModel disableAo() { ao = false; return this; } + @Override + public TemplatesClientApi.TweakableUnbakedModel itemModelState(BlockState state) { + throw new UnsupportedOperationException("UnbakedMeshRetexturedModel does not need an item model state set; it uses meshes"); + } + + /// actual unbakedmodel stuff + @Override public Collection getModelDependencies() { return Collections.singletonList(parent); @@ -52,7 +58,7 @@ public class UnbakedMeshRetexturedModel implements UnbakedModel { return new RetexturingBakedModel( baker.bake(parent, modelBakeSettings), - TemplatesClient.provider.getOrCreateTemplateApperanceManager(spriteLookup), + TemplatesClientApi.getInstance().getOrCreateTemplateApperanceManager(spriteLookup), modelBakeSettings, Blocks.AIR.getDefaultState(), ao @@ -63,4 +69,10 @@ public class UnbakedMeshRetexturedModel implements UnbakedModel { } }; } + + //ABI compat + @Deprecated(forRemoval = true) //2.2 - use TemplatesClientApi.getInstance().mesh + public UnbakedMeshRetexturedModel(Identifier parent, Supplier baseMeshFactory) { + this(parent, __ -> baseMeshFactory.get()); + } }