From 6ed03e1fcddeae0829a977ae75e440cc0d44d9b2 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 27 Mar 2019 20:38:39 +0000 Subject: [PATCH] Convert turtle refuelling into an event This should allow us (or other mods) to register custom refuel handlers should they so wish. --- .../api/turtle/event/TurtleRefuelEvent.java | 90 +++++++++++++++++++ .../shared/turtle/FurnaceRefuelHandler.java | 61 +++++++++++++ .../turtle/core/TurtleRefuelCommand.java | 82 +++-------------- 3 files changed, 164 insertions(+), 69 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java create mode 100644 src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java new file mode 100644 index 000000000..bc4084c56 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -0,0 +1,90 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.api.turtle.event; + +import dan200.computercraft.api.turtle.ITurtleAccess; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Objects; + +/** + * Fired when a turtle attempts to refuel from an item. + * + * One may use {@link #setCanceled(boolean, String)} to prevent refueling from this specific item. Additionally, you + * may use {@link #setHandler(Handler)} to register a custom fuel provider. + */ +public class TurtleRefuelEvent extends TurtleActionEvent +{ + private final ItemStack stack; + private Handler handler; + + public TurtleRefuelEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack ) + { + super( turtle, TurtleAction.REFUEL ); + + Objects.requireNonNull( turtle, "turtle cannot be null" ); + this.stack = stack; + } + + /** + * Get the stack we are attempting to refuel from. + * + * Do not modify the returned stack - all modifications should be done within the {@link Handler}. + * + * @return The stack to refuel from. + */ + public ItemStack getStack() + { + return stack; + } + + /** + * Get the refuel handler for this stack. + * + * @return The refuel handler, or {@code null} if none has currently been set. + * @see #setHandler(Handler) + */ + @Nullable + public Handler getHandler() + { + return handler; + } + + /** + * Set the refuel handler for this stack. + * + * You should call this if you can actually refuel from this item, and ideally only if there are no existing + * handlers. + * + * @param handler The new refuel handler. + * @see #getHandler() + */ + public void setHandler( @Nullable Handler handler ) + { + this.handler = handler; + } + + /** + * Handles refuelling a turtle from a specific item. + */ + public interface Handler + { + /** + * Refuel a turtle using an item. + * + * @param turtle The turtle to refuel. + * @param stack The stack to refuel with. + * @param slot The slot the stack resides within. This may be used to modify the inventory afterwards. + * @param limit The maximum number of refuel operations to perform. This will often correspond to the number of + * items to consume. + * @return The amount of fuel gained. + */ + int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, int slot, int limit ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java new file mode 100644 index 000000000..5998bdad2 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -0,0 +1,61 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.turtle; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; +import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.shared.util.WorldUtil; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import javax.annotation.Nonnull; + +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) +public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler +{ + private static final FurnaceRefuelHandler INSTANCE = new FurnaceRefuelHandler(); + + private FurnaceRefuelHandler() + { + } + + @Override + public int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack currentStack, int slot, int limit ) + { + ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false ); + int fuelToGive = getFuelPerItem( stack ) * stack.getCount(); + + // Store the replacement item in the inventory + ItemStack replacementStack = stack.getItem().getContainerItem( stack ); + if( !replacementStack.isEmpty() ) + { + ItemStack remainder = InventoryUtil.storeItems( replacementStack, turtle.getItemHandler(), turtle.getSelectedSlot() ); + if( !remainder.isEmpty() ) + { + WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() ); + } + } + + return fuelToGive; + } + + + private static int getFuelPerItem( @Nonnull ItemStack stack ) + { + return (TileEntityFurnace.getItemBurnTime( stack ) * 5) / 100; + } + + @SubscribeEvent + public static void onTurtleRefuel( TurtleRefuelEvent event ) + { + if( event.getHandler() == null && getFuelPerItem( event.getStack() ) > 0 ) event.setHandler( INSTANCE ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index a0be95b1d..8e4ebce11 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -10,92 +10,36 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntityFurnace; import net.minecraftforge.common.MinecraftForge; import javax.annotation.Nonnull; public class TurtleRefuelCommand implements ITurtleCommand { - private final int m_limit; + private final int limit; public TurtleRefuelCommand( int limit ) { - m_limit = limit; + this.limit = limit; } @Nonnull @Override public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { - if( m_limit == 0 ) + int slot = turtle.getSelectedSlot(); + ItemStack stack = turtle.getInventory().getStackInSlot( slot ); + if( stack.isEmpty() ) return TurtleCommandResult.failure( "No items to combust" ); + + TurtleRefuelEvent event = new TurtleRefuelEvent( turtle, stack ); + if( MinecraftForge.EVENT_BUS.post( event ) ) return TurtleCommandResult.failure( event.getFailureMessage() ); + if( event.getHandler() == null ) return TurtleCommandResult.failure( "Items not combustible" ); + + if( limit != 0 ) { - // If limit is zero, just check the item is combustible - ItemStack dummyStack = turtle.getInventory().getStackInSlot( turtle.getSelectedSlot() ); - if( !dummyStack.isEmpty() ) - { - return refuel( turtle, dummyStack, true ); - } - } - else - { - // Otherwise, refuel for real - // Remove items from inventory - ItemStack stack = InventoryUtil.takeItems( m_limit, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); - if( !stack.isEmpty() ) - { - TurtleCommandResult result = refuel( turtle, stack, false ); - if( !result.isSuccess() ) - { - // If the items weren't burnt, put them back - InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); - } - return result; - } - } - return TurtleCommandResult.failure( "No items to combust" ); - } - - private int getFuelPerItem( @Nonnull ItemStack stack ) - { - return (TileEntityFurnace.getItemBurnTime( stack ) * 5) / 100; - } - - private TurtleCommandResult refuel( ITurtleAccess turtle, @Nonnull ItemStack stack, boolean testOnly ) - { - // Check if item is fuel - int fuelPerItem = getFuelPerItem( stack ); - if( fuelPerItem <= 0 ) - { - return TurtleCommandResult.failure( "Items not combustible" ); - } - - TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.REFUEL ); - if( MinecraftForge.EVENT_BUS.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - - if( !testOnly ) - { - // Determine fuel to give and replacement item to leave behind - int fuelToGive = fuelPerItem * stack.getCount(); - ItemStack replacementStack = stack.getItem().getContainerItem( stack ); - - // Update fuel level - turtle.addFuel( fuelToGive ); - - // Store the replacement item in the inventory - if( !replacementStack.isEmpty() ) - { - InventoryUtil.storeItems( replacementStack, turtle.getItemHandler(), turtle.getSelectedSlot() ); - } - - // Animate + turtle.addFuel( event.getHandler().refuel( turtle, stack, slot, limit ) ); turtle.playAnimation( TurtleAnimation.Wait ); }