Skip to content

Commit

Permalink
tutorial stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
jiink committed Apr 16, 2024
1 parent 0c13887 commit 511799e
Show file tree
Hide file tree
Showing 8 changed files with 553 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/main/java/jiink/smeltinginapinch/DemoBlockEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void readNbt(NbtCompound nbt) {

public static void tick(World world, BlockPos pos, BlockState state, DemoBlockEntity be) {
if (!world.isClient) {
SmeltingInAPinch.LOGGER.info("Tick! " + be.number);
//SmeltingInAPinch.LOGGER.info("Tick! " + be.number);

}
}
Expand Down
213 changes: 213 additions & 0 deletions src/main/java/jiink/smeltinginapinch/ImplementedInventory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package jiink.smeltinginapinch;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventories;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.Nullable;

import java.util.List;

/**
* A simple {@code SidedInventory} implementation with only default methods + an item list getter.
*
* <h2>Reading and writing to tags</h2>
* Use {@link Inventories#writeNbt(NbtCompound, DefaultedList)} and {@link Inventories#readNbt(NbtCompound, DefaultedList)}
* on {@linkplain #getItems() the item list}.
*
* License: <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>
* @author Juuz
*/
@FunctionalInterface
public interface ImplementedInventory extends SidedInventory {
/**
* Gets the item list of this inventory.
* Must return the same instance every time it's called.
*
* @return the item list
*/
DefaultedList<ItemStack> getItems();

/**
* Creates an inventory from the item list.
*
* @param items the item list
* @return a new inventory
*/
static ImplementedInventory of(DefaultedList<ItemStack> items) {
return () -> items;
}

/**
* Creates a new inventory with the size.
*
* @param size the inventory size
* @return a new inventory
*/
static ImplementedInventory ofSize(int size) {
return of(DefaultedList.ofSize(size, ItemStack.EMPTY));
}

// SidedInventory

/**
* Gets the available slots to automation on the side.
*
* <p>The default implementation returns an array of all slots.
*
* @param side the side
* @return the available slots
*/
@Override
default int[] getAvailableSlots(Direction side) {
int[] result = new int[getItems().size()];
for (int i = 0; i < result.length; i++) {
result[i] = i;
}

return result;
}

/**
* Returns true if the stack can be inserted in the slot at the side.
*
* <p>The default implementation returns true.
*
* @param slot the slot
* @param stack the stack
* @param side the side
* @return true if the stack can be inserted
*/
@Override
default boolean canInsert(int slot, ItemStack stack, @Nullable Direction side) {
return true;
}

/**
* Returns true if the stack can be extracted from the slot at the side.
*
* <p>The default implementation returns true.
*
* @param slot the slot
* @param stack the stack
* @param side the side
* @return true if the stack can be extracted
*/
@Override
default boolean canExtract(int slot, ItemStack stack, Direction side) {
return true;
}

// Inventory

/**
* Returns the inventory size.
*
* <p>The default implementation returns the size of {@link #getItems()}.
*
* @return the inventory size
*/
@Override
default int size() {
return getItems().size();
}

/**
* @return true if this inventory has only empty stacks, false otherwise
*/
@Override
default boolean isEmpty() {
for (int i = 0; i < size(); i++) {
ItemStack stack = getStack(i);
if (!stack.isEmpty()) {
return false;
}
}

return true;
}

/**
* Gets the item in the slot.
*
* @param slot the slot
* @return the item in the slot
*/
@Override
default ItemStack getStack(int slot) {
return getItems().get(slot);
}

/**
* Takes a stack of the size from the slot.
*
* <p>(default implementation) If there are less items in the slot than what are requested,
* takes all items in that slot.
*
* @param slot the slot
* @param count the item count
* @return a stack
*/
@Override
default ItemStack removeStack(int slot, int count) {
ItemStack result = Inventories.splitStack(getItems(), slot, count);
if (!result.isEmpty()) {
markDirty();
}

return result;
}

/**
* Removes the current stack in the {@code slot} and returns it.
*
* <p>The default implementation uses {@link Inventories#removeStack(List, int)}
*
* @param slot the slot
* @return the removed stack
*/
@Override
default ItemStack removeStack(int slot) {
return Inventories.removeStack(getItems(), slot);
}

/**
* Replaces the current stack in the {@code slot} with the provided stack.
*
* <p>If the stack is too big for this inventory ({@link Inventory#getMaxCountPerStack()}),
* it gets resized to this inventory's maximum amount.
*
* @param slot the slot
* @param stack the stack
*/
@Override
default void setStack(int slot, ItemStack stack) {
getItems().set(slot, stack);
if (stack.getCount() > getMaxCountPerStack()) {
stack.setCount(getMaxCountPerStack());
}
markDirty();
}

/**
* Clears {@linkplain #getItems() the item list}}.
*/
@Override
default void clear() {
getItems().clear();
}

@Override
default void markDirty() {
// Override if you want behavior.
}

@Override
default boolean canPlayerUse(PlayerEntity player) {
return true;
}
}
16 changes: 15 additions & 1 deletion src/main/java/jiink/smeltinginapinch/SmeltingInAPinch.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType;
import net.minecraft.block.Block;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroups;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.screen.ScreenHandlerType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -20,6 +23,8 @@


public class SmeltingInAPinch implements ModInitializer {

public static final String MOD_ID = "smeltinginapinch";
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
public static final Logger LOGGER = LoggerFactory.getLogger("modid");
Expand All @@ -40,7 +45,7 @@ public class SmeltingInAPinch implements ModInitializer {
FabricBlockEntityTypeBuilder.create(DemoBlockEntity::new, DEMO_BLOCK).build()
);

public static final WoodenFurnaceBlock WOODEN_FURNACE_BLOCK = Registry.register(
public static final Block WOODEN_FURNACE_BLOCK = Registry.register(
Registries.BLOCK,
new Identifier("smeltinginapinch", "wooden_furnace"),
new WoodenFurnaceBlock(Block.Settings.create().strength(1.0f))
Expand All @@ -55,6 +60,12 @@ public class SmeltingInAPinch implements ModInitializer {
new Identifier("smeltinginapinch", "wooden_furnace_block_entity"),
FabricBlockEntityTypeBuilder.create(WoodenFurnaceBlockEntity::new, WOODEN_FURNACE_BLOCK).build()
);

public static final ScreenHandlerType<WoodenFurnaceScreenHandler> WOODEN_FURNACE_SCREEN_HANDLER = Registry.register(
Registries.SCREEN_HANDLER,
new Identifier("smeltinginapinch", "wooden_furnace_screen_handler"),
new ExtendedScreenHandlerType<>(WoodenFurnaceScreenHandler::new)
);
@Override
public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
Expand All @@ -66,5 +77,8 @@ public void onInitialize() {
content.addAfter(Items.BLAST_FURNACE, WOODEN_FURANCE_BLOCK_ITEM);
content.addAfter(Items.TORCH, DEMO_BLOCK_ITEM);
});

// Make sure screen handler and screen are linked together
HandledScreens.register(SmeltingInAPinch.WOODEN_FURNACE_SCREEN_HANDLER, WoodenFurnaceScreen::new);
}
}
56 changes: 51 additions & 5 deletions src/main/java/jiink/smeltinginapinch/WoodenFurnaceBlock.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jiink.smeltinginapinch;

import net.minecraft.block.AbstractFurnaceBlock;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
Expand All @@ -12,6 +13,11 @@
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
Expand All @@ -22,24 +28,64 @@

import com.mojang.serialization.MapCodec;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.AbstractBlock;

public class WoodenFurnaceBlock extends BlockWithEntity {
public WoodenFurnaceBlock(AbstractBlock.Settings settings) {
super(settings);
}

// @Nullable
// public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
// return world.isClient ? null : checkType(type, SmeltingInAPinch.WOODEN_FURNACE_BLOCK_ENTITY, WoodenFurnaceBlockEntity::tick);
// }

@Nullable
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
return validateTicker(type, SmeltingInAPinch.WOODEN_FURNACE_BLOCK_ENTITY, (world1, pos, state1, be) -> WoodenFurnaceBlockEntity.tick(world1, pos, state1));
}

@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new WoodenFurnaceBlockEntity(pos, state);
}

@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if (state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity = world.getBlockEntity(pos);
if (blockEntity instanceof WoodenFurnaceBlockEntity) {
ItemScatterer.spawn(world, pos, (WoodenFurnaceBlockEntity)blockEntity);
world.updateComparators(pos, this);
}
super.onStateReplaced(state, world, pos, newState, moved);
}
}

@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient && hand == Hand.MAIN_HAND) {
NamedScreenHandlerFactory screenHandlerFactory = (WoodenFurnaceBlockEntity)world.getBlockEntity(pos);
if (screenHandlerFactory != null) {
player.openHandledScreen(screenHandlerFactory);
}
}
return ActionResult.PASS;
}

@Environment(EnvType.CLIENT)
@Override
public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) {
double x = (double) pos.getX() + 0.5D;
double y = (double) pos.getY() + 1.0D;
double z = (double) pos.getZ() + 0.5D;

world.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0D, 0.0D, 0.0D);
world.addParticle(ParticleTypes.FLAME, x, y, z, 0.0D, 0.0D, 0.0D);
}

@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}

public static final MapCodec<WoodenFurnaceBlock> CODEC = WoodenFurnaceBlock.createCodec(WoodenFurnaceBlock::new);
@Override
protected MapCodec<WoodenFurnaceBlock> getCodec() {
Expand Down
Loading

0 comments on commit 511799e

Please sign in to comment.