Skip to content

Commit bb5d441

Browse files
committed
basic block entity
1 parent 019c9f2 commit bb5d441

File tree

12 files changed

+589
-0
lines changed

12 files changed

+589
-0
lines changed

src/main/java/net/kaupenjoe/tutorialmod/TutorialMod.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
99
import net.fabricmc.fabric.api.registry.*;
1010
import net.kaupenjoe.tutorialmod.block.ModBlocks;
11+
import net.kaupenjoe.tutorialmod.block.entity.ModBlockEntities;
1112
import net.kaupenjoe.tutorialmod.component.ModDataComponentTypes;
1213
import net.kaupenjoe.tutorialmod.effect.ModEffects;
1314
import net.kaupenjoe.tutorialmod.enchantment.ModEnchantmentEffects;
@@ -64,6 +65,8 @@ public void onInitialize() {
6465
ModParticles.registerParticles();
6566
ModLootTableModifiers.modifyLootTables();
6667

68+
ModBlockEntities.registerBlockEntities();
69+
6770
FuelRegistry.INSTANCE.add(ModItems.STARLIGHT_ASHES, 600);
6871

6972
PlayerBlockBreakEvents.BEFORE.register(new HammerUsageEvent());

src/main/java/net/kaupenjoe/tutorialmod/block/ModBlocks.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public class ModBlocks {
9696
public static final Block CHAIR = registerBlock("chair",
9797
new ChairBlock(AbstractBlock.Settings.create().nonOpaque()));
9898

99+
public static final Block PEDESTAL = registerBlock("pedestal",
100+
new PedestalBlock(AbstractBlock.Settings.create().nonOpaque()));
101+
99102

100103

101104
private static Block registerBlockWithoutBlockItem(String name, Block block) {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package net.kaupenjoe.tutorialmod.block.custom;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import net.kaupenjoe.tutorialmod.block.entity.custom.PedestalBlockEntity;
5+
import net.minecraft.block.*;
6+
import net.minecraft.block.entity.BlockEntity;
7+
import net.minecraft.entity.player.PlayerEntity;
8+
import net.minecraft.item.ItemStack;
9+
import net.minecraft.sound.SoundCategory;
10+
import net.minecraft.sound.SoundEvents;
11+
import net.minecraft.util.Hand;
12+
import net.minecraft.util.ItemActionResult;
13+
import net.minecraft.util.ItemScatterer;
14+
import net.minecraft.util.hit.BlockHitResult;
15+
import net.minecraft.util.math.BlockPos;
16+
import net.minecraft.util.shape.VoxelShape;
17+
import net.minecraft.world.BlockView;
18+
import net.minecraft.world.World;
19+
import org.jetbrains.annotations.Nullable;
20+
21+
public class PedestalBlock extends BlockWithEntity implements BlockEntityProvider {
22+
private static final VoxelShape SHAPE =
23+
Block.createCuboidShape(2, 0, 2, 14, 13, 14);
24+
public static final MapCodec<PedestalBlock> CODEC = PedestalBlock.createCodec(PedestalBlock::new);
25+
26+
public PedestalBlock(Settings settings) {
27+
super(settings);
28+
}
29+
30+
@Override
31+
protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
32+
return SHAPE;
33+
}
34+
35+
@Override
36+
protected MapCodec<? extends BlockWithEntity> getCodec() {
37+
return CODEC;
38+
}
39+
40+
@Nullable
41+
@Override
42+
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
43+
return new PedestalBlockEntity(pos, state);
44+
}
45+
46+
@Override
47+
protected BlockRenderType getRenderType(BlockState state) {
48+
return BlockRenderType.MODEL;
49+
}
50+
51+
@Override
52+
protected void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
53+
if(state.getBlock() != newState.getBlock()) {
54+
BlockEntity blockEntity = world.getBlockEntity(pos);
55+
if(blockEntity instanceof PedestalBlockEntity) {
56+
ItemScatterer.spawn(world, pos, ((PedestalBlockEntity) blockEntity));
57+
world.updateComparators(pos, this);
58+
}
59+
super.onStateReplaced(state, world, pos, newState, moved);
60+
}
61+
}
62+
63+
@Override
64+
protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos,
65+
PlayerEntity player, Hand hand, BlockHitResult hit) {
66+
if(world.getBlockEntity(pos) instanceof PedestalBlockEntity pedestalBlockEntity) {
67+
if(pedestalBlockEntity.isEmpty() && !stack.isEmpty()) {
68+
pedestalBlockEntity.setStack(0, stack.copyWithCount(1));
69+
world.playSound(player, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 1f, 2f);
70+
stack.decrement(1);
71+
72+
pedestalBlockEntity.markDirty();
73+
world.updateListeners(pos, state, state, 0);
74+
} else if(stack.isEmpty() && !player.isSneaking()) {
75+
ItemStack stackOnPedestal = pedestalBlockEntity.getStack(0);
76+
player.setStackInHand(Hand.MAIN_HAND, stackOnPedestal);
77+
world.playSound(player, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 1f, 1f);
78+
pedestalBlockEntity.clear();
79+
80+
pedestalBlockEntity.markDirty();
81+
world.updateListeners(pos, state, state, 0);
82+
}
83+
}
84+
85+
return ItemActionResult.SUCCESS;
86+
}
87+
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package net.kaupenjoe.tutorialmod.block.entity;
2+
3+
import net.minecraft.entity.player.PlayerEntity;
4+
import net.minecraft.inventory.Inventories;
5+
import net.minecraft.inventory.Inventory;
6+
import net.minecraft.inventory.SidedInventory;
7+
import net.minecraft.item.ItemStack;
8+
import net.minecraft.nbt.NbtCompound;
9+
import net.minecraft.registry.RegistryWrapper;
10+
import net.minecraft.util.collection.DefaultedList;
11+
import net.minecraft.util.math.Direction;
12+
import org.jetbrains.annotations.Nullable;
13+
14+
import java.util.List;
15+
16+
/**
17+
* A simple {@code SidedInventory} implementation with only default methods + an item list getter.
18+
*
19+
* <h2>Reading and writing to tags</h2>
20+
* Use {@link Inventories#writeNbt(NbtCompound, DefaultedList, RegistryWrapper.WrapperLookup)} and
21+
* {@link Inventories#readNbt(NbtCompound, DefaultedList, RegistryWrapper.WrapperLookup)}
22+
* on {@linkplain #getItems() the item list}.
23+
*
24+
* License: <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>
25+
* @author Juuz
26+
*/
27+
@FunctionalInterface
28+
public interface ImplementedInventory extends SidedInventory {
29+
/**
30+
* Gets the item list of this inventory.
31+
* Must return the same instance every time it's called.
32+
*
33+
* @return the item list
34+
*/
35+
DefaultedList<ItemStack> getItems();
36+
37+
/**
38+
* Creates an inventory from the item list.
39+
*
40+
* @param items the item list
41+
* @return a new inventory
42+
*/
43+
static ImplementedInventory of(DefaultedList<ItemStack> items) {
44+
return () -> items;
45+
}
46+
47+
/**
48+
* Creates a new inventory with the size.
49+
*
50+
* @param size the inventory size
51+
* @return a new inventory
52+
*/
53+
static ImplementedInventory ofSize(int size) {
54+
return of(DefaultedList.ofSize(size, ItemStack.EMPTY));
55+
}
56+
57+
// SidedInventory
58+
59+
/**
60+
* Gets the available slots to automation on the side.
61+
*
62+
* <p>The default implementation returns an array of all slots.
63+
*
64+
* @param side the side
65+
* @return the available slots
66+
*/
67+
@Override
68+
default int[] getAvailableSlots(Direction side) {
69+
int[] result = new int[getItems().size()];
70+
for (int i = 0; i < result.length; i++) {
71+
result[i] = i;
72+
}
73+
74+
return result;
75+
}
76+
77+
/**
78+
* Returns true if the stack can be inserted in the slot at the side.
79+
*
80+
* <p>The default implementation returns true.
81+
*
82+
* @param slot the slot
83+
* @param stack the stack
84+
* @param side the side
85+
* @return true if the stack can be inserted
86+
*/
87+
@Override
88+
default boolean canInsert(int slot, ItemStack stack, @Nullable Direction side) {
89+
return true;
90+
}
91+
92+
/**
93+
* Returns true if the stack can be extracted from the slot at the side.
94+
*
95+
* <p>The default implementation returns true.
96+
*
97+
* @param slot the slot
98+
* @param stack the stack
99+
* @param side the side
100+
* @return true if the stack can be extracted
101+
*/
102+
@Override
103+
default boolean canExtract(int slot, ItemStack stack, Direction side) {
104+
return true;
105+
}
106+
107+
// Inventory
108+
109+
/**
110+
* Returns the inventory size.
111+
*
112+
* <p>The default implementation returns the size of {@link #getItems()}.
113+
*
114+
* @return the inventory size
115+
*/
116+
@Override
117+
default int size() {
118+
return getItems().size();
119+
}
120+
121+
/**
122+
* @return true if this inventory has only empty stacks, false otherwise
123+
*/
124+
@Override
125+
default boolean isEmpty() {
126+
for (int i = 0; i < size(); i++) {
127+
ItemStack stack = getStack(i);
128+
if (!stack.isEmpty()) {
129+
return false;
130+
}
131+
}
132+
133+
return true;
134+
}
135+
136+
/**
137+
* Gets the item in the slot.
138+
*
139+
* @param slot the slot
140+
* @return the item in the slot
141+
*/
142+
@Override
143+
default ItemStack getStack(int slot) {
144+
return getItems().get(slot);
145+
}
146+
147+
/**
148+
* Takes a stack of the size from the slot.
149+
*
150+
* <p>(default implementation) If there are less items in the slot than what are requested,
151+
* takes all items in that slot.
152+
*
153+
* @param slot the slot
154+
* @param count the item count
155+
* @return a stack
156+
*/
157+
@Override
158+
default ItemStack removeStack(int slot, int count) {
159+
ItemStack result = Inventories.splitStack(getItems(), slot, count);
160+
if (!result.isEmpty()) {
161+
markDirty();
162+
}
163+
164+
return result;
165+
}
166+
167+
/**
168+
* Removes the current stack in the {@code slot} and returns it.
169+
*
170+
* <p>The default implementation uses {@link Inventories#removeStack(List, int)}
171+
*
172+
* @param slot the slot
173+
* @return the removed stack
174+
*/
175+
@Override
176+
default ItemStack removeStack(int slot) {
177+
return Inventories.removeStack(getItems(), slot);
178+
}
179+
180+
/**
181+
* Replaces the current stack in the {@code slot} with the provided stack.
182+
*
183+
* <p>If the stack is too big for this inventory ({@link Inventory#getMaxCountPerStack()}),
184+
* it gets resized to this inventory's maximum amount.
185+
*
186+
* @param slot the slot
187+
* @param stack the stack
188+
*/
189+
@Override
190+
default void setStack(int slot, ItemStack stack) {
191+
getItems().set(slot, stack);
192+
if (stack.getCount() > getMaxCountPerStack()) {
193+
stack.setCount(getMaxCountPerStack());
194+
}
195+
}
196+
197+
/**
198+
* Clears {@linkplain #getItems() the item list}}.
199+
*/
200+
@Override
201+
default void clear() {
202+
getItems().clear();
203+
}
204+
205+
@Override
206+
default void markDirty() {
207+
// Override if you want behavior.
208+
}
209+
210+
@Override
211+
default boolean canPlayerUse(PlayerEntity player) {
212+
return true;
213+
}
214+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.kaupenjoe.tutorialmod.block.entity;
2+
3+
import net.kaupenjoe.tutorialmod.TutorialMod;
4+
import net.kaupenjoe.tutorialmod.block.ModBlocks;
5+
import net.kaupenjoe.tutorialmod.block.entity.custom.PedestalBlockEntity;
6+
import net.minecraft.block.entity.BlockEntityType;
7+
import net.minecraft.registry.Registries;
8+
import net.minecraft.registry.Registry;
9+
import net.minecraft.util.Identifier;
10+
11+
public class ModBlockEntities {
12+
public static final BlockEntityType<PedestalBlockEntity> PEDESTAL_BE =
13+
Registry.register(Registries.BLOCK_ENTITY_TYPE, Identifier.of(TutorialMod.MOD_ID, "pedestal_be"),
14+
BlockEntityType.Builder.create(PedestalBlockEntity::new, ModBlocks.PEDESTAL).build(null));
15+
16+
public static void registerBlockEntities() {
17+
TutorialMod.LOGGER.info("Registering Block Entities for " + TutorialMod.MOD_ID);
18+
}
19+
}

0 commit comments

Comments
 (0)