diff --git a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java index a81c857..e3a48a0 100644 --- a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java +++ b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java @@ -7,6 +7,7 @@ import com.acethewildfire.acesbs.entity.client.CombustibleLemonRenderer; import com.acethewildfire.acesbs.entity.client.FrenModel; import com.acethewildfire.acesbs.entity.client.FrenRenderer; import com.acethewildfire.acesbs.screen.ModScreenHandlers; +import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreen; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreen; import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreen; import com.acethewildfire.acesbs.util.ModModelPredicates; @@ -39,5 +40,6 @@ public class AcesBSClient implements ClientModInitializer { HandledScreens.register(ModScreenHandlers.ENTROPIC_STABILIZER_SCREEN_HANDLER, EntropicStabilizerScreen::new); HandledScreens.register(ModScreenHandlers.ENTROPIC_EVISCERATOR_SCREEN_HANDLER, EntropicEvisceratorScreen::new); + HandledScreens.register(ModScreenHandlers.ENTROPIC_ENTANGLER_SCREEN_HANDLER, EntropicEntanglerScreen::new); } } diff --git a/src/main/java/com/acethewildfire/acesbs/block/ModBlocks.java b/src/main/java/com/acethewildfire/acesbs/block/ModBlocks.java index a8ffece..bd2c11c 100644 --- a/src/main/java/com/acethewildfire/acesbs/block/ModBlocks.java +++ b/src/main/java/com/acethewildfire/acesbs/block/ModBlocks.java @@ -90,7 +90,7 @@ public class ModBlocks { .requiresTool() )); public static final Block ENTROPIC_ENTANGLER = registerBlock("entropic_entangler", - new Block( + new EntropicEntangler( AbstractBlock.Settings.create() .mapColor(MapColor.LIGHT_GRAY) .strength(2.0F, 3.0F) diff --git a/src/main/java/com/acethewildfire/acesbs/block/custom/EntropicEntangler.java b/src/main/java/com/acethewildfire/acesbs/block/custom/EntropicEntangler.java new file mode 100644 index 0000000..cc0ea69 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/block/custom/EntropicEntangler.java @@ -0,0 +1,95 @@ +package com.acethewildfire.acesbs.block.custom; + +import com.acethewildfire.acesbs.block.entity.ModBlockEntities; +import com.acethewildfire.acesbs.block.entity.custom.EntropicEntanglerEntity; +import com.mojang.serialization.MapCodec; +import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityTicker; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.state.property.Properties; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemActionResult; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public class EntropicEntangler extends BlockWithEntity implements BlockEntityProvider { + public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + public static final MapCodec CODEC = EntropicEntangler.createCodec(EntropicEntangler::new); + + public EntropicEntangler(Settings settings) { + super(settings); + setDefaultState(getStateManager().getDefaultState().with(FACING, Direction.NORTH)); + } + + @Override + protected MapCodec getCodec() { + return CODEC; + } + + @Override + public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new EntropicEntanglerEntity(pos, state); + } + + @Override + protected BlockRenderType getRenderType(BlockState state) { + return BlockRenderType.MODEL; + } + + @Override + protected 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 EntropicEntanglerEntity) { + ItemScatterer.spawn(world, pos, ((EntropicEntanglerEntity) blockEntity)); + world.updateComparators(pos, this); + } + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = ((EntropicEntanglerEntity) world.getBlockEntity(pos)); + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + return ItemActionResult.SUCCESS; + + } + + @Nullable + @Override + public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { + if(world.isClient()) { + return null; + } + + return validateTicker(type, ModBlockEntities.E_ENTANGLER_BE, + (world1, pos, state1, blockEntity) -> blockEntity.tick(world1, pos, state1)); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(FACING); + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return getDefaultState().with(FACING, ctx.getHorizontalPlayerFacing().getOpposite()); + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/block/entity/EntanglerInventory.java b/src/main/java/com/acethewildfire/acesbs/block/entity/EntanglerInventory.java new file mode 100644 index 0000000..6238634 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/block/entity/EntanglerInventory.java @@ -0,0 +1,230 @@ +package com.acethewildfire.acesbs.block.entity; + +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.registry.RegistryWrapper; +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. + * + *

Reading and writing to tags

+ * Use {@link Inventories#writeNbt(NbtCompound, DefaultedList, RegistryWrapper.WrapperLookup)} and + * {@link Inventories#readNbt(NbtCompound, DefaultedList, RegistryWrapper.WrapperLookup)} + * on {@linkplain #getItems() the item list}. + * + * License: CC0 + * @author Juuz + */ +@FunctionalInterface +public interface EntanglerInventory extends SidedInventory { + int[] INPUT_SLOTS = new int[]{0, 1}; + int[] OUTPUT_SLOTS = new int[]{2}; + int[] NO_SLOTS = new int[]{}; + + /** + * Gets the item list of this inventory. + * Must return the same instance every time it's called. + * + * @return the item list + */ + DefaultedList getItems(); + + /** + * Creates an inventory from the item list. + * + * @param items the item list + * @return a new inventory + */ + static EntanglerInventory of(DefaultedList items) { + return () -> items; + } + + /** + * Creates a new inventory with the size. + * + * @param size the inventory size + * @return a new inventory + */ + static EntanglerInventory ofSize(int size) { + return of(DefaultedList.ofSize(size, ItemStack.EMPTY)); + } + + // SidedInventory + + /** + * Gets the available slots to automation on the side. + * + *

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; +// } + + if (side == Direction.DOWN) { + return OUTPUT_SLOTS; // hopper under pulls result + } + + // Allow input only from horizontal sides + if (side.getAxis().isHorizontal()) { + return INPUT_SLOTS; + } + + return NO_SLOTS; // top does nothing + } + + /** + * Returns true if the stack can be inserted in the slot at the side. + * + *

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) { + if (slot == 2) return false; // never insert into output + + // Only allow from horizontal sides + return side != null && side.getAxis().isHorizontal(); + } + + /** + * Returns true if the stack can be extracted from the slot at the side. + * + *

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 side == Direction.DOWN && slot == 2; + } + + // Inventory + + /** + * Returns the inventory size. + * + *

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. + * + *

(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. + * + *

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. + * + *

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()); + } + } + + /** + * 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/block/entity/ModBlockEntities.java b/src/main/java/com/acethewildfire/acesbs/block/entity/ModBlockEntities.java index b4269f7..7150089 100644 --- a/src/main/java/com/acethewildfire/acesbs/block/entity/ModBlockEntities.java +++ b/src/main/java/com/acethewildfire/acesbs/block/entity/ModBlockEntities.java @@ -2,6 +2,7 @@ package com.acethewildfire.acesbs.block.entity; import com.acethewildfire.acesbs.AcesBS; import com.acethewildfire.acesbs.block.ModBlocks; +import com.acethewildfire.acesbs.block.entity.custom.EntropicEntanglerEntity; import com.acethewildfire.acesbs.block.entity.custom.EntropicEvisceratorEntity; import com.acethewildfire.acesbs.block.entity.custom.EntropicStabilizerEntity; import net.minecraft.block.entity.BlockEntityType; @@ -17,6 +18,9 @@ public class ModBlockEntities { public static final BlockEntityType E_EVISCERATOR_BE = Registry.register(Registries.BLOCK_ENTITY_TYPE, Identifier.of(AcesBS.MOD_ID, "e_eviscerator_be"), BlockEntityType.Builder.create(EntropicEvisceratorEntity::new, ModBlocks.ENTROPIC_EVISCERATOR).build(null)); + public static final BlockEntityType E_ENTANGLER_BE = + Registry.register(Registries.BLOCK_ENTITY_TYPE, Identifier.of(AcesBS.MOD_ID, "e_entangler_be"), + BlockEntityType.Builder.create(EntropicEntanglerEntity::new, ModBlocks.ENTROPIC_ENTANGLER).build(null)); public static void registerBlockEntities() { AcesBS.LOGGER.info("Registering Block Entities for " + AcesBS.MOD_ID); diff --git a/src/main/java/com/acethewildfire/acesbs/block/entity/custom/EntropicEntanglerEntity.java b/src/main/java/com/acethewildfire/acesbs/block/entity/custom/EntropicEntanglerEntity.java new file mode 100644 index 0000000..3a859b7 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/block/entity/custom/EntropicEntanglerEntity.java @@ -0,0 +1,262 @@ +package com.acethewildfire.acesbs.block.entity.custom; + +import com.acethewildfire.acesbs.block.custom.EntropicEntangler; +import com.acethewildfire.acesbs.block.entity.EntanglerInventory; +import com.acethewildfire.acesbs.block.entity.ImplementedInventory; +import com.acethewildfire.acesbs.block.entity.ModBlockEntities; +import com.acethewildfire.acesbs.item.ModItems; +import com.acethewildfire.acesbs.recipe.EntropicEntanglerRecipe; +import com.acethewildfire.acesbs.recipe.EntropicEntanglerRecipeInput; +import com.acethewildfire.acesbs.recipe.ModRecipies; +import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreenHandler; +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventories; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.listener.ClientPlayPacketListener; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.recipe.RecipeEntry; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.screen.PropertyDelegate; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class EntropicEntanglerEntity extends BlockEntity implements EntanglerInventory, ExtendedScreenHandlerFactory { + private final DefaultedList inventory = DefaultedList.ofSize(3, ItemStack.EMPTY); + private Direction facing; + + private static final int INPUT_SLOT = 0; + private static final int INPUT2_SLOT = 1; + private static final int OUTPUT_SLOT = 2; + +// private static final int FUEL_PROGRESS = 0; +// private static final int FUEL_MAX_PROGRESS = 1; + private static final int ENTANGLE_PROGRESS = 2; + private static final int ENTANGLE_MAX_PROGRESS = 3; + +// private int fuel_progress = -1; +// private int fuel_max_progress = 400; + private int entangle_progress = 0; + private int entangle_max_progress = 200; + + protected final PropertyDelegate propertyDelegate; + + public EntropicEntanglerEntity(BlockPos pos, BlockState state) { + super(ModBlockEntities.E_ENTANGLER_BE, pos, state); + this.facing = state.get(EntropicEntangler.FACING); + this.propertyDelegate = new PropertyDelegate() { + @Override + public int get(int index) { + return switch (index) { +// case 0 -> EntropicEntanglerEntity.this.fuel_progress; +// case 1 -> EntropicEntanglerEntity.this.fuel_max_progress; + case 2 -> EntropicEntanglerEntity.this.entangle_progress; + case 3 -> EntropicEntanglerEntity.this.entangle_max_progress; + default -> 0; + }; + } + + @Override + public void set(int index, int value) { + switch (index) { +// case 0 -> EntropicEntanglerEntity.this.fuel_progress = value; +// case 1 -> EntropicEntanglerEntity.this.fuel_max_progress = value; + case 2 -> EntropicEntanglerEntity.this.entangle_progress = value; + case 3 -> EntropicEntanglerEntity.this.entangle_max_progress = value; + } + } + + @Override + public int size() { + return 4; + } + }; + } + + public Direction getFacing() { + return facing; + } + + public void setFacing(Direction newFacing) { + this.facing = newFacing; + // sync to blockstate for rendering + if (world != null && !world.isClient) { + world.setBlockState(pos, getCachedState().with(EntropicEntangler.FACING, newFacing), 3); + markDirty(); + } + } + + @Override + protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(nbt, registryLookup); + Inventories.writeNbt(nbt, inventory, registryLookup); + nbt.putInt("Facing", facing.getId()); +// nbt.putInt("entangler.fuel_progress", fuel_progress); +// nbt.putInt("entangler.fuel_max_progress", fuel_max_progress); + nbt.putInt("entangler.entangle_progress", entangle_progress); + nbt.putInt("entangler.entangle_max_progress", entangle_max_progress); + } + + @Override + protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + Inventories.readNbt(nbt, inventory, registryLookup); + this.facing = Direction.byId(nbt.getInt("Facing")); +// this.fuel_progress = nbt.getInt("entangler.fuel_progress"); +// this.fuel_max_progress = nbt.getInt("entangler.fuel_max_progress"); + this.entangle_progress = nbt.getInt("entangler.entangle_progress"); + this.entangle_max_progress = nbt.getInt("entangler.entangle_max_progress"); + super.readNbt(nbt, registryLookup); + } + + @Override + public DefaultedList getItems() { + return inventory; + } + + @Override + public BlockPos getScreenOpeningData(ServerPlayerEntity serverPlayerEntity) { + return this.pos; + } + + @Override + public Text getDisplayName() { + return Text.translatable("block.acesbs.entropic_entangler"); + } + + @Override + public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { + return new EntropicEntanglerScreenHandler(syncId, playerInventory, this, propertyDelegate); + } + + public float getCookProgress() { + int i = this.propertyDelegate.get(ENTANGLE_PROGRESS); + int j = this.propertyDelegate.get(ENTANGLE_MAX_PROGRESS); + return j != 0 && i != 0 ? MathHelper.clamp((float)i / (float)j, 0.0F, 1.0F) : 0.0F; + } + +// public float getFuelProgress() { +// int i = this.propertyDelegate.get(FUEL_MAX_PROGRESS); +// if (i == 0) { +// i = 200; +// } +// +// return MathHelper.clamp((float)this.propertyDelegate.get(FUEL_PROGRESS) / (float) i, 0.0F, 1.0F); +// } + +// public boolean canInsertIntoSlot(int index) { +// return index != 1; +// } + + public void tick(World world, BlockPos pos, BlockState state) { + if(hasRecipe()) { + increaseCraftingProgress(); + markDirty(world, pos, state); + + if(hasCraftingFinished()) { + craftItem(); + resetProgress(); + } + } else { + resetProgress(); + } + } + +// private boolean hasFuel() { +// return this.getStack(INPUT2_SLOT).isOf(ModItems.STABLE_ENTROPY); +// } + +// private boolean hasUnfinishedFuel() { +// return this.fuel_progress > -1 && !hasFuelFinished(); +// } + + private void resetProgress() { + this.entangle_progress = 0; + this.entangle_max_progress = 200; + } + +// private void resetFuelProgress() { +// this.fuel_progress = 0; +// this.fuel_max_progress = 400; +// } + + private void craftItem() { + Optional> recipe = getCurrentRecipe(); + ItemStack output = recipe.get().value().output(); + + this.removeStack(INPUT_SLOT, 1); + this.removeStack(INPUT2_SLOT, 1); + this.setStack(OUTPUT_SLOT, new ItemStack(output.getItem(), + this.getStack(OUTPUT_SLOT).getCount() + output.getCount())); + } + + private void consumeFuel() { + this.setStack(INPUT2_SLOT, new ItemStack(this.getStack(INPUT2_SLOT).getItem(), + this.getStack(INPUT2_SLOT).getCount() - 1)); + } + + private boolean hasCraftingFinished() { + return this.entangle_progress >= this.entangle_max_progress; + } + +// private boolean hasFuelFinished() { +// return this.fuel_progress >= this.fuel_max_progress; +// } + + private void increaseCraftingProgress() { + this.entangle_progress++; +// this.fuel_progress++; + } + + private boolean hasRecipe() { + Optional> recipe = getCurrentRecipe(); + + if (recipe.isEmpty()){ return false; } + + ItemStack output = recipe.get().value().output(); + + return canInsertAmountIntoOutputSlot(output.getCount()) && canInsertItemIntoOutputSlot(output); + } + + private Optional> getCurrentRecipe() { + return this.getWorld().getRecipeManager() + .getFirstMatch(ModRecipies.ENTROPIC_ENTANGLER_TYPE, new EntropicEntanglerRecipeInput(inventory.get(INPUT_SLOT), inventory.get(INPUT2_SLOT)), this.getWorld()); + } + + private boolean canInsertItemIntoOutputSlot(ItemStack output) { + return this.getStack(OUTPUT_SLOT).isEmpty() || this.getStack(OUTPUT_SLOT).getItem() == output.getItem(); + } + + private boolean canInsertAmountIntoOutputSlot(int count) { + int maxCount = this.getStack(OUTPUT_SLOT).isEmpty() ? 64 : this.getStack(OUTPUT_SLOT).getMaxCount(); + int currentCount = this.getStack(OUTPUT_SLOT).getCount(); + + return maxCount >= currentCount + count; + } + + @Nullable + @Override + public Packet toUpdatePacket() { + return BlockEntityUpdateS2CPacket.create(this); + } + + @Override + public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { + return createNbt(registryLookup); + } + + +} diff --git a/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipe.java b/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipe.java new file mode 100644 index 0000000..f386ba8 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipe.java @@ -0,0 +1,93 @@ +package com.acethewildfire.acesbs.recipe; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.item.ItemStack; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.RecipeType; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.world.World; + +public record EntropicEntanglerRecipe(Ingredient inputItem, Ingredient inputItem2, ItemStack output) implements Recipe { + + @Override + public DefaultedList getIngredients() { + DefaultedList list = DefaultedList.of(); + list.add(this.inputItem); + list.add(this.inputItem2); + return list; + } + + // Read JSON Files + // Turns into new EntropicEvisceratorRecipe + + @Override + public boolean matches(EntropicEntanglerRecipeInput input, World world) { + if(world.isClient()) { + return false; + } + + ItemStack slot0 = input.getStackInSlot(0); + ItemStack slot1 = input.getStackInSlot(1); + + // Allow either order (A+B or B+A) + return (inputItem.test(slot0) && inputItem2.test(slot1)) || + (inputItem.test(slot1) && inputItem2.test(slot0)); + } + + @Override + public ItemStack craft(EntropicEntanglerRecipeInput input, RegistryWrapper.WrapperLookup lookup) { + return output.copy(); + } + + @Override + public boolean fits(int width, int height) { + return true; + } + + @Override + public ItemStack getResult(RegistryWrapper.WrapperLookup registriesLookup) { + return output; + } + + @Override + public RecipeSerializer getSerializer() { + return ModRecipies.ENTROPIC_ENTANGLER_SERIALIZER; + } + + @Override + public RecipeType getType() { + return ModRecipies.ENTROPIC_ENTANGLER_TYPE; + } + + public static class Serializer implements RecipeSerializer { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group( + Ingredient.DISALLOW_EMPTY_CODEC.fieldOf("ingredient").forGetter(EntropicEntanglerRecipe::inputItem), + Ingredient.DISALLOW_EMPTY_CODEC.fieldOf("ingredient2").forGetter(EntropicEntanglerRecipe::inputItem2), + ItemStack.CODEC.fieldOf("result").forGetter(EntropicEntanglerRecipe::output) + ).apply(inst, EntropicEntanglerRecipe::new)); + + public static final PacketCodec STREAM_CODEC = + PacketCodec.tuple( + Ingredient.PACKET_CODEC, EntropicEntanglerRecipe::inputItem, + Ingredient.PACKET_CODEC, EntropicEntanglerRecipe::inputItem2, + ItemStack.PACKET_CODEC, EntropicEntanglerRecipe::output, + EntropicEntanglerRecipe::new); + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + public PacketCodec packetCodec() { + return STREAM_CODEC; + } + + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipeInput.java b/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipeInput.java new file mode 100644 index 0000000..394ea37 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/recipe/EntropicEntanglerRecipeInput.java @@ -0,0 +1,21 @@ +package com.acethewildfire.acesbs.recipe; + +import com.acethewildfire.acesbs.block.entity.custom.EntropicEntanglerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.input.RecipeInput; + +public record EntropicEntanglerRecipeInput(ItemStack input, ItemStack input2) implements RecipeInput { + @Override + public ItemStack getStackInSlot(int slot) { + return switch (slot) { + case 0 -> input; + case 1 -> input2; + default -> input; + }; + } + + @Override + public int getSize() { + return 2; + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/recipe/ModRecipies.java b/src/main/java/com/acethewildfire/acesbs/recipe/ModRecipies.java index 203f277..393bc0f 100644 --- a/src/main/java/com/acethewildfire/acesbs/recipe/ModRecipies.java +++ b/src/main/java/com/acethewildfire/acesbs/recipe/ModRecipies.java @@ -34,6 +34,19 @@ public class ModRecipies { } }); + public static final RecipeSerializer ENTROPIC_ENTANGLER_SERIALIZER = + Registry.register(Registries.RECIPE_SERIALIZER, Identifier.of(AcesBS.MOD_ID, "entropic_entangler"), + new EntropicEntanglerRecipe.Serializer()); + + public static final RecipeType ENTROPIC_ENTANGLER_TYPE = + Registry.register(Registries.RECIPE_TYPE, Identifier.of(AcesBS.MOD_ID, "entropic_entangler"), + new RecipeType() { + @Override + public String toString() { + return "entropic_entangler"; + } + }); + public static void registerRecipes() { AcesBS.LOGGER.info("Registering Custom Recipes for " + AcesBS.MOD_ID); } diff --git a/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java b/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java index 29c0af3..c1412a4 100644 --- a/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java +++ b/src/main/java/com/acethewildfire/acesbs/screen/ModScreenHandlers.java @@ -1,6 +1,7 @@ package com.acethewildfire.acesbs.screen; import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.screen.custom.EntropicEntanglerScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicEvisceratorScreenHandler; import com.acethewildfire.acesbs.screen.custom.EntropicStabilizerScreenHandler; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; @@ -19,6 +20,11 @@ public class ModScreenHandlers { public static final ScreenHandlerType ENTROPIC_EVISCERATOR_SCREEN_HANDLER = Registry.register(Registries.SCREEN_HANDLER, Identifier.of(AcesBS.MOD_ID, "entropic_eviscerator_screen_handler"), new ExtendedScreenHandlerType<>(EntropicEvisceratorScreenHandler::new, BlockPos.PACKET_CODEC)); + + public static final ScreenHandlerType ENTROPIC_ENTANGLER_SCREEN_HANDLER = + Registry.register(Registries.SCREEN_HANDLER, Identifier.of(AcesBS.MOD_ID, "entropic_entangler_screen_handler"), + new ExtendedScreenHandlerType<>(EntropicEntanglerScreenHandler::new, BlockPos.PACKET_CODEC)); + public static void registerScreenHandlers() { AcesBS.LOGGER.info("Registering Screen Handlers for " + AcesBS.MOD_ID); diff --git a/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreen.java b/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreen.java new file mode 100644 index 0000000..a705c78 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreen.java @@ -0,0 +1,63 @@ +package com.acethewildfire.acesbs.screen.custom; + +import com.acethewildfire.acesbs.AcesBS; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class EntropicEntanglerScreen extends HandledScreen { + + public static final Identifier GUI_TEXTURE = + Identifier.of(AcesBS.MOD_ID, "textures/gui/entropic_entangler/entropic_entangler_gui.png"); + public static final Identifier ENTANGLE_LEFT_TEXTURE = + Identifier.of(AcesBS.MOD_ID, "textures/gui/entangle_left_progress.png"); + public static final Identifier ENTANGLE_RIGHT_TEXTURE = + Identifier.of(AcesBS.MOD_ID, "textures/gui/entangle_right_progress.png"); + + public EntropicEntanglerScreen(EntropicEntanglerScreenHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + } + + @Override + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + RenderSystem.setShader(GameRenderer::getPositionTexProgram); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + RenderSystem.setShaderTexture(0, GUI_TEXTURE); + + int x = (width - backgroundWidth) / 2; + int y = (height - backgroundHeight) / 2; + + context.drawTexture(GUI_TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight); + +// renderProgressArrow(context, x, y); + renderEntangleProgress(context, x, y); + } + +// private void renderProgressArrow(DrawContext context, int x, int y) { +// +// if(handler.isCrafting()) { +// context.drawTexture(ARROW_TEXTURE, x + 79, y + 35, 0, 0, +// handler.getScaledArrowProgress(), 16, 24, 16); +// } +// } + + private void renderEntangleProgress(DrawContext context, int x, int y) { + if(handler.isCrafting()) { + context.drawTexture(ENTANGLE_LEFT_TEXTURE, x + 52, y + 25, 0, 0, + handler.getScaledEntangleProgress(), 9, 37, 9); + context.drawTexture(ENTANGLE_RIGHT_TEXTURE, x + 89 + (37 - handler.getScaledEntangleProgress()), y + 52, (37 - handler.getScaledEntangleProgress()), 0, + handler.getScaledEntangleProgress(), 9, 37, 9); + } + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + drawMouseoverTooltip(context, mouseX, mouseY); + } + +} diff --git a/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreenHandler.java b/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreenHandler.java new file mode 100644 index 0000000..dd5eab0 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/screen/custom/EntropicEntanglerScreenHandler.java @@ -0,0 +1,123 @@ +package com.acethewildfire.acesbs.screen.custom; + +import com.acethewildfire.acesbs.block.entity.custom.EntropicEntanglerEntity; +import com.acethewildfire.acesbs.block.entity.custom.EntropicStabilizerEntity; +import com.acethewildfire.acesbs.item.ModItems; +import com.acethewildfire.acesbs.recipe.EntropicEntanglerRecipeInput; +import com.acethewildfire.acesbs.recipe.ModRecipies; +import com.acethewildfire.acesbs.screen.ModScreenHandlers; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.ArrayPropertyDelegate; +import net.minecraft.screen.PropertyDelegate; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.math.BlockPos; + +public class EntropicEntanglerScreenHandler extends ScreenHandler { + private final Inventory inventory; + private final PropertyDelegate propertyDelegate; + public final EntropicEntanglerEntity blockEntity; + + public EntropicEntanglerScreenHandler(int syncId, PlayerInventory playerInventory, BlockPos pos) { + this(syncId, playerInventory, playerInventory.player.getWorld().getBlockEntity(pos), new ArrayPropertyDelegate(4)); + } + + public EntropicEntanglerScreenHandler(int syncId, PlayerInventory playerInventory, BlockEntity blockEntity, PropertyDelegate arrayPropertyDelegate) { + super(ModScreenHandlers.ENTROPIC_ENTANGLER_SCREEN_HANDLER, syncId); + this.inventory = ((Inventory) blockEntity); + this.blockEntity = ((EntropicEntanglerEntity) blockEntity); + this.propertyDelegate = arrayPropertyDelegate; + + this.addSlot(new Slot(inventory, 0, 44, 35)); //Item L + this.addSlot(new Slot(inventory, 1, 116, 35)); //Item R + this.addSlot(new Slot(inventory, 2, 80, 35)); // Output + + addPlayerInventory(playerInventory); + addPlayerHotbar(playerInventory); + + addProperties(arrayPropertyDelegate); + } + + public boolean isCrafting() { + return propertyDelegate.get(2) > 0; + } + + public boolean isCooking() { + return propertyDelegate.get(0) > 0; + } + +// public int getScaledArrowProgress() { +// int progress = this.propertyDelegate.get(2); +// int maxProgress = this.propertyDelegate.get(3); // Max Progress +// int arrowPixelSize = 24; // This is the width in pixels of your arrow +// +// return maxProgress != 0 && progress != 0 ? progress * arrowPixelSize / maxProgress : 0; +// } + + public int getScaledEntangleProgress() { + int progress = this.propertyDelegate.get(2); + int maxProgress = this.propertyDelegate.get(3); // Max Progress + int entanglePixelSize = 37; // This is the width in pixels of your bar + + return maxProgress != 0 && progress != 0 ? progress * entanglePixelSize / maxProgress : 0; + } + + @Override + public ItemStack quickMove(PlayerEntity player, int invSlot) { + ItemStack newStack = ItemStack.EMPTY; + Slot slot = this.slots.get(invSlot); + if (slot != null && slot.hasStack()) { + // Has something to move + ItemStack originalStack = slot.getStack(); + newStack = originalStack.copy(); + if (invSlot < this.inventory.size()) { + // machine -> player + if (!this.insertItem(originalStack, this.inventory.size(), this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!this.insertItem(originalStack, 0, 2, false)) { + // player -> machine + return ItemStack.EMPTY; + } + + if (originalStack.isEmpty()) { + slot.setStack(ItemStack.EMPTY); + } else { + slot.markDirty(); + } + } + return newStack; + } + +// protected boolean isEntangleable(ItemStack itemStack) { +// return itemStack.isOf(ModItems.RAW_ENTROPY); +// } + +// protected boolean isFuel(ItemStack itemStack) { +// return itemStack.isOf(ModItems.STABLE_ENTROPY); +// } + + @Override + public boolean canUse(PlayerEntity player) { + return this.inventory.canPlayerUse(player); + } + + private void addPlayerInventory(PlayerInventory playerInventory) { + for (int i = 0; i < 3; ++i) { + for (int l = 0; l < 9; ++l) { + this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, 84 + i * 18)); + } + } + } + + private void addPlayerHotbar(PlayerInventory playerInventory) { + for (int i = 0; i < 9; ++i) { + this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142)); + } + } +} diff --git a/src/main/resources/assets/acesbs/blockstates/entropic_entangler.json b/src/main/resources/assets/acesbs/blockstates/entropic_entangler.json index aeb6cca..f285a96 100644 --- a/src/main/resources/assets/acesbs/blockstates/entropic_entangler.json +++ b/src/main/resources/assets/acesbs/blockstates/entropic_entangler.json @@ -1,7 +1,8 @@ { "variants": { - "": { - "model": "acesbs:block/entropic_entangler" - } + "facing=north": { "model": "acesbs:block/entropic_entangler" }, + "facing=south": { "model": "acesbs:block/entropic_entangler", "y": 180 }, + "facing=west": { "model": "acesbs:block/entropic_entangler", "y": 270 }, + "facing=east": { "model": "acesbs:block/entropic_entangler", "y": 90 } } } \ No newline at end of file diff --git a/src/main/resources/assets/acesbs/textures/gui/entangle_left_progress.png b/src/main/resources/assets/acesbs/textures/gui/entangle_left_progress.png new file mode 100644 index 0000000..817bbc1 Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/gui/entangle_left_progress.png differ diff --git a/src/main/resources/assets/acesbs/textures/gui/entangle_right_progress.png b/src/main/resources/assets/acesbs/textures/gui/entangle_right_progress.png new file mode 100644 index 0000000..833152e Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/gui/entangle_right_progress.png differ diff --git a/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui.png b/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui.png new file mode 100644 index 0000000..a2789c3 Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui.png differ diff --git a/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui_rei.png b/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui_rei.png new file mode 100644 index 0000000..cc2397d Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/gui/entropic_entangler/entropic_entangler_gui_rei.png differ diff --git a/src/main/resources/data/acesbs/recipe/prismasteel_ingot_from_entropic_entangler.json b/src/main/resources/data/acesbs/recipe/prismasteel_ingot_from_entropic_entangler.json new file mode 100644 index 0000000..b764f79 --- /dev/null +++ b/src/main/resources/data/acesbs/recipe/prismasteel_ingot_from_entropic_entangler.json @@ -0,0 +1,13 @@ +{ + "type": "acesbs:entropic_entangler", + "ingredient": { + "item": "minecraft:iron_ingot" + }, + "ingredient2": { + "item": "acesbs:stable_entropy" + }, + "result": { + "count": 1, + "id": "acesbs:prisma_steel" + } +} \ No newline at end of file