From a160f68ffc6e1af1789db0f300164f5112cba73a Mon Sep 17 00:00:00 2001 From: quat1024 Date: Thu, 31 Aug 2023 22:47:50 -0400 Subject: [PATCH] way better block registration, more comments --- .../github/cottonmc/templates/Templates.java | 214 +++++++----------- .../cottonmc/templates/TemplatesClient.java | 80 +++---- .../templates/TemplatesModelProvider.java | 9 +- .../api/TemplateInteractionUtil.java | 13 +- .../templates/mixin/MinecraftAccessor.java | 1 + .../templates/mixin/WallBlockAccessor.java | 1 + .../particles/MixinBlockDustParticle.java | 3 +- 7 files changed, 122 insertions(+), 199 deletions(-) diff --git a/src/main/java/io/github/cottonmc/templates/Templates.java b/src/main/java/io/github/cottonmc/templates/Templates.java index 53f4a3e..dc1f135 100644 --- a/src/main/java/io/github/cottonmc/templates/Templates.java +++ b/src/main/java/io/github/cottonmc/templates/Templates.java @@ -25,14 +25,12 @@ import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityT import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockSetType; -import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.GlazedTerracottaBlock; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; @@ -42,158 +40,98 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockView; import net.minecraft.world.World; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; +import java.util.stream.Collectors; public class Templates implements ModInitializer { public static final String MODID = "templates"; + //addon devs: *Don't* add your blocks to this collection, it's just for my registration convenience since Templates adds a lot of blocks... + @ApiStatus.Internal static final ArrayList INTERNAL_TEMPLATES = new ArrayList<>(); + @ApiStatus.Internal static Block CUBE, STAIRS, SLAB, VERTICAL_SLAB, POST, FENCE, FENCE_GATE, DOOR, TRAPDOOR, IRON_DOOR, IRON_TRAPDOOR, PRESSURE_PLATE, BUTTON, LEVER, WALL, CARPET, PANE, CANDLE, SLOPE, TINY_SLOPE, COOL_RIVULET; + + //For addon devs: Please don't stuff more blocks into this BlockEntityType, and register your own. + //You can even re-register the same TemplateEntity class under your own ID if you like. (It's an extensible block entity.) + @ApiStatus.Internal public static BlockEntityType TEMPLATE_BLOCK_ENTITY; + + //Changed in TemplatesClient (which is safe since client initializers load after common initializers) + @ApiStatus.Internal public static BiConsumer chunkRerenderProxy = (world, pos) -> {}; + + @Override + public void onInitialize() { + //registerTemplate mutates MY_TEMPLATES as a side effect, which is a List, so order is preserved + //the ordering is used in the creative tab, so they're roughly sorted by encounter order of the + //corresponding vanilla block in the "search" creative tab... with the non-vanilla "post" and + //"vertical slab" inserted where they fit ...and i moved the lever way up next to the pressureplate + //and button, cause theyre redstoney... hopefully this ordering makes sense lol + CUBE = registerTemplate("cube" , new TemplateBlock(TemplateInteractionUtil.makeSettings())); + STAIRS = registerTemplate("stairs" , new TemplateStairsBlock(cp(Blocks.OAK_STAIRS))); + SLAB = registerTemplate("slab" , new TemplateSlabBlock(cp(Blocks.OAK_SLAB))); + VERTICAL_SLAB = registerTemplate("vertical_slab" , new TemplateVerticalSlabBlock(cp(Blocks.OAK_SLAB))); + POST = registerTemplate("post" , new TemplatePostBlock(cp(Blocks.OAK_FENCE))); + FENCE = registerTemplate("fence" , new TemplateFenceBlock(cp(Blocks.OAK_FENCE))); + FENCE_GATE = registerTemplate("fence_gate" , new TemplateFenceGateBlock(cp(Blocks.OAK_FENCE_GATE))); + DOOR = registerTemplate("door" , new TemplateDoorBlock(cp(Blocks.OAK_DOOR), BlockSetType.OAK)); + TRAPDOOR = registerTemplate("trapdoor" , new TemplateTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR), BlockSetType.OAK)); + IRON_DOOR = registerTemplate("iron_door" , new TemplateDoorBlock(cp(Blocks.IRON_DOOR), BlockSetType.IRON)); + IRON_TRAPDOOR = registerTemplate("iron_trapdoor" , new TemplateTrapdoorBlock(cp(Blocks.IRON_TRAPDOOR), BlockSetType.IRON)); + PRESSURE_PLATE = registerTemplate("pressure_plate", new TemplatePressurePlateBlock(cp(Blocks.OAK_PRESSURE_PLATE))); + BUTTON = registerTemplate("button" , new TemplateButtonBlock(cp(Blocks.OAK_BUTTON))); + LEVER = registerTemplate("lever" , new TemplateLeverBlock(cp(Blocks.LEVER))); + WALL = registerTemplate("wall" , new TemplateWallBlock(TemplateInteractionUtil.makeSettings())); + CARPET = registerTemplate("carpet" , new TemplateCarpetBlock(cp(Blocks.WHITE_CARPET))); + PANE = registerTemplate("pane" , new TemplatePaneBlock(cp(Blocks.GLASS_PANE))); + CANDLE = registerTemplate("candle" , new TemplateCandleBlock(TemplateCandleBlock.configureSettings(cp(Blocks.CANDLE)))); + SLOPE = registerTemplate("slope" , new TemplateSlopeBlock(TemplateInteractionUtil.makeSettings())); + TINY_SLOPE = registerTemplate("tiny_slope" , new TemplateSlopeBlock.Tiny(TemplateInteractionUtil.makeSettings())); + + 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) + ); + + //hey guys rate my registration code + Registry.register(Registries.ITEM, id("cool_rivulet"), new BlockItem( + COOL_RIVULET = Registry.register(Registries.BLOCK, id("cool_rivulet"), new GlazedTerracottaBlock( + AbstractBlock.Settings.create().hardness(0.2f)) { + @Override + public void appendTooltip(ItemStack stack, @Nullable BlockView world, List tooltip, TooltipContext eggbals) { + tooltip.add(Text.translatable("block.templates.cool_rivulet").formatted(Formatting.GRAY)); + } + }), + new Item.Settings() + )); + + Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder() + .displayName(Text.translatable("itemGroup.templates.tab")) + .icon(() -> new ItemStack(SLOPE)) + .entries((ctx, e) -> { + e.addAll(INTERNAL_TEMPLATES.stream().map(ItemStack::new).collect(Collectors.toList())); + e.add(COOL_RIVULET); + }).build() + ); + } + + //purely to shorten this call :p private static AbstractBlock.Settings cp(Block base) { return TemplateInteractionUtil.configureSettings(AbstractBlock.Settings.copy(base)); } - //vanilla, or at least vanilla-like, templates: - public static final Block BUTTON = Registry.register(Registries.BLOCK, id("button") , new TemplateButtonBlock(cp(Blocks.OAK_BUTTON))); - public static final Block CANDLE = Registry.register(Registries.BLOCK, id("candle") , new TemplateCandleBlock(TemplateCandleBlock.configureSettings(cp(Blocks.CANDLE)))); - public static final Block CARPET = Registry.register(Registries.BLOCK, id("carpet") , new TemplateCarpetBlock(cp(Blocks.WHITE_CARPET))); - public static final Block CUBE = Registry.register(Registries.BLOCK, id("cube") , new TemplateBlock(TemplateInteractionUtil.makeSettings())); - public static final Block DOOR = Registry.register(Registries.BLOCK, id("door") , new TemplateDoorBlock(cp(Blocks.OAK_DOOR), BlockSetType.OAK)); - public static final Block FENCE = Registry.register(Registries.BLOCK, id("fence") , new TemplateFenceBlock(cp(Blocks.OAK_FENCE))); - public static final Block FENCE_GATE = Registry.register(Registries.BLOCK, id("fence_gate") , new TemplateFenceGateBlock(cp(Blocks.OAK_FENCE_GATE))); - public static final Block IRON_DOOR = Registry.register(Registries.BLOCK, id("iron_door") , new TemplateDoorBlock(cp(Blocks.IRON_DOOR), BlockSetType.IRON)); - public static final Block IRON_TRAPDOOR = Registry.register(Registries.BLOCK, id("iron_trapdoor") , new TemplateTrapdoorBlock(cp(Blocks.IRON_TRAPDOOR), BlockSetType.IRON)); - public static final Block LEVER = Registry.register(Registries.BLOCK, id("lever") , new TemplateLeverBlock(cp(Blocks.LEVER))); - public static final Block PANE = Registry.register(Registries.BLOCK, id("pane") , new TemplatePaneBlock(cp(Blocks.GLASS_PANE))); - public static final Block POST = Registry.register(Registries.BLOCK, id("post") , new TemplatePostBlock(cp(Blocks.OAK_FENCE))); - public static final Block PRESSURE_PLATE = Registry.register(Registries.BLOCK, id("pressure_plate"), new TemplatePressurePlateBlock(cp(Blocks.OAK_PRESSURE_PLATE))); - public static final Block SLAB = Registry.register(Registries.BLOCK, id("slab") , new TemplateSlabBlock(cp(Blocks.OAK_SLAB))); - public static final Block STAIRS = Registry.register(Registries.BLOCK, id("stairs") , new TemplateStairsBlock(cp(Blocks.OAK_STAIRS))); - public static final Block TRAPDOOR = Registry.register(Registries.BLOCK, id("trapdoor") , new TemplateTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR), BlockSetType.OAK)); - public static final Block VERTICAL_SLAB = Registry.register(Registries.BLOCK, id("vertical_slab") , new TemplateVerticalSlabBlock(cp(Blocks.OAK_SLAB))); - public static final Block WALL = Registry.register(Registries.BLOCK, id("wall") , new TemplateWallBlock(TemplateInteractionUtil.makeSettings())); - - //oddball templates: - public static final Block SLOPE = Registry.register(Registries.BLOCK, id("slope") , new TemplateSlopeBlock(TemplateInteractionUtil.makeSettings())); - public static final Block TINY_SLOPE = Registry.register(Registries.BLOCK, id("tiny_slope") , new TemplateSlopeBlock.Tiny(TemplateInteractionUtil.makeSettings())); - //30 degree slope (shallow/deep) - //corner slopes - //quarter slabs???? - - //Very good - public static final Block COOL_RIVULET = Registry.register(Registries.BLOCK, id("cool_rivulet"), new GlazedTerracottaBlock(AbstractBlock.Settings.create().hardness(0.2f)) { - @Override - public void appendTooltip(ItemStack stack, @Nullable BlockView world, List tooltip, TooltipContext eggbals) { - tooltip.add(Text.translatable("block.templates.cool_rivulet").formatted(Formatting.GRAY)); - } - }); - - //For addon devs: Just make your own BlockEntityType instead of trying to add more blocks to this one. - //You can even re-register the same TemplateEntity class if you like. It's an extensible block entity. - public static final BlockEntityType TEMPLATE_BLOCK_ENTITY = Registry.register( - Registries.BLOCK_ENTITY_TYPE, id("slope"), - FabricBlockEntityTypeBuilder.create(Templates::makeTemplateBlockEntity, - BUTTON, - CANDLE, - CARPET, - CUBE, - DOOR, - FENCE, - FENCE_GATE, - IRON_DOOR, - IRON_TRAPDOOR, - LEVER, - PANE, - POST, - PRESSURE_PLATE, - SLAB, - STAIRS, - TRAPDOOR, - VERTICAL_SLAB, - WALL, - SLOPE, - TINY_SLOPE - ).build(null) - ); - - //Overridden in TemplatesClient - public static BiConsumer chunkRerenderProxy = (world, pos) -> {}; - - @Override - public void onInitialize() { - Registry.register( - Registries.ITEM_GROUP, id("tab"), - FabricItemGroup.builder() - .displayName(Text.translatable("itemGroup.templates.tab")) - .icon(() -> new ItemStack(SLOPE)) - .entries(this::fillCreativeTab) - .build() - ); + private static B registerTemplate(String path, B block) { + Identifier id = id(path); - Registry.register(Registries.ITEM, id("button") , new BlockItem(BUTTON, new Item.Settings())); - Registry.register(Registries.ITEM, id("candle") , new BlockItem(CANDLE, new Item.Settings())); - Registry.register(Registries.ITEM, id("carpet") , new BlockItem(CARPET, new Item.Settings())); - Registry.register(Registries.ITEM, id("cube") , new BlockItem(CUBE, new Item.Settings())); - Registry.register(Registries.ITEM, id("door") , new BlockItem(DOOR, new Item.Settings())); - Registry.register(Registries.ITEM, id("fence") , new BlockItem(FENCE, new Item.Settings())); - Registry.register(Registries.ITEM, id("fence_gate") , new BlockItem(FENCE_GATE, new Item.Settings())); - Registry.register(Registries.ITEM, id("iron_door") , new BlockItem(IRON_DOOR, new Item.Settings())); - Registry.register(Registries.ITEM, id("iron_trapdoor") , new BlockItem(IRON_TRAPDOOR, new Item.Settings())); - Registry.register(Registries.ITEM, id("lever") , new BlockItem(LEVER, new Item.Settings())); - Registry.register(Registries.ITEM, id("pane") , new BlockItem(PANE, new Item.Settings())); - Registry.register(Registries.ITEM, id("post") , new BlockItem(POST, new Item.Settings())); - Registry.register(Registries.ITEM, id("pressure_plate"), new BlockItem(PRESSURE_PLATE, new Item.Settings())); - Registry.register(Registries.ITEM, id("slab") , new BlockItem(SLAB, new Item.Settings())); - Registry.register(Registries.ITEM, id("stairs") , new BlockItem(STAIRS, new Item.Settings())); - Registry.register(Registries.ITEM, id("trapdoor") , new BlockItem(TRAPDOOR, new Item.Settings())); - Registry.register(Registries.ITEM, id("vertical_slab") , new BlockItem(VERTICAL_SLAB, new Item.Settings())); - Registry.register(Registries.ITEM, id("wall") , new BlockItem(WALL, new Item.Settings())); - - Registry.register(Registries.ITEM, id("slope") , new BlockItem(SLOPE, new Item.Settings())); - Registry.register(Registries.ITEM, id("tiny_slope") , new BlockItem(TINY_SLOPE, new Item.Settings())); - - Registry.register(Registries.ITEM, id("cool_rivulet") , new BlockItem(COOL_RIVULET, new Item.Settings())); //Very good + Registry.register(Registries.BLOCK, id, block); + Registry.register(Registries.ITEM, id, new BlockItem(block, new Item.Settings())); + INTERNAL_TEMPLATES.add(block); + return block; } + @ApiStatus.Internal public static Identifier id(String path) { return new Identifier(MODID, path); } - - //simply for breaking circular reference in the registration call - private static TemplateEntity makeTemplateBlockEntity(BlockPos pos, BlockState state) { - return new TemplateEntity(TEMPLATE_BLOCK_ENTITY, pos, state); - } - - private void fillCreativeTab(ItemGroup.DisplayContext ctx, ItemGroup.Entries e) { - //sorted by encounter order of the vanilla block in the "search" creative tab - //with the non-vanilla "post" and "vertical slab" inserted where they fit - //...and i moved the lever way up next to the pressureplate and button, cause theyre redstoney... - //hopefully this ordering makes sense lol - e.add(CUBE); - e.add(STAIRS); - e.add(SLAB); - e.add(VERTICAL_SLAB); - e.add(POST); - e.add(FENCE); - e.add(FENCE_GATE); - e.add(DOOR); - e.add(TRAPDOOR); - e.add(IRON_DOOR); - e.add(IRON_TRAPDOOR); - e.add(PRESSURE_PLATE); - e.add(BUTTON); - e.add(LEVER); - e.add(WALL); - e.add(CARPET); - e.add(PANE); - e.add(CANDLE); - - //Oddball that doesn't look anything like vanilla blocks - e.add(SLOPE); - e.add(TINY_SLOPE); - - //Very good - e.add(COOL_RIVULET); - } } diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java index ca03217..3453c18 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesClient.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesClient.java @@ -12,6 +12,7 @@ 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; import net.minecraft.resource.ResourceManager; @@ -21,26 +22,13 @@ import net.minecraft.util.math.ChunkSectionPos; import org.jetbrains.annotations.NotNull; public class TemplatesClient implements ClientModInitializer { - //2.2 note: Yes, this wasn't final before, but it should have been + //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. public static final TemplatesModelProvider provider = new TemplatesModelProvider(); - 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); - } - @Override public void onInitializeClient() { + //set up some magic to force chunk rerenders when you change a template (see TemplateEntity) Templates.chunkRerenderProxy = (world, pos) -> { if(world == MinecraftClient.getInstance().world) { MinecraftClient.getInstance().worldRenderer.scheduleBlockRender( @@ -51,46 +39,19 @@ public class TemplatesClient implements ClientModInitializer { } }; - ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { - @Override - public Identifier getFabricId() { - return Templates.id("dump-caches"); - } - - @Override - public void reload(ResourceManager resourceManager) { - provider.dumpCache(); - } - }); - + //supporting code for the TemplatesModelProvider ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> provider); //block models ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> provider); //item models - BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), - Templates.BUTTON, - Templates.CANDLE, - Templates.CARPET, - Templates.CUBE, - Templates.DOOR, - Templates.FENCE, - Templates.FENCE_GATE, - Templates.IRON_DOOR, - Templates.IRON_TRAPDOOR, - Templates.LEVER, - Templates.PANE, - Templates.POST, - Templates.PRESSURE_PLATE, - Templates.SLAB, - Templates.STAIRS, - Templates.TRAPDOOR, - Templates.VERTICAL_SLAB, - Templates.WALL, - - Templates.SLOPE, - Templates.TINY_SLOPE - ); + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { + @Override public Identifier getFabricId() { return Templates.id("dump-caches"); } + @Override public void reload(ResourceManager blah) { provider.dumpCache(); } + }); - //vanilla style models (using "auto" method) + //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"))); @@ -168,4 +129,19 @@ public class TemplatesClient implements ClientModInitializer { 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/TemplatesModelProvider.java b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java index 1d2d775..90dbf2b 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java @@ -18,7 +18,7 @@ import java.util.Map; import java.util.Objects; import java.util.function.Function; -@SuppressWarnings("unused") //part of the api +@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<>(); @@ -46,9 +46,10 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria /// template appearance manager cache public TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function spriteLookup) { - //This is kind of needlessly fancy using the "volatile double checked locking" pattern. + //This is kind of needlessly sketchy using the "volatile double checked locking" pattern. //I'd like all template models to use the same TemplateApperanceManager, despite the model - //baking process happening concurrently on several threads. + //baking process happening concurrently on several threads, but I also don't want to + //hold up the model baking process too long. //Volatile field read: TemplateAppearanceManager read = appearanceManager; @@ -70,7 +71,7 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria } public void dumpCache() { - appearanceManager = null; + appearanceManager = null; //volatile write } /// "public api" diff --git a/src/main/java/io/github/cottonmc/templates/api/TemplateInteractionUtil.java b/src/main/java/io/github/cottonmc/templates/api/TemplateInteractionUtil.java index d3d542d..7866668 100644 --- a/src/main/java/io/github/cottonmc/templates/api/TemplateInteractionUtil.java +++ b/src/main/java/io/github/cottonmc/templates/api/TemplateInteractionUtil.java @@ -34,6 +34,8 @@ import net.minecraft.world.GameRules; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; +//For an example of how to use this class, have a look at TemplateBlock. +//Basically there are several methods that would like to modify the return value of something. public class TemplateInteractionUtil { public static final BooleanProperty LIGHT = BooleanProperty.of("templates_light"); @@ -41,15 +43,18 @@ public class TemplateInteractionUtil { return builder.add(LIGHT); } - public static AbstractBlock.Settings makeSettings() { - return configureSettings(AbstractBlock.Settings.create()); - } - + //Use this to obtain a Block.Settings that'll make your Template act like the ones in the mod. + //(To complete the look, don't forget to tag your blocks with mineable/axe.) private static final AbstractBlock.ContextPredicate NOPE = (blah, blahdey, blahh) -> false; public static AbstractBlock.Settings configureSettings(AbstractBlock.Settings s) { return s.luminance(TemplateInteractionUtil::luminance).nonOpaque().sounds(BlockSoundGroup.WOOD).hardness(0.2f).suffocates(NOPE).blockVision(NOPE); } + //And if you don't have a Block.Settings to copy off of. + public static AbstractBlock.Settings makeSettings() { + return configureSettings(AbstractBlock.Settings.create()); + } + public static BlockState setDefaultStates(BlockState in) { if(in.contains(LIGHT)) in = in.with(LIGHT, false); return in; diff --git a/src/main/java/io/github/cottonmc/templates/mixin/MinecraftAccessor.java b/src/main/java/io/github/cottonmc/templates/mixin/MinecraftAccessor.java index 09a928f..4a16a91 100644 --- a/src/main/java/io/github/cottonmc/templates/mixin/MinecraftAccessor.java +++ b/src/main/java/io/github/cottonmc/templates/mixin/MinecraftAccessor.java @@ -7,5 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(MinecraftClient.class) public interface MinecraftAccessor { + //Yeah there's a fabric API for this, but do we really need it, no. @Accessor("itemColors") ItemColors templates$getItemColors(); } diff --git a/src/main/java/io/github/cottonmc/templates/mixin/WallBlockAccessor.java b/src/main/java/io/github/cottonmc/templates/mixin/WallBlockAccessor.java index 6cc3290..7368c1b 100644 --- a/src/main/java/io/github/cottonmc/templates/mixin/WallBlockAccessor.java +++ b/src/main/java/io/github/cottonmc/templates/mixin/WallBlockAccessor.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.gen.Accessor; import java.util.Map; +//Used in TemplateWallBlock, since the vanilla wall block code explodes if you add more blockstates. @Mixin(WallBlock.class) public interface WallBlockAccessor { @Accessor("shapeMap") Map templates$getShapeMap(); diff --git a/src/main/java/io/github/cottonmc/templates/mixin/particles/MixinBlockDustParticle.java b/src/main/java/io/github/cottonmc/templates/mixin/particles/MixinBlockDustParticle.java index d4f23ef..cad758c 100644 --- a/src/main/java/io/github/cottonmc/templates/mixin/particles/MixinBlockDustParticle.java +++ b/src/main/java/io/github/cottonmc/templates/mixin/particles/MixinBlockDustParticle.java @@ -29,7 +29,8 @@ public class MixinBlockDustParticle { //basically just re-implement what the constructor does - since we mixin at tail, this already ran //some modifyvariable magic on the BlockState wouldn't hurt, i suppose, but, eh - //it'd need to capture method arguments but 99% of block dust particles are not for template blocks + //it'd need to capture method arguments but in this version of mixin it requires using threadlocals, + //and 99.9999% of block dust particles are not for template blocks, so it seems like a waste of cpu cycles int color = MinecraftClient.getInstance().getBlockColors().getColor(theme, clientWorld, pos, 0); a.templates$setRed(0.6f * ((color & 0xFF0000) >> 16) / 255f); a.templates$setGreen(0.6f * ((color & 0x00FF00) >> 8) / 255f);