Merge remote-tracking branch 'SquidDev-CC-ComputerCraft/feature/turtle-event'

This commit is contained in:
SquidDev 2018-02-16 10:48:43 +00:00
commit d3ecd5214b
22 changed files with 831 additions and 15 deletions

View File

@ -7,6 +7,7 @@
package dan200.computercraft;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaAPIFactory;
@ -19,6 +20,7 @@
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.core.apis.AddressPredicate;
import dan200.computercraft.core.filesystem.ComboMount;
import dan200.computercraft.core.filesystem.FileMount;
@ -140,6 +142,7 @@ public class ComputerCraft
public static int advancedTurtleFuelLimit = 100000;
public static boolean turtlesObeyBlockProtection = true;
public static boolean turtlesCanPush = true;
public static EnumSet<TurtleAction> turtleDisabledActions = EnumSet.noneOf( TurtleAction.class );
public static final int terminalWidth_computer = 51;
public static final int terminalHeight_computer = 19;
@ -222,6 +225,7 @@ public static class Config {
public static Property advancedTurtleFuelLimit;
public static Property turtlesObeyBlockProtection;
public static Property turtlesCanPush;
public static Property turtleDisabledActions;
public static Property modem_range;
public static Property modem_highAltitudeRange;
@ -377,6 +381,9 @@ public static void loadConfig()
Config.turtlesCanPush = Config.config.get( Configuration.CATEGORY_GENERAL, "turtlesCanPush", turtlesCanPush );
Config.turtlesCanPush.setComment( "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" );
Config.turtleDisabledActions = Config.config.get( Configuration.CATEGORY_GENERAL, "turtle_disabled_actions", new String[ 0 ] );
Config.turtleDisabledActions.setComment( "A list of turtle actions which are disabled." );
Config.maxNotesPerTick = Config.config.get( Configuration.CATEGORY_GENERAL, "maxNotesPerTick", maxNotesPerTick );
Config.maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" );
@ -417,6 +424,20 @@ public static void syncConfig() {
turtlesObeyBlockProtection = Config.turtlesObeyBlockProtection.getBoolean();
turtlesCanPush = Config.turtlesCanPush.getBoolean();
turtleDisabledActions.clear();
Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE );
for( String value : Config.turtleDisabledActions.getStringList() )
{
try
{
turtleDisabledActions.add( TurtleAction.valueOf( converter.convert( value ) ) );
}
catch( IllegalArgumentException e )
{
ComputerCraft.log.error( "Unknown turtle action " + value );
}
}
maxNotesPerTick = Math.max(1, Config.maxNotesPerTick.getInt());
Config.config.save();

View File

@ -8,11 +8,15 @@
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.event.TurtleAttackEvent;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.tuple.Pair;
@ -100,6 +104,9 @@ public interface ITurtleUpgrade
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
* by the turtle, and the tool is required to do some work.
*
* Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig}for digging,
* {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking.
*
* @param turtle Access to the turtle that the tool resides on.
* @param side Which side of the turtle (left or right) the tool resides on.
* @param verb Which action (dig or attack) the turtle is being called on to perform.

View File

@ -0,0 +1,84 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.turtle.event;
/**
* A basic action that a turtle may perform, as accessed by the {@code turtle} API.
*
* @see TurtleActionEvent
*/
public enum TurtleAction
{
/**
* A turtle moves to a new position.
*
* @see TurtleBlockEvent.Move
*/
MOVE,
/**
* A turtle turns in a specific direction.
*/
TURN,
/**
* A turtle attempts to dig a block.
*
* @see TurtleBlockEvent.Dig
*/
DIG,
/**
* A turtle attempts to place a block or item in the world.
*
* @see TurtleBlockEvent.Place
*/
PLACE,
/**
* A turtle attempts to attack an entity.
*
* @see TurtleActionEvent
*/
ATTACK,
/**
* Drop an item into an inventory/the world.
*
* @see TurtleInventoryEvent.Drop
*/
DROP,
/**
* Suck an item from an inventory or the world.
*
* @see TurtleInventoryEvent.Suck
*/
SUCK,
/**
* Refuel the turtle's fuel levels.
*/
REFUEL,
/**
* Equip or unequip an item.
*/
EQUIP,
/**
* Inspect a block in world
*
* @see TurtleBlockEvent.Inspect
*/
INSPECT,
/**
* Gather metdata about an item in the turtle's inventory.
*/
INSPECT_ITEM,
}

View File

@ -0,0 +1,76 @@
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* An event fired when a turtle is performing a known action.
*/
@Cancelable
public class TurtleActionEvent extends TurtleEvent
{
private final TurtleAction action;
private String failureMessage;
public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action )
{
super( turtle );
Preconditions.checkNotNull( action, "action cannot be null" );
this.action = action;
}
public TurtleAction getAction()
{
return action;
}
/**
* Sets the cancellation state of this action.
*
* If {@code cancel} is {@code true}, this action will not be carried out.
*
* @param cancel The new canceled value.
* @see TurtleCommandResult#failure()
* @deprecated Use {@link #setCanceled(boolean, String)} instead.
*/
@Override
@Deprecated
public void setCanceled( boolean cancel )
{
setCanceled( cancel, null );
}
/**
* Set the cancellation state of this action, setting a failure message if required.
*
* If {@code cancel} is {@code true}, this action will not be carried out.
*
* @param cancel The new canceled value.
* @param failureMessage The message to return to the user explaining the failure.
* @see TurtleCommandResult#failure(String)
*/
public void setCanceled( boolean cancel, @Nullable String failureMessage )
{
super.setCanceled( cancel );
this.failureMessage = cancel ? failureMessage : null;
}
/**
* Get the message with which this will fail.
*
* @return The failure message.
* @see TurtleCommandResult#failure()
* @see #setCanceled(boolean, String)
*/
@Nullable
public String getFailureMessage()
{
return failureMessage;
}
}

View File

@ -0,0 +1,80 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import javax.annotation.Nonnull;
/**
* Fired when a turtle attempts to attack an entity.
*
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
* as the base {@code turtle.attack()} command does not fire it.
*
* Note that such commands should also fire {@link AttackEntityEvent}, so you do not need to listen to both.
*
* @see TurtleAction#ATTACK
*/
public class TurtleAttackEvent extends TurtlePlayerEvent
{
private final Entity target;
private final ITurtleUpgrade upgrade;
private final TurtleSide side;
public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
{
super( turtle, TurtleAction.ATTACK, player );
Preconditions.checkNotNull( target, "target cannot be null" );
Preconditions.checkNotNull( upgrade, "upgrade cannot be null" );
Preconditions.checkNotNull( side, "side cannot be null" );
this.target = target;
this.upgrade = upgrade;
this.side = side;
}
/**
* Get the entity being attacked by this turtle.
*
* @return The entity being attacked.
*/
@Nonnull
public Entity getTarget()
{
return target;
}
/**
* Get the upgrade responsible for attacking.
*
* @return The upgrade responsible for attacking.
*/
@Nonnull
public ITurtleUpgrade getUpgrade()
{
return upgrade;
}
/**
* Get the side the attacking upgrade is on.
*
* @return The upgrade's side.
*/
@Nonnull
public TurtleSide getSide()
{
return side;
}
}

View File

@ -0,0 +1,241 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.TurtleVerb;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import javax.annotation.Nonnull;
import java.util.Map;
/**
* A general event for when a turtle interacts with a block or region.
*
* You should generally listen to one of the sub-events instead, cancelling them where
* appropriate.
*
* Note that you are not guaranteed to receive this event, if it has been cancelled by other
* mechanisms, such as block protection systems.
*
* Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact
* with a block, simply objects within that block space.
*/
@Cancelable
public abstract class TurtleBlockEvent extends TurtlePlayerEvent
{
private final World world;
private final BlockPos pos;
protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos )
{
super( turtle, action, player );
Preconditions.checkNotNull( world, "world cannot be null" );
Preconditions.checkNotNull( pos, "pos cannot be null" );
this.world = world;
this.pos = pos;
}
/**
* Get the world the turtle is interacting in.
*
* @return The world the turtle is interacting in.
*/
public World getWorld()
{
return world;
}
/**
* Get the position the turtle is interacting with. Note that this is different
* to {@link ITurtleAccess#getPosition()}.
*
* @return The position the turtle is interacting with.
*/
public BlockPos getPos()
{
return pos;
}
/**
* Fired when a turtle attempts to dig a block.
*
* This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)},
* as the base {@code turtle.dig()} command does not fire it.
*
* Note that such commands should also fire {@link BlockEvent.BreakEvent}, so you do not need to listen to both.
*
* @see TurtleAction#DIG
*/
@Cancelable
public static class Dig extends TurtleBlockEvent
{
private final IBlockState block;
private final ITurtleUpgrade upgrade;
private final TurtleSide side;
public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side )
{
super( turtle, TurtleAction.DIG, player, world, pos );
Preconditions.checkNotNull( block, "block cannot be null" );
Preconditions.checkNotNull( upgrade, "upgrade cannot be null" );
Preconditions.checkNotNull( side, "side cannot be null" );
this.block = block;
this.upgrade = upgrade;
this.side = side;
}
/**
* Get the block which is about to be broken.
*
* @return The block which is going to be broken.
*/
@Nonnull
public IBlockState getBlock()
{
return block;
}
/**
* Get the upgrade doing the digging
*
* @return The upgrade doing the digging.
*/
@Nonnull
public ITurtleUpgrade getUpgrade()
{
return upgrade;
}
/**
* Get the side the upgrade doing the digging is on.
*
* @return The upgrade's side.
*/
@Nonnull
public TurtleSide getSide()
{
return side;
}
}
/**
* Fired when a turtle attempts to move into a block.
*
* @see TurtleAction#MOVE
*/
@Cancelable
public static class Move extends TurtleBlockEvent
{
public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos )
{
super( turtle, TurtleAction.MOVE, player, world, pos );
}
}
/**
* Fired when a turtle attempts to place a block in the world.
*
* @see TurtleAction#PLACE
*/
@Cancelable
public static class Place extends TurtleBlockEvent
{
private final ItemStack stack;
public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull ItemStack stack )
{
super( turtle, TurtleAction.PLACE, player, world, pos );
Preconditions.checkNotNull( stack, "stack cannot be null" );
this.stack = stack;
}
/**
* Get the item stack that will be placed. This should not be modified.
*
* @return The item stack to be placed.
*/
@Nonnull
public ItemStack getStack()
{
return stack;
}
}
/**
* Fired when a turtle gathers data on a block in world.
*
* You may prevent blocks being inspected, or add additional information to the result.
*
* @see TurtleAction#INSPECT
*/
@Cancelable
public static class Inspect extends TurtleBlockEvent
{
private final IBlockState state;
private final Map<String, Object> data;
public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Map<String, Object> data )
{
super( turtle, TurtleAction.INSPECT, player, world, pos );
Preconditions.checkNotNull( state, "state cannot be null" );
Preconditions.checkNotNull( data, "data cannot be null" );
this.data = data;
this.state = state;
}
/**
* Get the block state which is being inspected.
*
* @return The inspected block state.
*/
@Nonnull
public IBlockState getState()
{
return state;
}
/**
* Get the "inspection data" from this block, which will be returned to the user.
*
* @return This block's inspection data.
*/
@Nonnull
public Map<String, Object> getData()
{
return data;
}
/**
* Add new information to the inspection result. Note this will override fields with the same name.
*
* @param newData The data to add. Note all values should be convertable to Lua (see
* {@link dan200.computercraft.api.peripheral.IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}).
*/
public void addData( @Nonnull Map<String, ?> newData )
{
Preconditions.checkNotNull( newData, "newData cannot be null" );
data.putAll( newData );
}
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraftforge.fml.common.eventhandler.Event;
import javax.annotation.Nonnull;
/**
* A base class for all events concerning a turtle. This will only ever constructed and fired on the server side,
* so sever specific methods on {@link ITurtleAccess} are safe to use.
*
* You should generally not need to subscribe to this event, preferring one of the more specific classes.
*
* @see TurtleActionEvent
*/
public abstract class TurtleEvent extends Event
{
private final ITurtleAccess turtle;
protected TurtleEvent( @Nonnull ITurtleAccess turtle )
{
Preconditions.checkNotNull( turtle, "turtle cannot be null" );
this.turtle = turtle;
}
/**
* Get the turtle which is performing this action.
*
* @return The access for this turtle.
*/
@Nonnull
public ITurtleAccess getTurtle()
{
return turtle;
}
}

View File

@ -0,0 +1,84 @@
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Fired when a turtle attempts to interact with an inventory.
*/
@Cancelable
public abstract class TurtleInventoryEvent extends TurtleBlockEvent
{
private final IItemHandler handler;
protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler )
{
super( turtle, action, player, world, pos );
this.handler = handler;
}
/**
* Get the inventory being interacted with
*
* @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world.
*/
@Nullable
public IItemHandler getItemHandler()
{
return handler;
}
/**
* Fired when a turtle attempts to suck from an inventory.
*
* @see TurtleAction#SUCK
*/
@Cancelable
public static class Suck extends TurtleInventoryEvent
{
public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler )
{
super( turtle, TurtleAction.SUCK, player, world, pos, handler );
}
}
/**
* Fired when a turtle attempts to drop an item into an inventory.
*
* @see TurtleAction#DROP
*/
@Cancelable
public static class Drop extends TurtleInventoryEvent
{
private final ItemStack stack;
public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nullable IItemHandler handler, @Nonnull ItemStack stack )
{
super( turtle, TurtleAction.DROP, player, world, pos, handler );
Preconditions.checkNotNull( stack, "stack cannot be null" );
this.stack = stack;
}
/**
* The item which will be inserted into the inventory/dropped on the ground.
*
* Note that this is a copy of the original stack, and so should not be modified, as that will have no effect.
*
* @return The item stack which will be dropped.
*/
public ItemStack getStack()
{
return stack.copy();
}
}
}

View File

@ -0,0 +1,44 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
package dan200.computercraft.api.turtle.event;
import com.google.common.base.Preconditions;
import dan200.computercraft.api.turtle.ITurtleAccess;
import net.minecraftforge.common.util.FakePlayer;
import javax.annotation.Nonnull;
/**
* An action done by a turtle which is normally done by a player.
*
* {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks.
*/
public abstract class TurtlePlayerEvent extends TurtleActionEvent
{
private final FakePlayer player;
protected TurtlePlayerEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player )
{
super( turtle, action );
Preconditions.checkNotNull( player, "player cannot be null" );
this.player = player;
}
/**
* A fake player, representing this turtle.
*
* This may be used for triggering permission checks.
*
* @return A {@link FakePlayer} representing this turtle.
*/
@Nonnull
public FakePlayer getPlayer()
{
return player;
}
}

View File

@ -0,0 +1,10 @@
/*
* This file is part of the public ComputerCraft API - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2017. This API may be redistributed unmodified and in full only.
* For help using the API, and posting your mods, visit the forums at computercraft.info.
*/
@API(owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle|Event", apiVersion = "${version}")
package dan200.computercraft.api.turtle.event;
import net.minecraftforge.fml.common.API;

View File

@ -8,6 +8,7 @@
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
@ -465,6 +466,14 @@ public void onEntityLivingDrops( LivingDropsEvent event )
{
dispatchEntityDrops( event.getEntity(), event.getDrops() );
}
@SubscribeEvent
public void onTurtleAction( TurtleActionEvent event) {
if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) )
{
event.setCanceled( true, "Action has been disabled" );
}
}
}
private void dispatchEntityDrops( Entity entity, java.util.List<EntityItem> drops )

View File

@ -12,10 +12,13 @@
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.shared.turtle.core.*;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import java.util.HashMap;
@ -424,6 +427,13 @@ public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull O
table.put( "name", name );
table.put( "damage", damage );
table.put( "count", count );
TurtleActionEvent event = new TurtleActionEvent( m_turtle, TurtleAction.INSPECT_ITEM );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return new Object[] { false, event.getFailureMessage() };
}
return new Object[] { table };
}
else

View File

@ -10,12 +10,14 @@
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleInventoryEvent;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
@ -59,6 +61,16 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
EnumFacing side = direction.getOpposite();
IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side );
// Fire the event, restoring the inventory and exiting if it is cancelled.
TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
TurtleInventoryEvent.Drop event = new TurtleInventoryEvent.Drop( turtle, player, world, newPosition, inventory, stack );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
return TurtleCommandResult.failure( event.getFailureMessage() );
}
if( inventory != null )
{
// Drop the item into the inventory

View File

@ -8,11 +8,14 @@
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.api.turtle.event.TurtleAction;
import dan200.computercraft.api.turtle.event.TurtleActionEvent;
import dan200.computercraft.shared.proxy.CCTurtleProxyCommon;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
@ -63,6 +66,12 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
oldUpgradeStack = null;
}
TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.EQUIP );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return TurtleCommandResult.failure( event.getFailureMessage() );
}
// Do the swapping:
if( newUpgradeStack != null )
{

View File

@ -10,13 +10,15 @@
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import java.util.HashMap;
@ -46,14 +48,14 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
if( WorldUtil.isBlockInWorld( world, newPosition ) )
{
if( !FAIL_ON_AIR || !world.isAirBlock( newPosition ) )
IBlockState state = world.getBlockState( newPosition );
if( !FAIL_ON_AIR || !state.getBlock().isAir( state, world, newPosition ) )
{
IBlockState state = world.getBlockState( newPosition );
Block block = state.getBlock();
String name = Block.REGISTRY.getNameForObject( block ).toString();
int metadata = block.getMetaFromState( state );
Map<Object, Object> table = new HashMap<>();
Map<String, Object> table = new HashMap<>();
table.put( "name", name );
table.put( "metadata", metadata );
@ -73,7 +75,15 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
}
table.put( "state", stateTable );
return TurtleCommandResult.success( new Object[]{ table } );
// Fire the event, exiting if it is cancelled
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
TurtleBlockEvent.Inspect event = new TurtleBlockEvent.Inspect( turtle, turtlePlayer, world, newPosition, state, table );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return TurtleCommandResult.failure( event.getFailureMessage() );
}
return TurtleCommandResult.success( new Object[] { table } );
}
}
@ -83,7 +93,7 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
table.put( "name", "minecraft:air" );
table.put( "metadata", 0 );
table.put( "state", new HashMap<>() );
return TurtleCommandResult.success( new Object[]{ table } );
return TurtleCommandResult.success( new Object[] { table } );
}
return TurtleCommandResult.failure( "No block to inspect" );
}

View File

@ -11,6 +11,7 @@
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
@ -18,6 +19,7 @@
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import java.util.List;
@ -103,6 +105,12 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
}
}
TurtleBlockEvent.Move moveEvent = new TurtleBlockEvent.Move( turtle, turtlePlayer, oldWorld, newPosition );
if( MinecraftForge.EVENT_BUS.post( moveEvent ) )
{
return TurtleCommandResult.failure( moveEvent.getFailureMessage() );
}
// Check fuel level
if( turtle.isFuelNeeded() && turtle.getFuelLevel() < 1 )
{

View File

@ -11,6 +11,7 @@
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
@ -31,6 +32,7 @@
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.Event;
import org.apache.commons.lang3.tuple.Pair;
@ -64,6 +66,16 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
World world = turtle.getWorld();
BlockPos coordinates = WorldUtil.moveCoords( turtle.getPosition(), direction );
// Create a fake player, and orient it appropriately
BlockPos playerPosition = WorldUtil.moveCoords( turtle.getPosition(), direction );
TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction );
TurtleBlockEvent.Place place = new TurtleBlockEvent.Place( turtle, turtlePlayer, turtle.getWorld(), coordinates, stack );
if( MinecraftForge.EVENT_BUS.post( place ) )
{
return TurtleCommandResult.failure( place.getFailureMessage() );
}
IBlockState previousState;
if( WorldUtil.isBlockInWorld( world, coordinates ) )
{
@ -75,8 +87,8 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
}
// Do the deploying
String[] errorMessage = new String[1];
ItemStack remainder = deploy( stack, turtle, direction, m_extraArguments, errorMessage );
String[] errorMessage = new String[ 1 ];
ItemStack remainder = deploy( stack, turtle, turtlePlayer, direction, m_extraArguments, errorMessage );
if( remainder != stack )
{
// Put the remaining items back
@ -117,6 +129,11 @@ public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle,
BlockPos playerPosition = WorldUtil.moveCoords( turtle.getPosition(), direction );
TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction );
return deploy( stack, turtle, turtlePlayer, direction, extraArguments, o_errorMessage );
}
public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, EnumFacing direction, Object[] extraArguments, String[] o_errorMessage )
{
// Deploy on an entity
ItemStack remainder = deployOnEntity( stack, turtle, turtlePlayer, direction, extraArguments, o_errorMessage );
if( remainder != stack )

View File

@ -10,9 +10,12 @@
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 net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
@ -71,6 +74,12 @@ private TurtleCommandResult refuel( ITurtleAccess turtle, @Nonnull ItemStack sta
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

View File

@ -10,6 +10,7 @@
import dan200.computercraft.api.turtle.ITurtleCommand;
import dan200.computercraft.api.turtle.TurtleAnimation;
import dan200.computercraft.api.turtle.TurtleCommandResult;
import dan200.computercraft.api.turtle.event.TurtleInventoryEvent;
import dan200.computercraft.shared.util.InventoryUtil;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.entity.Entity;
@ -19,6 +20,7 @@
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
@ -56,6 +58,15 @@ public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
EnumFacing side = direction.getOpposite();
IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side );
// Fire the event, exiting if it is cancelled.
TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
TurtleInventoryEvent.Suck event = new TurtleInventoryEvent.Suck( turtle, player, world, newPosition, inventory );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return TurtleCommandResult.failure( event.getFailureMessage() );
}
if( inventory != null )
{
// Take from inventory of thing in front

View File

@ -10,7 +10,10 @@
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.DirectionUtil;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
@ -27,6 +30,12 @@ public TurtleTurnCommand( TurnDirection direction )
@Override
public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
{
TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.TURN );
if( MinecraftForge.EVENT_BUS.post( event ) )
{
return TurtleCommandResult.failure( event.getFailureMessage() );
}
switch( m_direction )
{
case Left:

View File

@ -9,6 +9,8 @@
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.turtle.*;
import dan200.computercraft.api.turtle.event.TurtleAttackEvent;
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
import dan200.computercraft.shared.turtle.core.TurtleBrain;
import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand;
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
@ -127,11 +129,11 @@ public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull Turt
{
case Attack:
{
return attack( turtle, direction );
return attack( turtle, direction, side );
}
case Dig:
{
return dig( turtle, direction );
return dig( turtle, direction, side );
}
default:
{
@ -161,7 +163,7 @@ protected float getDamageMultiplier()
return 3.0f;
}
private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direction )
private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direction, TurtleSide side )
{
// Create a fake player, and orient it appropriately
final World world = turtle.getWorld();
@ -178,8 +180,21 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc
ItemStack stackCopy = m_item.copy();
turtlePlayer.loadInventory( stackCopy );
// Start claiming entity drops
Entity hitEntity = hit.getKey();
// Fire several events to ensure we have permissions.
if( MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) || !hitEntity.canBeAttackedWithItem() )
{
return TurtleCommandResult.failure( "Nothing to attack here" );
}
TurtleAttackEvent attackEvent = new TurtleAttackEvent( turtle, turtlePlayer, hitEntity, this, side );
if( MinecraftForge.EVENT_BUS.post( attackEvent ) )
{
return TurtleCommandResult.failure( attackEvent.getFailureMessage() );
}
// Start claiming entity drops
ComputerCraft.setEntityDropConsumer( hitEntity, ( entity, drop ) ->
{
ItemStack remainder = InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() );
@ -191,8 +206,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc
// Attack the entity
boolean attacked = false;
if( hitEntity.canBeAttackedWithItem() && !hitEntity.hitByEntity( turtlePlayer )
&& !MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) )
if( !hitEntity.hitByEntity( turtlePlayer ) )
{
float damage = (float)turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue();
damage *= getDamageMultiplier();
@ -233,7 +247,7 @@ private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direc
return TurtleCommandResult.failure( "Nothing to attack here" );
}
private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction )
private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction, TurtleSide side )
{
// Get ready to dig
World world = turtle.getWorld();
@ -266,6 +280,13 @@ private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction )
return TurtleCommandResult.failure( "Unbreakable block detected" );
}
// Fire the dig event, checking whether it was cancelled.
TurtleBlockEvent.Dig digEvent = new TurtleBlockEvent.Dig( turtle, turtlePlayer, world, newPosition, world.getBlockState( newPosition ), this, side );
if( MinecraftForge.EVENT_BUS.post( digEvent ) )
{
return TurtleCommandResult.failure( digEvent.getFailureMessage() );
}
// Consume the items the block drops
if( canHarvestBlock( turtle, newPosition ) )
{

View File

@ -62,5 +62,6 @@ gui.computercraft:config.turtle_fuel_limit=Turtle fuel limit
gui.computercraft:config.advanced_turtle_fuel_limit=Advanced Turtle fuel limit
gui.computercraft:config.turtles_obey_block_protection=Turtles obey block protection
gui.computercraft:config.turtles_can_push=Turtles can push entities
gui.computercraft:config.turtle_disabled_actions=Disabled turtle actions
gui.computercraft:config.maximum_files_open=Maximum files open per computer
gui.computercraft:config.max_notes_per_tick=Maximum notes that a computer can play at once