summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-01-09 19:37:28 +0100
committerGravatar Uko Kokņevičs2024-01-09 19:37:28 +0100
commit4606c536a6260477870426234f748067240de3d1 (patch)
tree52ecd35ab0a51dd84bbebb675f5433a85166b132 /src
parentReplace ItemMixin.java with proper ItemTooltipCallback usage. (diff)
downloadmc-eris-alchemy-4606c536a6260477870426234f748067240de3d1.tar.gz
mc-eris-alchemy-4606c536a6260477870426234f748067240de3d1.tar.xz
mc-eris-alchemy-4606c536a6260477870426234f748067240de3d1.zip
Added Alchemical Chest.
Diffstat (limited to 'src')
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/EMC.java6
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java41
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyItems.java44
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java162
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/ErisAlchemyBlocks.java29
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java198
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/entity/ErisAlchemyBlockEntities.java33
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/AlchemicalChestScreen.java43
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/ChestItemRenderer.java40
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java41
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyMaterials.java15
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/package-info.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java91
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/menu/ErisAlchemyMenus.java29
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/client/SheetsMixin.java22
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/mixin/client/package-info.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/recipe/CovalenceRepair.java (renamed from src/main/java/lv/enes/mc/eris_alchemy/CovalenceRepair.java)9
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/recipe/ErisAlchemyRecipeSerializers.java27
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java (renamed from src/main/java/lv/enes/mc/eris_alchemy/SubAxe.java)8
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/RecipeUtils.java4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java4
-rw-r--r--src/main/resources/assets/eris_alchemy/blockstates/alchemical_chest.json7
-rw-r--r--src/main/resources/assets/eris_alchemy/icon.pngbin391 -> 687 bytes
-rw-r--r--src/main/resources/assets/eris_alchemy/lang/en_us.json4
-rw-r--r--src/main/resources/assets/eris_alchemy/models/block/alchemical_chest.json5
-rw-r--r--src/main/resources/assets/eris_alchemy/models/item/alchemical_chest.json6
-rw-r--r--src/main/resources/assets/eris_alchemy/patchouli_books/guide_book/en_us/entries/root/alchemical_chest.json14
-rw-r--r--src/main/resources/assets/eris_alchemy/textures/entity/chest/alchemical_chest.pngbin0 -> 1996 bytes
-rw-r--r--src/main/resources/assets/eris_alchemy/textures/gui/container/alchemical_chest.pngbin0 -> 1298 bytes
-rw-r--r--src/main/resources/data/eris_alchemy/loot_tables/blocks/alchemical_chest.json13
-rw-r--r--src/main/resources/data/eris_alchemy/recipes/alchemical_chest.json34
-rw-r--r--src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json6
-rw-r--r--src/main/resources/eris_alchemy.mixins.json3
-rw-r--r--src/main/resources/quilt.mod.json3
38 files changed, 914 insertions, 51 deletions
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/EMC.java b/src/main/java/lv/enes/mc/eris_alchemy/EMC.java
index 4f2c5e4..b8d5557 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/EMC.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/EMC.java
@@ -1,10 +1,8 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy;
2 2
3import jakarta.annotation.Nullable; 3import jakarta.annotation.Nullable;
4import lv.enes.mc.eris_alchemy.utils.CoralUtils; 4import lv.enes.mc.eris_alchemy.utils.*;
5import lv.enes.mc.eris_alchemy.utils.DyeUtils;
6import lv.enes.mc.eris_alchemy.utils.ItemUtils; 5import lv.enes.mc.eris_alchemy.utils.ItemUtils;
7import lv.enes.mc.eris_alchemy.utils.RecipeUtils;
8import net.minecraft.core.RegistryAccess; 6import net.minecraft.core.RegistryAccess;
9import net.minecraft.core.registries.BuiltInRegistries; 7import net.minecraft.core.registries.BuiltInRegistries;
10import net.minecraft.tags.BlockTags; 8import net.minecraft.tags.BlockTags;
@@ -116,7 +114,7 @@ public class EMC {
116 private List<SimplifiedRecipe> getRecipes(@Nullable Level world) { 114 private List<SimplifiedRecipe> getRecipes(@Nullable Level world) {
117 Stream<SimplifiedRecipe> recipes = Stream.concat( 115 Stream<SimplifiedRecipe> recipes = Stream.concat(
118 FAKE_RECIPES.stream(), 116 FAKE_RECIPES.stream(),
119 SubAxe.getStrippables() 117 AxeUtils.getStrippables()
120 .entrySet() 118 .entrySet()
121 .stream() 119 .stream()
122 .map(entry -> new SimplifiedRecipe(entry.getValue(), Ingredient.of(entry.getKey()))) 120 .map(entry -> new SimplifiedRecipe(entry.getValue(), Ingredient.of(entry.getKey())))
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
index fe7e40d..83cef8c 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
@@ -1,39 +1,29 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy;
2 2
3import lv.enes.mc.eris_alchemy.block.ErisAlchemyBlocks;
4import lv.enes.mc.eris_alchemy.block.entity.ErisAlchemyBlockEntities;
5import lv.enes.mc.eris_alchemy.menu.ErisAlchemyMenus;
6import lv.enes.mc.eris_alchemy.recipe.ErisAlchemyRecipeSerializers;
3import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; 7import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
4import net.minecraft.core.Registry; 8import net.minecraft.core.Registry;
5import net.minecraft.core.registries.BuiltInRegistries; 9import net.minecraft.core.registries.BuiltInRegistries;
6import net.minecraft.network.chat.Component; 10import net.minecraft.network.chat.Component;
7import net.minecraft.resources.ResourceLocation; 11import net.minecraft.resources.ResourceLocation;
8import net.minecraft.world.item.CreativeModeTab; 12import net.minecraft.world.item.CreativeModeTab;
9import net.minecraft.world.item.Item;
10import net.minecraft.world.item.ItemStack; 13import net.minecraft.world.item.ItemStack;
11import net.minecraft.world.item.Rarity;
12import org.quiltmc.loader.api.ModContainer; 14import org.quiltmc.loader.api.ModContainer;
13import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; 15import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
14import org.quiltmc.qsl.item.setting.api.QuiltItemSettings;
15import org.quiltmc.qsl.tooltip.api.client.ItemTooltipCallback;
16import org.slf4j.Logger; 16import org.slf4j.Logger;
17import org.slf4j.LoggerFactory; 17import org.slf4j.LoggerFactory;
18 18
19import java.text.DecimalFormat;
20
21public class ErisAlchemy implements ModInitializer { 19public class ErisAlchemy implements ModInitializer {
22 public static final String ID = "eris_alchemy"; 20 public static final String ID = "eris_alchemy";
23 public static final Logger LOGGER = LoggerFactory.getLogger(ID); 21 public static final Logger LOGGER = LoggerFactory.getLogger(ID);
24 22
25 public static final Item LOW_COVALENCE_DUST = new Item(new QuiltItemSettings().rarity(Rarity.COMMON));
26 public static final Item MEDIUM_COVALENCE_DUST = new Item(new QuiltItemSettings().rarity(Rarity.UNCOMMON));
27 public static final Item HIGH_COVALENCE_DUST = new Item(new QuiltItemSettings().rarity(Rarity.RARE));
28
29 public static final CreativeModeTab ITEM_GROUP = FabricItemGroup.builder() 23 public static final CreativeModeTab ITEM_GROUP = FabricItemGroup.builder()
30 .icon(() -> new ItemStack(LOW_COVALENCE_DUST)) 24 .icon(() -> new ItemStack(ErisAlchemyItems.LOW_COVALENCE_DUST))
31 .title(Component.translatable("itemGroup.eris_alchemy.item_group")) 25 .title(Component.translatable("itemGroup.eris_alchemy.item_group"))
32 .displayItems((context, entries) -> { 26 .displayItems((context, entries) -> ErisAlchemyItems.consumeItems((id, item) -> entries.accept(item)))
33 entries.accept(LOW_COVALENCE_DUST);
34 entries.accept(MEDIUM_COVALENCE_DUST);
35 entries.accept(HIGH_COVALENCE_DUST);
36 })
37 .build(); 27 .build();
38 28
39 @Override 29 @Override
@@ -45,19 +35,10 @@ public class ErisAlchemy implements ModInitializer {
45 35
46 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP); 36 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP);
47 37
48 Registry.register(BuiltInRegistries.ITEM, new ResourceLocation(ID, "low_covalence_dust"), LOW_COVALENCE_DUST); 38 ErisAlchemyBlocks.consumeBlocks((id, block) -> Registry.register(BuiltInRegistries.BLOCK, id, block));
49 Registry.register(BuiltInRegistries.ITEM, new ResourceLocation(ID, "medium_covalence_dust"), MEDIUM_COVALENCE_DUST); 39 ErisAlchemyBlockEntities.consumeBlockEntities((id, block) -> Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, id, block));
50 Registry.register(BuiltInRegistries.ITEM, new ResourceLocation(ID, "high_covalence_dust"), HIGH_COVALENCE_DUST); 40 ErisAlchemyItems.consumeItems((id, item) -> Registry.register(BuiltInRegistries.ITEM, id, item));
51 41 ErisAlchemyMenus.consumeMenus((id, menu) -> Registry.register(BuiltInRegistries.MENU, id, menu));
52 Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, CovalenceRepair.Serializer.ID, CovalenceRepair.Serializer.INSTANCE); 42 ErisAlchemyRecipeSerializers.consumeSerializers((id, serializer) -> Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, id, serializer));
53
54 var doubleFormat = new DecimalFormat("0");
55 doubleFormat.setMaximumFractionDigits(1);
56
57 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> {
58 var world = player == null ? null : player.level();
59 var emc = EMC.getInstance(world).get(stack.getItem());
60 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(doubleFormat.format(value)))));
61 });
62 } 43 }
63} 44}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyItems.java b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyItems.java
new file mode 100644
index 0000000..21bcc7f
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyItems.java
@@ -0,0 +1,44 @@
1package lv.enes.mc.eris_alchemy;
2
3import lv.enes.mc.eris_alchemy.block.ErisAlchemyBlocks;
4import net.minecraft.core.registries.BuiltInRegistries;
5import net.minecraft.resources.ResourceLocation;
6import net.minecraft.world.item.BlockItem;
7import net.minecraft.world.item.Item;
8import net.minecraft.world.item.Rarity;
9import net.minecraft.world.level.block.Block;
10import org.quiltmc.qsl.item.setting.api.QuiltItemSettings;
11
12import java.util.LinkedHashMap;
13import java.util.Map;
14import java.util.function.BiConsumer;
15
16public final class ErisAlchemyItems {
17 private static final Map<ResourceLocation, Item> items = new LinkedHashMap<>();
18
19 public static final Item ALCHEMICAL_CHEST = register(ErisAlchemyBlocks.ALCHEMICAL_CHEST, new QuiltItemSettings().rarity(Rarity.RARE));
20 public static final Item LOW_COVALENCE_DUST = register("low_covalence_dust", new Item(new QuiltItemSettings().rarity(Rarity.COMMON)));
21 @SuppressWarnings("unused")
22 public static final Item MEDIUM_COVALENCE_DUST = register("medium_covalence_dust", new Item(new QuiltItemSettings().rarity(Rarity.UNCOMMON)));
23 @SuppressWarnings("unused")
24 public static final Item HIGH_COVALENCE_DUST = register("high_covalence_dust", new Item(new QuiltItemSettings().rarity(Rarity.RARE)));
25
26 public static void consumeItems(BiConsumer<? super ResourceLocation, ? super Item> consumer) {
27 items.forEach(consumer);
28 }
29
30 private static BlockItem register(Block block, QuiltItemSettings settings) {
31 return register(BuiltInRegistries.BLOCK.getKey(block), new BlockItem(block, settings));
32 }
33
34 private static <T extends Item> T register(String id, T item) {
35 return register(new ResourceLocation(ErisAlchemy.ID, id), item);
36 }
37
38 private static <T extends Item> T register(ResourceLocation id, T item) {
39 items.putIfAbsent(id, item);
40 return item;
41 }
42
43 private ErisAlchemyItems() {}
44}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java b/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java
new file mode 100644
index 0000000..c013df6
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java
@@ -0,0 +1,162 @@
1package lv.enes.mc.eris_alchemy.block;
2
3import jakarta.annotation.Nonnull;
4import jakarta.annotation.Nullable;
5import lv.enes.mc.eris_alchemy.block.entity.AlchemicalChestBlockEntity;
6import lv.enes.mc.eris_alchemy.block.entity.ErisAlchemyBlockEntities;
7import lv.enes.mc.eris_alchemy.menu.AlchemicalChestMenu;
8import net.minecraft.core.BlockPos;
9import net.minecraft.core.Direction;
10import net.minecraft.network.chat.Component;
11import net.minecraft.world.*;
12import net.minecraft.world.entity.monster.piglin.PiglinAi;
13import net.minecraft.world.entity.player.Player;
14import net.minecraft.world.item.context.BlockPlaceContext;
15import net.minecraft.world.level.BlockGetter;
16import net.minecraft.world.level.Level;
17import net.minecraft.world.level.block.*;
18import net.minecraft.world.level.block.entity.BlockEntity;
19import net.minecraft.world.level.block.entity.BlockEntityTicker;
20import net.minecraft.world.level.block.entity.BlockEntityType;
21import net.minecraft.world.level.block.entity.ChestBlockEntity;
22import net.minecraft.world.level.block.state.BlockState;
23import net.minecraft.world.level.block.state.StateDefinition;
24import net.minecraft.world.level.block.state.properties.BlockStateProperties;
25import net.minecraft.world.level.block.state.properties.DirectionProperty;
26import net.minecraft.world.level.pathfinder.PathComputationType;
27import net.minecraft.world.phys.BlockHitResult;
28import net.minecraft.world.phys.shapes.CollisionContext;
29import net.minecraft.world.phys.shapes.VoxelShape;
30
31public class AlchemicalChestBlock extends AbstractChestBlock<AlchemicalChestBlockEntity> {
32 public static final Component CONTAINER_TITLE = Component.translatable("container.eris_alchemy.alchemical_chest");
33 public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
34 public static final VoxelShape SHAPE = Block.box(1.0, 0.0, 1.0, 15.0, 14.0, 15.0);
35
36 public static Container getContainer(Level world, BlockPos pos) {
37 if (world.getBlockEntity(pos) instanceof AlchemicalChestBlockEntity container) {
38 return container;
39 }
40 return null;
41 }
42
43 public AlchemicalChestBlock(Properties properties) {
44 super(properties, () -> ErisAlchemyBlockEntities.ALCHEMICAL_CHEST);
45 registerDefaultState(getStateDefinition().any()
46 .setValue(FACING, Direction.NORTH)
47 );
48 }
49
50 @Nonnull
51 @Override
52 public DoubleBlockCombiner.NeighborCombineResult<? extends ChestBlockEntity> combine(BlockState state, Level world, BlockPos pos, boolean ignoreBlocked) {
53 return DoubleBlockCombiner.Combiner::acceptNone;
54 }
55
56 @Override
57 protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
58 builder.add(FACING);
59 }
60
61 @SuppressWarnings("deprecation")
62 @Override
63 public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
64 return AlchemicalChestMenu.getRedstoneSignalFromContainer(getContainer(world, pos));
65 }
66
67 @Override
68 public MenuProvider getMenuProvider(BlockState state, Level world, BlockPos pos) {
69 if (world.getBlockEntity(pos) instanceof AlchemicalChestBlockEntity entity) {
70 return new SimpleMenuProvider(entity, CONTAINER_TITLE);
71 }
72 return null;
73 }
74
75 @Nonnull
76 @Override
77 public RenderShape getRenderShape(BlockState state) {
78 return RenderShape.ENTITYBLOCK_ANIMATED;
79 }
80
81 @SuppressWarnings("deprecation")
82 @Nonnull
83 @Override
84 public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext ctx) {
85 return SHAPE;
86 }
87
88 @Override
89 public BlockState getStateForPlacement(BlockPlaceContext ctx) {
90 return defaultBlockState()
91 .setValue(FACING, ctx.getHorizontalDirection().getOpposite());
92 }
93
94 @Override
95 public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level ignoredWorld, BlockState ignoredState, BlockEntityType<T> type) {
96 return createTickerHelper(type, blockEntityType.get(), (world, pos, state, entity) -> entity.tick(world, pos, state));
97 }
98
99 @SuppressWarnings("deprecation")
100 @Override
101 public boolean hasAnalogOutputSignal(BlockState state) {
102 return true;
103 }
104
105 @SuppressWarnings("deprecation")
106 @Override
107 public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
108 return false;
109 }
110
111 @SuppressWarnings("deprecation")
112 @Nonnull
113 @Override
114 public BlockState mirror(BlockState state, Mirror mirror) {
115 return state.rotate(mirror.getRotation(state.getValue(FACING)));
116 }
117
118 @Nullable
119 @Override
120 public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
121 return new AlchemicalChestBlockEntity(pos, state);
122 }
123
124 @SuppressWarnings("deprecation")
125 @Override
126 public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
127 if (!state.is(newState.getBlock())) {
128 var entity = world.getBlockEntity(pos);
129 if (entity instanceof Container container) {
130 Containers.dropContents(world, pos, container);
131 world.updateNeighbourForOutputSignal(pos, this);
132 }
133
134 super.onRemove(state, world, pos, newState, moved);
135 }
136 }
137
138 @SuppressWarnings("deprecation")
139 @Nonnull
140 @Override
141 public BlockState rotate(BlockState state, Rotation rotation) {
142 return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
143 }
144
145 @SuppressWarnings("deprecation")
146 @Nonnull
147 @Override
148 public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
149 if (world.isClientSide) {
150 return InteractionResult.SUCCESS;
151 }
152
153 var provider = getMenuProvider(state, world, pos);
154 if (provider != null) {
155 player.openMenu(provider);
156 // player.awardStat(getOpenChestStat);
157 PiglinAi.angerNearbyPiglins(player, true);
158 }
159
160 return InteractionResult.CONSUME;
161 }
162}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/ErisAlchemyBlocks.java b/src/main/java/lv/enes/mc/eris_alchemy/block/ErisAlchemyBlocks.java
new file mode 100644
index 0000000..6966681
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/ErisAlchemyBlocks.java
@@ -0,0 +1,29 @@
1package lv.enes.mc.eris_alchemy.block;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import net.minecraft.resources.ResourceLocation;
5import net.minecraft.world.level.block.Block;
6import net.minecraft.world.level.block.Blocks;
7import org.quiltmc.qsl.block.extensions.api.QuiltBlockSettings;
8
9import java.util.LinkedHashMap;
10import java.util.Map;
11import java.util.function.BiConsumer;
12
13public final class ErisAlchemyBlocks {
14 private static final Map<ResourceLocation, Block> blocks = new LinkedHashMap<>();
15
16 public static final AlchemicalChestBlock ALCHEMICAL_CHEST = register("alchemical_chest", new AlchemicalChestBlock(QuiltBlockSettings.copy(Blocks.ENDER_CHEST)));
17
18 public static void consumeBlocks(BiConsumer<? super ResourceLocation, ? super Block> consumer) {
19 blocks.forEach(consumer);
20 }
21
22 private static <T extends Block> T register(String id, T block) {
23 blocks.putIfAbsent(new ResourceLocation(ErisAlchemy.ID, id), block);
24 return block;
25 }
26
27 private ErisAlchemyBlocks() {}
28
29}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java
new file mode 100644
index 0000000..9c9942f
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java
@@ -0,0 +1,198 @@
1package lv.enes.mc.eris_alchemy.block.entity;
2
3import jakarta.annotation.Nonnull;
4import lv.enes.mc.eris_alchemy.block.ErisAlchemyBlocks;
5import lv.enes.mc.eris_alchemy.menu.AlchemicalChestMenu;
6import net.minecraft.core.BlockPos;
7import net.minecraft.core.NonNullList;
8import net.minecraft.nbt.CompoundTag;
9import net.minecraft.network.chat.Component;
10import net.minecraft.sounds.SoundEvents;
11import net.minecraft.sounds.SoundSource;
12import net.minecraft.world.Container;
13import net.minecraft.world.ContainerHelper;
14import net.minecraft.world.entity.player.Inventory;
15import net.minecraft.world.entity.player.Player;
16import net.minecraft.world.inventory.AbstractContainerMenu;
17import net.minecraft.world.item.ItemStack;
18import net.minecraft.world.level.Level;
19import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
20import net.minecraft.world.level.block.entity.ChestLidController;
21import net.minecraft.world.level.block.entity.ContainerOpenersCounter;
22import net.minecraft.world.level.block.entity.LidBlockEntity;
23import net.minecraft.world.level.block.state.BlockState;
24
25public class AlchemicalChestBlockEntity extends BaseContainerBlockEntity implements LidBlockEntity {
26 private final static int WIDTH = 13;
27 private final static int HEIGHT = 8;
28
29 private final static int EVENT = 1;
30
31 private final NonNullList<ItemStack> items = NonNullList.withSize(WIDTH * HEIGHT, ItemStack.EMPTY);
32 private final ChestLidController lidController = new ChestLidController();
33 private final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
34 @Override
35 protected void onOpen(Level world, BlockPos pos, BlockState state) {
36 // TODO: Sound effects?
37 world.playSound(
38 null,
39 pos.getX() + 0.5,
40 pos.getY() + 0.5,
41 pos.getZ() + 0.5,
42 SoundEvents.ENDER_CHEST_OPEN,
43 SoundSource.BLOCKS,
44 0.5f,
45 world.random.nextFloat() * 0.1f + 0.9f
46 );
47 }
48
49 @Override
50 protected void onClose(Level world, BlockPos pos, BlockState state) {
51 // TODO: Sound effects?
52 world.playSound(
53 null,
54 pos.getX() + 0.5,
55 pos.getY() + 0.5,
56 pos.getZ() + 0.5,
57 SoundEvents.ENDER_CHEST_CLOSE,
58 SoundSource.BLOCKS,
59 0.5f,
60 world.random.nextFloat() * 0.1f + 0.9f
61 );
62 }
63
64 @Override
65 protected void openerCountChanged(Level world, BlockPos pos, BlockState state, int oldViewerCount, int newViewerCount) {
66 world.blockEvent(worldPosition, ErisAlchemyBlocks.ALCHEMICAL_CHEST, EVENT, newViewerCount);
67 }
68
69 @Override
70 protected boolean isOwnContainer(Player player) {
71 if (player.containerMenu instanceof AlchemicalChestMenu menu) {
72 return menu.getContainer() == AlchemicalChestBlockEntity.this;
73 }
74 return false;
75 }
76 };
77
78 public AlchemicalChestBlockEntity(BlockPos pos, BlockState state) {
79 super(ErisAlchemyBlockEntities.ALCHEMICAL_CHEST, pos, state);
80 }
81
82 @Override
83 public void clearContent() {
84 items.clear();
85 }
86
87 @Nonnull
88 @Override
89 protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) {
90 return new AlchemicalChestMenu(syncId, playerInventory, this);
91 }
92
93 @Override
94 public int getContainerSize() {
95 return items.size();
96 }
97
98 @Nonnull
99 @Override
100 protected Component getDefaultName() {
101 return Component.translatable("container.eris_alchemy.alchemical_chest");
102 }
103
104 @Nonnull
105 @Override
106 public ItemStack getItem(int slot) {
107 return items.get(slot);
108 }
109
110 @Override
111 public float getOpenNess(float tickDelta) {
112 return lidController.getOpenness(tickDelta);
113 }
114
115 @Override
116 public boolean isEmpty() {
117 return items.stream().allMatch(ItemStack::isEmpty);
118 }
119
120 @Override
121 public void load(CompoundTag nbt) {
122 super.load(nbt);
123 ContainerHelper.loadAllItems(nbt, items);
124 }
125
126 private void recheckOpen() {
127 if (!remove) {
128 openersCounter.recheckOpeners(getLevel(), getBlockPos(), getBlockState());
129 }
130 }
131
132 @Nonnull
133 @Override
134 public ItemStack removeItem(int slot, int amount) {
135 var stack = ContainerHelper.removeItem(items, slot, amount);
136 if (!stack.isEmpty()) {
137 this.setChanged();
138 }
139 return stack;
140 }
141
142 @Nonnull
143 @Override
144 public ItemStack removeItemNoUpdate(int slot) {
145 return ContainerHelper.takeItem(items, slot);
146 }
147
148 @Override
149 protected void saveAdditional(CompoundTag nbt) {
150 super.saveAdditional(nbt);
151 ContainerHelper.saveAllItems(nbt, items);
152 }
153
154 @Override
155 public void setItem(int slot, ItemStack stack) {
156 items.set(slot, stack);
157 if (stack.getCount() > getMaxStackSize()) {
158 stack.setCount(getMaxStackSize());
159 }
160 this.setChanged();
161 }
162
163 @Override
164 public void startOpen(Player player) {
165 if (!remove && !player.isSpectator()) {
166 openersCounter.incrementOpeners(player, getLevel(), getBlockPos(), getBlockState());
167 }
168 }
169
170 @Override
171 public boolean stillValid(Player player) {
172 return Container.stillValidBlockEntity(this, player);
173 }
174
175 @Override
176 public void stopOpen(Player player) {
177 if (!remove && !player.isSpectator()) {
178 openersCounter.decrementOpeners(player, getLevel(), getBlockPos(), getBlockState());
179 }
180 }
181
182 public void tick(Level world, BlockPos ignoredPos, BlockState ignoredState) {
183 if (world.isClientSide) {
184 lidController.tickLid();
185 }
186 recheckOpen();
187 }
188
189 @Override
190 public boolean triggerEvent(int type, int data) {
191 if (type == EVENT) {
192 lidController.shouldBeOpen(data > 0);
193 return true;
194 }
195
196 return super.triggerEvent(type, data);
197 }
198}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ErisAlchemyBlockEntities.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ErisAlchemyBlockEntities.java
new file mode 100644
index 0000000..a95ac58
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ErisAlchemyBlockEntities.java
@@ -0,0 +1,33 @@
1package lv.enes.mc.eris_alchemy.block.entity;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import lv.enes.mc.eris_alchemy.block.ErisAlchemyBlocks;
5import net.minecraft.resources.ResourceLocation;
6import net.minecraft.world.level.block.entity.BlockEntity;
7import net.minecraft.world.level.block.entity.BlockEntityType;
8import org.quiltmc.qsl.block.entity.api.QuiltBlockEntityTypeBuilder;
9
10import java.util.LinkedHashMap;
11import java.util.Map;
12import java.util.function.BiConsumer;
13
14public final class ErisAlchemyBlockEntities {
15 private static final Map<ResourceLocation, BlockEntityType<?>> entities = new LinkedHashMap<>();
16
17 public static final BlockEntityType<AlchemicalChestBlockEntity> ALCHEMICAL_CHEST = register(
18 "alchemical_chest",
19 QuiltBlockEntityTypeBuilder.create(AlchemicalChestBlockEntity::new, ErisAlchemyBlocks.ALCHEMICAL_CHEST)
20 .build()
21 );
22
23 public static void consumeBlockEntities(BiConsumer<? super ResourceLocation, ? super BlockEntityType<?>> consumer) {
24 entities.forEach(consumer);
25 }
26
27 private static <T extends BlockEntity> BlockEntityType<T> register(String id, BlockEntityType<T> type) {
28 entities.putIfAbsent(new ResourceLocation(ErisAlchemy.ID, id), type);
29 return type;
30 }
31
32 private ErisAlchemyBlockEntities() {}
33}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/AlchemicalChestScreen.java b/src/main/java/lv/enes/mc/eris_alchemy/client/AlchemicalChestScreen.java
new file mode 100644
index 0000000..319dea8
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/AlchemicalChestScreen.java
@@ -0,0 +1,43 @@
1package lv.enes.mc.eris_alchemy.client;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import lv.enes.mc.eris_alchemy.menu.AlchemicalChestMenu;
5import net.minecraft.client.gui.GuiGraphics;
6import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
7import net.minecraft.network.chat.Component;
8import net.minecraft.resources.ResourceLocation;
9import net.minecraft.world.entity.player.Inventory;
10
11public class AlchemicalChestScreen extends AbstractContainerScreen<AlchemicalChestMenu> {
12 public static final ResourceLocation TEXTURE =
13 new ResourceLocation(ErisAlchemy.ID, "textures/gui/container/alchemical_chest.png");
14
15 public static final int TEXTURE_WIDTH = 248;
16 public static final int TEXTURE_HEIGHT = 237;
17
18 public AlchemicalChestScreen(AlchemicalChestMenu menu, Inventory inventory, Component title) {
19 super(menu, inventory, title);
20
21 imageWidth = TEXTURE_WIDTH;
22 imageHeight = TEXTURE_HEIGHT;
23 }
24
25 @Override
26 public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
27 renderBackground(graphics);
28 super.render(graphics, mouseX, mouseY, delta);
29 renderTooltip(graphics, mouseX, mouseY);
30 }
31
32 @Override
33 protected void renderBg(GuiGraphics graphics, float delta, int mouseX, int mouseY) {
34 int x = (width - imageWidth) / 2;
35 int y = (height - imageHeight) / 2;
36 graphics.blit(TEXTURE, x, y, 0, 0, imageWidth, imageHeight);
37 }
38
39 @Override
40 protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
41 // Don't render any labels, there's no space for them lol
42 }
43}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/ChestItemRenderer.java b/src/main/java/lv/enes/mc/eris_alchemy/client/ChestItemRenderer.java
new file mode 100644
index 0000000..d49cc28
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/ChestItemRenderer.java
@@ -0,0 +1,40 @@
1package lv.enes.mc.eris_alchemy.client;
2
3import com.mojang.blaze3d.vertex.PoseStack;
4import net.minecraft.client.Minecraft;
5import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
6import net.minecraft.client.renderer.MultiBufferSource;
7import net.minecraft.core.BlockPos;
8import net.minecraft.world.item.ItemDisplayContext;
9import net.minecraft.world.item.ItemStack;
10import net.minecraft.world.level.block.AbstractChestBlock;
11import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
12import net.minecraft.world.level.block.state.BlockState;
13
14import java.util.function.BiFunction;
15
16public class ChestItemRenderer<T extends BaseContainerBlockEntity> extends BlockEntityWithoutLevelRenderer {
17 private final T chest;
18
19 public ChestItemRenderer(
20 AbstractChestBlock<T> block,
21 BiFunction<? super BlockPos, ? super BlockState, ? extends T> creator
22 ) {
23 super(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels());
24 chest = creator.apply(BlockPos.ZERO, block.defaultBlockState());
25 }
26
27 @Override
28 public void renderByItem(
29 ItemStack stack,
30 ItemDisplayContext transformationMode,
31 PoseStack matrices,
32 MultiBufferSource vertexConsumers,
33 int light,
34 int overlay
35 ) {
36 Minecraft.getInstance()
37 .getBlockEntityRenderDispatcher()
38 .renderItem(chest, matrices, vertexConsumers, light, overlay);
39 }
40}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
new file mode 100644
index 0000000..bb5de4f
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
@@ -0,0 +1,41 @@
1package lv.enes.mc.eris_alchemy.client;
2
3import lv.enes.mc.eris_alchemy.EMC;
4import lv.enes.mc.eris_alchemy.ErisAlchemyItems;
5import lv.enes.mc.eris_alchemy.block.ErisAlchemyBlocks;
6import lv.enes.mc.eris_alchemy.block.entity.AlchemicalChestBlockEntity;
7import lv.enes.mc.eris_alchemy.block.entity.ErisAlchemyBlockEntities;
8import lv.enes.mc.eris_alchemy.menu.ErisAlchemyMenus;
9import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
10import net.minecraft.client.gui.screens.MenuScreens;
11import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
12import net.minecraft.client.renderer.blockentity.ChestRenderer;
13import net.minecraft.network.chat.Component;
14import org.quiltmc.loader.api.ModContainer;
15import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer;
16import org.quiltmc.qsl.tooltip.api.client.ItemTooltipCallback;
17
18import java.text.DecimalFormat;
19
20@SuppressWarnings("unused")
21public class ErisAlchemyClient implements ClientModInitializer {
22 @Override
23 public void onInitializeClient(ModContainer mod) {
24 BlockEntityRenderers.register(ErisAlchemyBlockEntities.ALCHEMICAL_CHEST, ChestRenderer::new);
25
26 BuiltinItemRendererRegistry.INSTANCE.register(
27 ErisAlchemyItems.ALCHEMICAL_CHEST,
28 new ChestItemRenderer<>(ErisAlchemyBlocks.ALCHEMICAL_CHEST, AlchemicalChestBlockEntity::new)::renderByItem
29 );
30
31 MenuScreens.register(ErisAlchemyMenus.ALCHEMICAL_CHEST, AlchemicalChestScreen::new);
32
33 var doubleFormat = new DecimalFormat("0");
34 doubleFormat.setMaximumFractionDigits(1);
35 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> {
36 var world = player == null ? null : player.level();
37 var emc = EMC.getInstance(world).get(stack.getItem());
38 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(doubleFormat.format(value)))));
39 });
40 }
41}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyMaterials.java b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyMaterials.java
new file mode 100644
index 0000000..15d9209
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyMaterials.java
@@ -0,0 +1,15 @@
1package lv.enes.mc.eris_alchemy.client;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import net.minecraft.client.renderer.Sheets;
5import net.minecraft.client.resources.model.Material;
6import net.minecraft.resources.ResourceLocation;
7
8public final class ErisAlchemyMaterials {
9 public static final Material ALCHEMICAL_CHEST = new Material(
10 Sheets.CHEST_SHEET,
11 new ResourceLocation(ErisAlchemy.ID, "entity/chest/alchemical_chest")
12 );
13
14 private ErisAlchemyMaterials() {}
15}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/package-info.java b/src/main/java/lv/enes/mc/eris_alchemy/client/package-info.java
new file mode 100644
index 0000000..7b1c99a
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/package-info.java
@@ -0,0 +1,4 @@
1@ClientOnly
2package lv.enes.mc.eris_alchemy.client;
3
4import org.quiltmc.loader.api.minecraft.ClientOnly; \ No newline at end of file
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java b/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java
new file mode 100644
index 0000000..e4135c9
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java
@@ -0,0 +1,91 @@
1package lv.enes.mc.eris_alchemy.menu;
2
3import jakarta.annotation.Nonnull;
4import net.minecraft.world.Container;
5import net.minecraft.world.SimpleContainer;
6import net.minecraft.world.entity.player.Inventory;
7import net.minecraft.world.entity.player.Player;
8import net.minecraft.world.inventory.AbstractContainerMenu;
9import net.minecraft.world.inventory.Slot;
10import net.minecraft.world.item.ItemStack;
11
12public class AlchemicalChestMenu extends AbstractContainerMenu {
13 private static final int WIDTH = 13;
14 private static final int HEIGHT = 8;
15
16 private final Container container;
17
18 public AlchemicalChestMenu(int syncId, Inventory playerInventory) {
19 this(syncId, playerInventory, new SimpleContainer(WIDTH * HEIGHT));
20 }
21
22 public AlchemicalChestMenu(int syncId, Inventory playerInventory, Container inventory) {
23 super(ErisAlchemyMenus.ALCHEMICAL_CHEST, syncId);
24 checkContainerSize(inventory, WIDTH * HEIGHT);
25
26 this.container = inventory;
27 inventory.startOpen(playerInventory.player);
28
29 var x_off = 8;
30 var y_off = 8;
31
32 for (var y = 0; y < HEIGHT; y++) {
33 for (var x = 0; x < WIDTH; x++ ) {
34 addSlot(new Slot(inventory, y * WIDTH + x, x_off + x * 18, y_off + y * 18));
35 }
36 }
37
38 x_off = 44;
39 y_off = 155;
40
41 for (var y = 0; y < 3; y++) {
42 for (var x = 0; x < 9; x++) {
43 addSlot(new Slot(playerInventory, y * 9 + x + 9, x_off + x * 18, y_off + y * 18));
44 }
45 }
46
47 y_off = 213;
48
49 for (var x = 0; x < 9; x++) {
50 addSlot(new Slot(playerInventory, x, x_off + x * 18, y_off));
51 }
52 }
53
54 public Container getContainer() {
55 return container;
56 }
57
58 @Nonnull
59 @Override
60 public ItemStack quickMoveStack(Player player, int fromIndex) {
61 var newStack = ItemStack.EMPTY;
62 var slot = slots.get(fromIndex);
63 if (!slot.hasItem()) {
64 return newStack;
65 }
66
67 var originalStack = slot.getItem();
68 newStack = originalStack.copy();
69
70 if (fromIndex < container.getContainerSize()) {
71 if (!moveItemStackTo(originalStack, container.getContainerSize(), slots.size(), true)) {
72 return ItemStack.EMPTY;
73 }
74 } else if (!moveItemStackTo(originalStack, 0, container.getContainerSize(), false)) {
75 return ItemStack.EMPTY;
76 }
77
78 if (originalStack.isEmpty()) {
79 slot.setByPlayer(ItemStack.EMPTY);
80 } else {
81 slot.setChanged();
82 }
83
84 return newStack;
85 }
86
87 @Override
88 public boolean stillValid(Player player) {
89 return container.stillValid(player);
90 }
91}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/menu/ErisAlchemyMenus.java b/src/main/java/lv/enes/mc/eris_alchemy/menu/ErisAlchemyMenus.java
new file mode 100644
index 0000000..5e3b54a
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/menu/ErisAlchemyMenus.java
@@ -0,0 +1,29 @@
1package lv.enes.mc.eris_alchemy.menu;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import net.minecraft.resources.ResourceLocation;
5import net.minecraft.world.flag.FeatureFlags;
6import net.minecraft.world.inventory.AbstractContainerMenu;
7import net.minecraft.world.inventory.MenuType;
8
9import java.util.LinkedHashMap;
10import java.util.Map;
11import java.util.function.BiConsumer;
12
13public final class ErisAlchemyMenus {
14 private static final Map<ResourceLocation, MenuType<?>> menus = new LinkedHashMap<>();
15
16 public static final MenuType<AlchemicalChestMenu> ALCHEMICAL_CHEST = register("alchemy_chest", AlchemicalChestMenu::new);
17
18 public static void consumeMenus(BiConsumer<? super ResourceLocation, ? super MenuType<?>> consumer) {
19 menus.forEach(consumer);
20 }
21
22 private static <T extends AbstractContainerMenu> MenuType<T> register(String id, MenuType.MenuSupplier<T> supplier) {
23 var menuType = new MenuType<>(supplier, FeatureFlags.VANILLA_SET);
24 menus.putIfAbsent(new ResourceLocation(ErisAlchemy.ID, id), menuType);
25 return menuType;
26 }
27
28 private ErisAlchemyMenus() {}
29}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/SheetsMixin.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/SheetsMixin.java
new file mode 100644
index 0000000..544dcef
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/SheetsMixin.java
@@ -0,0 +1,22 @@
1package lv.enes.mc.eris_alchemy.mixin.client;
2
3import lv.enes.mc.eris_alchemy.client.ErisAlchemyMaterials;
4import lv.enes.mc.eris_alchemy.block.entity.AlchemicalChestBlockEntity;
5import net.minecraft.client.renderer.Sheets;
6import net.minecraft.client.resources.model.Material;
7import net.minecraft.world.level.block.entity.BlockEntity;
8import net.minecraft.world.level.block.state.properties.ChestType;
9import org.spongepowered.asm.mixin.Mixin;
10import org.spongepowered.asm.mixin.injection.At;
11import org.spongepowered.asm.mixin.injection.Inject;
12import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
13
14@Mixin(Sheets.class)
15public abstract class SheetsMixin {
16 @Inject(method = "chooseMaterial(Lnet/minecraft/world/level/block/entity/BlockEntity;Lnet/minecraft/world/level/block/state/properties/ChestType;Z)Lnet/minecraft/client/resources/model/Material;", at = @At("RETURN"), cancellable = true)
17 private static void chooseMaterial(BlockEntity entity, ChestType type, boolean christmas, CallbackInfoReturnable<Material> cir) {
18 if (entity instanceof AlchemicalChestBlockEntity) {
19 cir.setReturnValue(ErisAlchemyMaterials.ALCHEMICAL_CHEST);
20 }
21 }
22}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/package-info.java b/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/package-info.java
new file mode 100644
index 0000000..f7d5ada
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/mixin/client/package-info.java
@@ -0,0 +1,4 @@
1@ClientOnly
2package lv.enes.mc.eris_alchemy.mixin.client;
3
4import org.quiltmc.loader.api.minecraft.ClientOnly; \ No newline at end of file
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/CovalenceRepair.java b/src/main/java/lv/enes/mc/eris_alchemy/recipe/CovalenceRepair.java
index f094342..dca464a 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/CovalenceRepair.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/recipe/CovalenceRepair.java
@@ -1,4 +1,4 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy.recipe;
2 2
3import com.google.gson.Gson; 3import com.google.gson.Gson;
4import com.google.gson.JsonElement; 4import com.google.gson.JsonElement;
@@ -29,10 +29,7 @@ public class CovalenceRepair extends CustomRecipe {
29 JsonElement tools = new JsonObject(); 29 JsonElement tools = new JsonObject();
30 } 30 }
31 31
32 private Serializer() {} 32 Serializer() {}
33
34 public static final Serializer INSTANCE = new Serializer();
35 public static final ResourceLocation ID = new ResourceLocation(ErisAlchemy.ID, "covalence_repair");
36 33
37 @Override 34 @Override
38 public JsonObject toJson(CovalenceRepair recipe) { 35 public JsonObject toJson(CovalenceRepair recipe) {
@@ -124,7 +121,7 @@ public class CovalenceRepair extends CustomRecipe {
124 @Nonnull 121 @Nonnull
125 @Override 122 @Override
126 public RecipeSerializer<CovalenceRepair> getSerializer() { 123 public RecipeSerializer<CovalenceRepair> getSerializer() {
127 return Serializer.INSTANCE; 124 return ErisAlchemyRecipeSerializers.COVALENCE_REPAIR;
128 } 125 }
129 126
130 private boolean isTool(ItemStack stack) { 127 private boolean isTool(ItemStack stack) {
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/recipe/ErisAlchemyRecipeSerializers.java b/src/main/java/lv/enes/mc/eris_alchemy/recipe/ErisAlchemyRecipeSerializers.java
new file mode 100644
index 0000000..c5a6676
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/recipe/ErisAlchemyRecipeSerializers.java
@@ -0,0 +1,27 @@
1package lv.enes.mc.eris_alchemy.recipe;
2
3import lv.enes.mc.eris_alchemy.ErisAlchemy;
4import net.minecraft.resources.ResourceLocation;
5import net.minecraft.world.item.crafting.Recipe;
6import net.minecraft.world.item.crafting.RecipeSerializer;
7
8import java.util.LinkedHashMap;
9import java.util.Map;
10import java.util.function.BiConsumer;
11
12public final class ErisAlchemyRecipeSerializers {
13 private static final Map<ResourceLocation, RecipeSerializer<?>> serializers = new LinkedHashMap<>();
14
15 public static final RecipeSerializer<CovalenceRepair> COVALENCE_REPAIR = register("covalence_repair", new CovalenceRepair.Serializer());
16
17 public static void consumeSerializers(BiConsumer<? super ResourceLocation, ? super RecipeSerializer<?>> consumer) {
18 serializers.forEach(consumer);
19 }
20
21 private static <T extends Recipe<?>> RecipeSerializer<T> register(String id, RecipeSerializer<T> serializer) {
22 serializers.putIfAbsent(new ResourceLocation(ErisAlchemy.ID, id), serializer);
23 return serializer;
24 }
25
26 private ErisAlchemyRecipeSerializers() {}
27}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/SubAxe.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java
index 045a5a1..22c0bad 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/SubAxe.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/AxeUtils.java
@@ -1,4 +1,4 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy.utils;
2 2
3import net.minecraft.world.item.AxeItem; 3import net.minecraft.world.item.AxeItem;
4import net.minecraft.world.item.Tier; 4import net.minecraft.world.item.Tier;
@@ -6,13 +6,13 @@ import net.minecraft.world.level.block.Block;
6 6
7import java.util.Map; 7import java.util.Map;
8 8
9/** The only reason this exists is to read STRIPPABLES property from AxeItem :3 */ 9/** This extends AxeItem only to read the STRIPPABLES variable :3 */
10public abstract class SubAxe extends AxeItem { 10public final class AxeUtils extends AxeItem {
11 public static Map<Block, Block> getStrippables() { 11 public static Map<Block, Block> getStrippables() {
12 return STRIPPABLES; 12 return STRIPPABLES;
13 } 13 }
14 14
15 private SubAxe(Tier material, float attackDamage, float attackSpeed, Properties settings) { 15 private AxeUtils(Tier material, float attackDamage, float attackSpeed, Properties settings) {
16 super(material, attackDamage, attackSpeed, settings); 16 super(material, attackDamage, attackSpeed, settings);
17 } 17 }
18} 18}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java
index 74b6069..88b6231 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/BlockUtils.java
@@ -6,8 +6,10 @@ import net.minecraft.world.level.block.Block;
6 6
7import java.util.stream.Stream; 7import java.util.stream.Stream;
8 8
9public class BlockUtils { 9public final class BlockUtils {
10 public static Stream<Block> streamTag(TagKey<Block> tag) { 10 public static Stream<Block> streamTag(TagKey<Block> tag) {
11 return TagUtils.stream(BuiltInRegistries.BLOCK, tag); 11 return TagUtils.stream(BuiltInRegistries.BLOCK, tag);
12 } 12 }
13
14 private BlockUtils() {}
13} 15}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java
index c9203c6..1136c9e 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/CoralUtils.java
@@ -5,7 +5,7 @@ import net.minecraft.world.level.block.*;
5 5
6import java.util.stream.Stream; 6import java.util.stream.Stream;
7 7
8public class CoralUtils { 8public final class CoralUtils {
9 /** 9 /**
10 * @see lv.enes.mc.eris_alchemy.mixin.CoralBlockMixin 10 * @see lv.enes.mc.eris_alchemy.mixin.CoralBlockMixin
11 * @see lv.enes.mc.eris_alchemy.mixin.CoralFanBlockMixin 11 * @see lv.enes.mc.eris_alchemy.mixin.CoralFanBlockMixin
@@ -39,4 +39,6 @@ public class CoralUtils {
39 public static Block getDeadCoralBlock(CoralBlock live) { 39 public static Block getDeadCoralBlock(CoralBlock live) {
40 return ((CoralSuper)live).lv_enes_mc$getDead(); 40 return ((CoralSuper)live).lv_enes_mc$getDead();
41 } 41 }
42
43 private CoralUtils() {}
42} 44}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java
index 83c8e04..3ceb965 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/DyeUtils.java
@@ -7,7 +7,7 @@ import net.minecraft.world.level.block.Blocks;
7import net.minecraft.world.level.block.ConcretePowderBlock; 7import net.minecraft.world.level.block.ConcretePowderBlock;
8import net.minecraft.world.level.block.ShulkerBoxBlock; 8import net.minecraft.world.level.block.ShulkerBoxBlock;
9 9
10public class DyeUtils { 10public final class DyeUtils {
11 public static Block getConcrete(DyeColor color) { 11 public static Block getConcrete(DyeColor color) {
12 return switch (color) { 12 return switch (color) {
13 case BLACK -> Blocks.BLACK_CONCRETE; 13 case BLACK -> Blocks.BLACK_CONCRETE;
@@ -57,4 +57,6 @@ public class DyeUtils {
57 public static ShulkerBoxBlock getShulkerBox(DyeColor color) { 57 public static ShulkerBoxBlock getShulkerBox(DyeColor color) {
58 return (ShulkerBoxBlock)ShulkerBoxBlock.getBlockByColor(color); 58 return (ShulkerBoxBlock)ShulkerBoxBlock.getBlockByColor(color);
59 } 59 }
60
61 private DyeUtils() {}
60} 62}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
index 2f7c8b2..26d4405 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/ItemUtils.java
@@ -6,8 +6,10 @@ import net.minecraft.world.item.Item;
6 6
7import java.util.stream.Stream; 7import java.util.stream.Stream;
8 8
9public class ItemUtils { 9public final class ItemUtils {
10 public static Stream<Item> streamTag(TagKey<Item> tag) { 10 public static Stream<Item> streamTag(TagKey<Item> tag) {
11 return TagUtils.stream(BuiltInRegistries.ITEM, tag); 11 return TagUtils.stream(BuiltInRegistries.ITEM, tag);
12 } 12 }
13
14 private ItemUtils() {}
13} 15}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/RecipeUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/RecipeUtils.java
index 53ceaab..0eb6a2c 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/RecipeUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/RecipeUtils.java
@@ -7,7 +7,7 @@ import net.minecraft.world.item.crafting.Recipe;
7 7
8import java.util.List; 8import java.util.List;
9 9
10public class RecipeUtils { 10public final class RecipeUtils {
11 public interface RecipeSuper { 11 public interface RecipeSuper {
12 List<Ingredient> lv_enes_mc$getIngredients(); 12 List<Ingredient> lv_enes_mc$getIngredients();
13 ItemStack lv_enes_mc$getOutput(RegistryAccess registryAccess); 13 ItemStack lv_enes_mc$getOutput(RegistryAccess registryAccess);
@@ -20,4 +20,6 @@ public class RecipeUtils {
20 public static ItemStack getOutput(Recipe<?> recipe, RegistryAccess registryAccess) { 20 public static ItemStack getOutput(Recipe<?> recipe, RegistryAccess registryAccess) {
21 return ((RecipeSuper)recipe).lv_enes_mc$getOutput(registryAccess); 21 return ((RecipeSuper)recipe).lv_enes_mc$getOutput(registryAccess);
22 } 22 }
23
24 private RecipeUtils() {}
23} 25}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java
index bb923ba..93e577f 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/TagUtils.java
@@ -7,8 +7,10 @@ import net.minecraft.tags.TagKey;
7import java.util.stream.Stream; 7import java.util.stream.Stream;
8import java.util.stream.StreamSupport; 8import java.util.stream.StreamSupport;
9 9
10public class TagUtils { 10public final class TagUtils {
11 public static <T> Stream<T> stream(Registry<T> registry, TagKey<T> tag) { 11 public static <T> Stream<T> stream(Registry<T> registry, TagKey<T> tag) {
12 return StreamSupport.stream(registry.getTagOrEmpty(tag).spliterator(), false).map(Holder::value); 12 return StreamSupport.stream(registry.getTagOrEmpty(tag).spliterator(), false).map(Holder::value);
13 } 13 }
14
15 private TagUtils() {}
14} 16}
diff --git a/src/main/resources/assets/eris_alchemy/blockstates/alchemical_chest.json b/src/main/resources/assets/eris_alchemy/blockstates/alchemical_chest.json
new file mode 100644
index 0000000..e04b5f5
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/blockstates/alchemical_chest.json
@@ -0,0 +1,7 @@
1{
2 "variants": {
3 "": {
4 "model": "eris_alchemy:block/alchemical_chest"
5 }
6 }
7} \ No newline at end of file
diff --git a/src/main/resources/assets/eris_alchemy/icon.png b/src/main/resources/assets/eris_alchemy/icon.png
index 09015e4..89c12c2 100644
--- a/src/main/resources/assets/eris_alchemy/icon.png
+++ b/src/main/resources/assets/eris_alchemy/icon.png
Binary files differ
diff --git a/src/main/resources/assets/eris_alchemy/lang/en_us.json b/src/main/resources/assets/eris_alchemy/lang/en_us.json
index c001018..ed007dd 100644
--- a/src/main/resources/assets/eris_alchemy/lang/en_us.json
+++ b/src/main/resources/assets/eris_alchemy/lang/en_us.json
@@ -1,8 +1,12 @@
1{ 1{
2 "block.eris_alchemy.alchemical_chest": "Alchemical Chest",
3
2 "book.eris_alchemy.title": "Eris Alchemy", 4 "book.eris_alchemy.title": "Eris Alchemy",
3 "book.eris_alchemy.subtitle": "the Official Guide", 5 "book.eris_alchemy.subtitle": "the Official Guide",
4 "book.eris_alchemy.landing_text": "Welcome to Alchemy!", 6 "book.eris_alchemy.landing_text": "Welcome to Alchemy!",
5 7
8 "container.eris_alchemy.alchemical_chest": "Alchemical Chest",
9
6 "item.eris_alchemy.low_covalence_dust": "Low Covalence Dust", 10 "item.eris_alchemy.low_covalence_dust": "Low Covalence Dust",
7 "item.eris_alchemy.medium_covalence_dust": "Medium Covalence Dust", 11 "item.eris_alchemy.medium_covalence_dust": "Medium Covalence Dust",
8 "item.eris_alchemy.high_covalence_dust": "High Covalence Dust", 12 "item.eris_alchemy.high_covalence_dust": "High Covalence Dust",
diff --git a/src/main/resources/assets/eris_alchemy/models/block/alchemical_chest.json b/src/main/resources/assets/eris_alchemy/models/block/alchemical_chest.json
new file mode 100644
index 0000000..84acbec
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/models/block/alchemical_chest.json
@@ -0,0 +1,5 @@
1{
2 "textures": {
3 "particle": "minecraft:block/stone"
4 }
5} \ No newline at end of file
diff --git a/src/main/resources/assets/eris_alchemy/models/item/alchemical_chest.json b/src/main/resources/assets/eris_alchemy/models/item/alchemical_chest.json
new file mode 100644
index 0000000..62b3156
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/models/item/alchemical_chest.json
@@ -0,0 +1,6 @@
1{
2 "parent": "item/chest",
3 "textures": {
4 "particle": "block/stone"
5 }
6} \ No newline at end of file
diff --git a/src/main/resources/assets/eris_alchemy/patchouli_books/guide_book/en_us/entries/root/alchemical_chest.json b/src/main/resources/assets/eris_alchemy/patchouli_books/guide_book/en_us/entries/root/alchemical_chest.json
new file mode 100644
index 0000000..bd594f6
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/patchouli_books/guide_book/en_us/entries/root/alchemical_chest.json
@@ -0,0 +1,14 @@
1{
2 "name": "Alchemical Chest",
3 "icon": "eris_alchemy:alchemical_chest",
4 "category": "eris_alchemy:root",
5 "pages": [{
6 "type": "patchouli:spotlight",
7 "item": "eris_alchemy:alchemical_chest",
8 "link_recipe": true,
9 "text": "$(item)Alchemical Chest$() is a chest with a giant inventory space (104 slots)."
10 }, {
11 "type": "patchouli:crafting",
12 "recipe": "eris_alchemy:alchemical_chest"
13 }]
14} \ No newline at end of file
diff --git a/src/main/resources/assets/eris_alchemy/textures/entity/chest/alchemical_chest.png b/src/main/resources/assets/eris_alchemy/textures/entity/chest/alchemical_chest.png
new file mode 100644
index 0000000..cc75ed1
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/textures/entity/chest/alchemical_chest.png
Binary files differ
diff --git a/src/main/resources/assets/eris_alchemy/textures/gui/container/alchemical_chest.png b/src/main/resources/assets/eris_alchemy/textures/gui/container/alchemical_chest.png
new file mode 100644
index 0000000..fe06cf6
--- /dev/null
+++ b/src/main/resources/assets/eris_alchemy/textures/gui/container/alchemical_chest.png
Binary files differ
diff --git a/src/main/resources/data/eris_alchemy/loot_tables/blocks/alchemical_chest.json b/src/main/resources/data/eris_alchemy/loot_tables/blocks/alchemical_chest.json
new file mode 100644
index 0000000..a552e23
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/loot_tables/blocks/alchemical_chest.json
@@ -0,0 +1,13 @@
1{
2 "type": "minecraft:block",
3 "pools": [{
4 "rolls": 1,
5 "entries": [{
6 "type": "minecraft:item",
7 "name": "eris_alchemy:alchemical_chest"
8 }],
9 "conditions": [{
10 "condition": "minecraft:survives_explosion"
11 }]
12 }]
13} \ No newline at end of file
diff --git a/src/main/resources/data/eris_alchemy/recipes/alchemical_chest.json b/src/main/resources/data/eris_alchemy/recipes/alchemical_chest.json
new file mode 100644
index 0000000..7c97900
--- /dev/null
+++ b/src/main/resources/data/eris_alchemy/recipes/alchemical_chest.json
@@ -0,0 +1,34 @@
1{
2 "type": "crafting_shaped",
3 "pattern": [
4 "123",
5 "SDS",
6 "ICI"
7 ],
8 "key": {
9 "1": {
10 "item": "eris_alchemy:low_covalence_dust"
11 },
12 "2": {
13 "item": "eris_alchemy:medium_covalence_dust"
14 },
15 "3": {
16 "item": "eris_alchemy:high_covalence_dust"
17 },
18 "S": {
19 "item": "minecraft:stone"
20 },
21 "D": {
22 "item": "minecraft:diamond"
23 },
24 "I": {
25 "item": "minecraft:iron_ingot"
26 },
27 "C": {
28 "item": "minecraft:chest"
29 }
30 },
31 "result": {
32 "item": "eris_alchemy:alchemical_chest"
33 }
34} \ No newline at end of file
diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json
new file mode 100644
index 0000000..27c0b6d
--- /dev/null
+++ b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json
@@ -0,0 +1,6 @@
1{
2 "replace": false,
3 "values": [
4 "eris_alchemy:alchemical_chest"
5 ]
6} \ No newline at end of file
diff --git a/src/main/resources/eris_alchemy.mixins.json b/src/main/resources/eris_alchemy.mixins.json
index 56177c0..36cb47f 100644
--- a/src/main/resources/eris_alchemy.mixins.json
+++ b/src/main/resources/eris_alchemy.mixins.json
@@ -3,6 +3,9 @@
3 "minVersion": "0.8", 3 "minVersion": "0.8",
4 "package": "lv.enes.mc.eris_alchemy.mixin", 4 "package": "lv.enes.mc.eris_alchemy.mixin",
5 "compatibilityLevel": "JAVA_17", 5 "compatibilityLevel": "JAVA_17",
6 "client": [
7 "client.SheetsMixin"
8 ],
6 "mixins": [ 9 "mixins": [
7 "CoralBlockMixin", 10 "CoralBlockMixin",
8 "CoralFanBlockMixin", 11 "CoralFanBlockMixin",
diff --git a/src/main/resources/quilt.mod.json b/src/main/resources/quilt.mod.json
index 873c25f..5b6373a 100644
--- a/src/main/resources/quilt.mod.json
+++ b/src/main/resources/quilt.mod.json
@@ -19,7 +19,8 @@
19 }, 19 },
20 "intermediate_mappings": "net.fabricmc:intermediary", 20 "intermediate_mappings": "net.fabricmc:intermediary",
21 "entrypoints": { 21 "entrypoints": {
22 "init": "lv.enes.mc.eris_alchemy.ErisAlchemy" 22 "init": "lv.enes.mc.eris_alchemy.ErisAlchemy",
23 "client_init": "lv.enes.mc.eris_alchemy.client.ErisAlchemyClient"
23 }, 24 },
24 "depends": [{ 25 "depends": [{
25 "id": "quilt_loader", 26 "id": "quilt_loader",