way better block registration, more comments
This commit is contained in:
parent
d688ddbeb0
commit
a160f68ffc
@ -25,14 +25,12 @@ import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityT
|
|||||||
import net.minecraft.block.AbstractBlock;
|
import net.minecraft.block.AbstractBlock;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockSetType;
|
import net.minecraft.block.BlockSetType;
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.GlazedTerracottaBlock;
|
import net.minecraft.block.GlazedTerracottaBlock;
|
||||||
import net.minecraft.block.entity.BlockEntityType;
|
import net.minecraft.block.entity.BlockEntityType;
|
||||||
import net.minecraft.client.item.TooltipContext;
|
import net.minecraft.client.item.TooltipContext;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemGroup;
|
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.registry.Registry;
|
import net.minecraft.registry.Registry;
|
||||||
@ -42,158 +40,98 @@ import net.minecraft.util.Identifier;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Templates implements ModInitializer {
|
public class Templates implements ModInitializer {
|
||||||
public static final String MODID = "templates";
|
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<Block> 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<TemplateEntity> TEMPLATE_BLOCK_ENTITY;
|
||||||
|
|
||||||
|
//Changed in TemplatesClient (which is safe since client initializers load after common initializers)
|
||||||
|
@ApiStatus.Internal public static BiConsumer<World, BlockPos> 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<Text> 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) {
|
private static AbstractBlock.Settings cp(Block base) {
|
||||||
return TemplateInteractionUtil.configureSettings(AbstractBlock.Settings.copy(base));
|
return TemplateInteractionUtil.configureSettings(AbstractBlock.Settings.copy(base));
|
||||||
}
|
}
|
||||||
|
|
||||||
//vanilla, or at least vanilla-like, templates:
|
private static <B extends Block> B registerTemplate(String path, B block) {
|
||||||
public static final Block BUTTON = Registry.register(Registries.BLOCK, id("button") , new TemplateButtonBlock(cp(Blocks.OAK_BUTTON)));
|
Identifier id = id(path);
|
||||||
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:
|
Registry.register(Registries.BLOCK, id, block);
|
||||||
public static final Block SLOPE = Registry.register(Registries.BLOCK, id("slope") , new TemplateSlopeBlock(TemplateInteractionUtil.makeSettings()));
|
Registry.register(Registries.ITEM, id, new BlockItem(block, new Item.Settings()));
|
||||||
public static final Block TINY_SLOPE = Registry.register(Registries.BLOCK, id("tiny_slope") , new TemplateSlopeBlock.Tiny(TemplateInteractionUtil.makeSettings()));
|
INTERNAL_TEMPLATES.add(block);
|
||||||
//30 degree slope (shallow/deep)
|
return block;
|
||||||
//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<Text> 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<TemplateEntity> 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<World, BlockPos> 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()
|
|
||||||
);
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
public static Identifier id(String path) {
|
public static Identifier id(String path) {
|
||||||
return new Identifier(MODID, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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.ResourceManagerHelper;
|
||||||
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
|
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.resource.ResourceManager;
|
import net.minecraft.resource.ResourceManager;
|
||||||
@ -21,26 +22,13 @@ import net.minecraft.util.math.ChunkSectionPos;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class TemplatesClient implements ClientModInitializer {
|
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 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
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
|
//set up some magic to force chunk rerenders when you change a template (see TemplateEntity)
|
||||||
Templates.chunkRerenderProxy = (world, pos) -> {
|
Templates.chunkRerenderProxy = (world, pos) -> {
|
||||||
if(world == MinecraftClient.getInstance().world) {
|
if(world == MinecraftClient.getInstance().world) {
|
||||||
MinecraftClient.getInstance().worldRenderer.scheduleBlockRender(
|
MinecraftClient.getInstance().worldRenderer.scheduleBlockRender(
|
||||||
@ -51,46 +39,19 @@ public class TemplatesClient implements ClientModInitializer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
|
//supporting code for the TemplatesModelProvider
|
||||||
@Override
|
|
||||||
public Identifier getFabricId() {
|
|
||||||
return Templates.id("dump-caches");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reload(ResourceManager resourceManager) {
|
|
||||||
provider.dumpCache();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> provider); //block models
|
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> provider); //block models
|
||||||
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> provider); //item models
|
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> provider); //item models
|
||||||
|
|
||||||
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(),
|
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
|
||||||
Templates.BUTTON,
|
@Override public Identifier getFabricId() { return Templates.id("dump-caches"); }
|
||||||
Templates.CANDLE,
|
@Override public void reload(ResourceManager blah) { provider.dumpCache(); }
|
||||||
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,
|
//all templates mustn't be on the SOLID layer because they are not opaque by default (!)
|
||||||
Templates.TINY_SLOPE
|
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), Templates.INTERNAL_TEMPLATES.toArray(new Block[0]));
|
||||||
);
|
|
||||||
|
|
||||||
//vanilla style models (using "auto" method)
|
//and a big wall of fancy models
|
||||||
provider.addTemplateModel(Templates.id("button_special") , new UnbakedAutoRetexturedModel(new Identifier("block/button")));
|
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("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("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("slope_special") , Templates.SLOPE);
|
||||||
provider.assignItemModel(Templates.id("tiny_slope_special") , Templates.TINY_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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
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 {
|
public class TemplatesModelProvider implements ModelResourceProvider, ModelVariantProvider {
|
||||||
private final Map<Identifier, UnbakedModel> models = new HashMap<>();
|
private final Map<Identifier, UnbakedModel> models = new HashMap<>();
|
||||||
private final Map<ModelIdentifier, Identifier> itemAssignments = new HashMap<>();
|
private final Map<ModelIdentifier, Identifier> itemAssignments = new HashMap<>();
|
||||||
@ -46,9 +46,10 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria
|
|||||||
/// template appearance manager cache
|
/// template appearance manager cache
|
||||||
|
|
||||||
public TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
public TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function<SpriteIdentifier, Sprite> 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
|
//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:
|
//Volatile field read:
|
||||||
TemplateAppearanceManager read = appearanceManager;
|
TemplateAppearanceManager read = appearanceManager;
|
||||||
@ -70,7 +71,7 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dumpCache() {
|
public void dumpCache() {
|
||||||
appearanceManager = null;
|
appearanceManager = null; //volatile write
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "public api"
|
/// "public api"
|
||||||
|
@ -34,6 +34,8 @@ import net.minecraft.world.GameRules;
|
|||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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 class TemplateInteractionUtil {
|
||||||
public static final BooleanProperty LIGHT = BooleanProperty.of("templates_light");
|
public static final BooleanProperty LIGHT = BooleanProperty.of("templates_light");
|
||||||
|
|
||||||
@ -41,15 +43,18 @@ public class TemplateInteractionUtil {
|
|||||||
return builder.add(LIGHT);
|
return builder.add(LIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AbstractBlock.Settings makeSettings() {
|
//Use this to obtain a Block.Settings that'll make your Template act like the ones in the mod.
|
||||||
return configureSettings(AbstractBlock.Settings.create());
|
//(To complete the look, don't forget to tag your blocks with mineable/axe.)
|
||||||
}
|
|
||||||
|
|
||||||
private static final AbstractBlock.ContextPredicate NOPE = (blah, blahdey, blahh) -> false;
|
private static final AbstractBlock.ContextPredicate NOPE = (blah, blahdey, blahh) -> false;
|
||||||
public static AbstractBlock.Settings configureSettings(AbstractBlock.Settings s) {
|
public static AbstractBlock.Settings configureSettings(AbstractBlock.Settings s) {
|
||||||
return s.luminance(TemplateInteractionUtil::luminance).nonOpaque().sounds(BlockSoundGroup.WOOD).hardness(0.2f).suffocates(NOPE).blockVision(NOPE);
|
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) {
|
public static BlockState setDefaultStates(BlockState in) {
|
||||||
if(in.contains(LIGHT)) in = in.with(LIGHT, false);
|
if(in.contains(LIGHT)) in = in.with(LIGHT, false);
|
||||||
return in;
|
return in;
|
||||||
|
@ -7,5 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
|||||||
|
|
||||||
@Mixin(MinecraftClient.class)
|
@Mixin(MinecraftClient.class)
|
||||||
public interface MinecraftAccessor {
|
public interface MinecraftAccessor {
|
||||||
|
//Yeah there's a fabric API for this, but do we really need it, no.
|
||||||
@Accessor("itemColors") ItemColors templates$getItemColors();
|
@Accessor("itemColors") ItemColors templates$getItemColors();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
//Used in TemplateWallBlock, since the vanilla wall block code explodes if you add more blockstates.
|
||||||
@Mixin(WallBlock.class)
|
@Mixin(WallBlock.class)
|
||||||
public interface WallBlockAccessor {
|
public interface WallBlockAccessor {
|
||||||
@Accessor("shapeMap") Map<BlockState, VoxelShape> templates$getShapeMap();
|
@Accessor("shapeMap") Map<BlockState, VoxelShape> templates$getShapeMap();
|
||||||
|
@ -29,7 +29,8 @@ public class MixinBlockDustParticle {
|
|||||||
|
|
||||||
//basically just re-implement what the constructor does - since we mixin at tail, this already ran
|
//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
|
//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);
|
int color = MinecraftClient.getInstance().getBlockColors().getColor(theme, clientWorld, pos, 0);
|
||||||
a.templates$setRed(0.6f * ((color & 0xFF0000) >> 16) / 255f);
|
a.templates$setRed(0.6f * ((color & 0xFF0000) >> 16) / 255f);
|
||||||
a.templates$setGreen(0.6f * ((color & 0x00FF00) >> 8) / 255f);
|
a.templates$setGreen(0.6f * ((color & 0x00FF00) >> 8) / 255f);
|
||||||
|
Loading…
Reference in New Issue
Block a user