Throw, Punch, Fill and Destroy
- Deployers can now use buckets properly - Deployers can interact with entities - Deployers can use items to hurt entities and break blocks - Deployers can left-click blocks - Deployers automatically pick up items gathered from interacting with or killing entities - Deployers eject collected items when no Inventory is adjacent - Fixed Deployers throwing projectiles from the wrong height - Fixed blocks not dropping applied filter items - Fixed adjustable crates not invalidating their inventory - Fixed shift-clicking in crate guis - Fixed vertical funnels not dropping when destroyed - Added NBT utility for writing and reading lists
This commit is contained in:
parent
b8490038fd
commit
39cbf77457
10 changed files with 380 additions and 42 deletions
|
@ -7,12 +7,15 @@ import com.simibubi.create.AllPackets;
|
|||
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
|
||||
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class FilteringBehaviour extends TileEntityBehaviour {
|
||||
|
||||
|
@ -127,6 +130,17 @@ public class FilteringBehaviour extends TileEntityBehaviour {
|
|||
tileEntity.sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (filter.getItem() instanceof FilterItem) {
|
||||
Vec3d pos = VecHelper.getCenterOf(getPos());
|
||||
World world = getWorld();
|
||||
world.addEntity(new ItemEntity(world, pos.x, pos.y, pos.z, filter.copy()));
|
||||
}
|
||||
|
||||
super.remove();
|
||||
}
|
||||
|
||||
public ItemStack getFilter() {
|
||||
return filter.copy();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
|
||||
public class NBTHelper {
|
||||
|
||||
public static <T extends Enum<?>> T readEnum(String name, Class<T> enumClass) {
|
||||
|
@ -17,4 +25,24 @@ public class NBTHelper {
|
|||
return enumConstant.name();
|
||||
}
|
||||
|
||||
public static <T> ListNBT writeCompoundList(List<T> list, Function<T, CompoundNBT> serializer) {
|
||||
ListNBT listNBT = new ListNBT();
|
||||
list.forEach(t -> listNBT.add(serializer.apply(t)));
|
||||
return listNBT;
|
||||
}
|
||||
|
||||
public static <T> List<T> readCompoundList(ListNBT listNBT, Function<CompoundNBT, T> deserializer) {
|
||||
List<T> list = new ArrayList<>(listNBT.size());
|
||||
listNBT.forEach(inbt -> list.add(deserializer.apply((CompoundNBT) inbt)));
|
||||
return list;
|
||||
}
|
||||
|
||||
public static ListNBT writeItemList(List<ItemStack> stacks) {
|
||||
return writeCompoundList(stacks, ItemStack::serializeNBT);
|
||||
}
|
||||
|
||||
public static List<ItemStack> readItemList(ListNBT stacks) {
|
||||
return readCompoundList(stacks, ItemStack::read);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simibubi.create.modules.contraptions.components.deployer;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.block.IWithTileEntity;
|
||||
import com.simibubi.create.foundation.utility.AllShapes;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
|
@ -54,10 +55,26 @@ public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithT
|
|||
}
|
||||
return super.onWrenched(state, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
te.player.inventory.dropAllItems();
|
||||
te.overflowItems.forEach(itemstack -> te.player.dropItem(itemstack, true, false));
|
||||
});
|
||||
|
||||
worldIn.removeTileEntity(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
|
||||
BlockRayTraceResult hit) {
|
||||
ItemStack held = player.getHeldItem(handIn);
|
||||
if (AllItems.WRENCH.typeOf(held))
|
||||
return false;
|
||||
|
||||
if (hit.getFace() == state.get(FACING)) {
|
||||
if (!worldIn.isRemote)
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
|
@ -66,6 +83,7 @@ public class DeployerBlock extends DirectionalAxisKineticBlock implements IWithT
|
|||
return;
|
||||
player.inventory.placeItemBackInInventory(worldIn, heldItemMainhand);
|
||||
te.player.setHeldItem(Hand.MAIN_HAND, ItemStack.EMPTY);
|
||||
te.sendData();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@ import java.util.OptionalInt;
|
|||
import java.util.UUID;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.Pose;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.inventory.container.INamedContainerProvider;
|
||||
import net.minecraft.network.IPacket;
|
||||
|
@ -14,9 +17,21 @@ import net.minecraft.network.NetworkManager;
|
|||
import net.minecraft.network.PacketDirection;
|
||||
import net.minecraft.network.play.ServerPlayNetHandler;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.EntityDamageSource;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.entity.EntityEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDropsEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingExperienceDropEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber
|
||||
public class DeployerFakePlayer extends FakePlayer {
|
||||
|
||||
private static final NetworkManager NETWORK_MANAGER = new NetworkManager(PacketDirection.CLIENTBOUND);
|
||||
|
@ -33,6 +48,52 @@ public class DeployerFakePlayer extends FakePlayer {
|
|||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITextComponent getDisplayName() {
|
||||
return new StringTextComponent(Lang.translate("block.deployer.damage_source_name"));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public float getEyeHeight(Pose poseIn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getPositionVector() {
|
||||
return new Vec3d(posX, posY, posZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCooldownPeriod() {
|
||||
return 1 / 64f;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void deployerHasEyesOnHisFeet(EntityEvent.EyeHeight event) {
|
||||
if (event.getEntity() instanceof DeployerFakePlayer)
|
||||
event.setNewHeight(0);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) {
|
||||
if (!(event.getSource() instanceof EntityDamageSource))
|
||||
return;
|
||||
EntityDamageSource source = (EntityDamageSource) event.getSource();
|
||||
Entity trueSource = source.getTrueSource();
|
||||
if (trueSource != null && trueSource instanceof DeployerFakePlayer) {
|
||||
DeployerFakePlayer fakePlayer = (DeployerFakePlayer) trueSource;
|
||||
event.getDrops()
|
||||
.forEach(stack -> fakePlayer.inventory.placeItemBackInInventory(trueSource.world, stack.getItem()));
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void deployerKillsDoNotSpawnXP(LivingExperienceDropEvent event) {
|
||||
if (event.getAttackingPlayer() instanceof DeployerFakePlayer)
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
private static class FakePlayNetHandler extends ServerPlayNetHandler {
|
||||
public FakePlayNetHandler(MinecraftServer server, ServerPlayerEntity playerIn) {
|
||||
super(server, NETWORK_MANAGER, playerIn);
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
|
||||
|
@ -21,16 +22,31 @@ import com.simibubi.create.foundation.item.ItemHelper;
|
|||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.WrappedWorld;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.BucketItem;
|
||||
import net.minecraft.item.FlintAndSteelItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUseContext;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
|
@ -42,9 +58,14 @@ import net.minecraft.util.math.RayTraceContext;
|
|||
import net.minecraft.util.math.RayTraceContext.BlockMode;
|
||||
import net.minecraft.util.math.RayTraceContext.FluidMode;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.ITickList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock;
|
||||
import net.minecraftforge.eventbus.api.Event.Result;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
|
@ -61,8 +82,10 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
protected DeployerFakePlayer player;
|
||||
protected int timer;
|
||||
protected float reach;
|
||||
protected List<ItemStack> overflowItems = new ArrayList<>();
|
||||
protected Pair<BlockPos, Float> blockBreakingProgress;
|
||||
|
||||
private List<ItemStack> overflowItems = new ArrayList<>();
|
||||
private ListNBT deferredInventoryList;
|
||||
|
||||
enum State {
|
||||
WAITING, EXPANDING, RETRACTING, DUMPING;
|
||||
|
@ -94,8 +117,15 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
if (!world.isRemote)
|
||||
if (!world.isRemote) {
|
||||
player = new DeployerFakePlayer((ServerWorld) world);
|
||||
if (deferredInventoryList != null) {
|
||||
player.inventory.read(deferredInventoryList);
|
||||
deferredInventoryList = null;
|
||||
heldItem = player.getHeldItemMainhand();
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onExtract(ItemStack stack) {
|
||||
|
@ -109,7 +139,7 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
|
||||
protected int getTimerSpeed() {
|
||||
return (int) (getSpeed() == 0 ? 0 : MathHelper.clamp(Math.abs(getSpeed()) / 4, 1, 512));
|
||||
return (int) (getSpeed() == 0 ? 0 : MathHelper.clamp(Math.abs(getSpeed()) / 2, 8, 512));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,6 +148,12 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
|
||||
if (getSpeed() == 0)
|
||||
return;
|
||||
if (!world.isRemote && blockBreakingProgress != null) {
|
||||
if (world.isAirBlock(blockBreakingProgress.getKey())) {
|
||||
world.sendBlockBreakProgress(player.getEntityId(), blockBreakingProgress.getKey(), -1);
|
||||
blockBreakingProgress = null;
|
||||
}
|
||||
}
|
||||
if (timer > 0) {
|
||||
timer -= getTimerSpeed();
|
||||
return;
|
||||
|
@ -125,6 +161,7 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
ItemStack stack = player.getHeldItemMainhand();
|
||||
if (state == State.WAITING) {
|
||||
if (!overflowItems.isEmpty()) {
|
||||
tryDisposeOfItems();
|
||||
|
@ -133,24 +170,34 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!filtering.test(player.getHeldItemMainhand())) {
|
||||
if (!player.getHeldItemMainhand().isEmpty()) {
|
||||
overflowItems.add(player.getHeldItemMainhand());
|
||||
if (!filtering.test(stack)) {
|
||||
if (!stack.isEmpty()) {
|
||||
overflowItems.add(stack);
|
||||
player.setHeldItem(Hand.MAIN_HAND, ItemStack.EMPTY);
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
extracting.extract(1);
|
||||
if (!filtering.test(player.getHeldItemMainhand()))
|
||||
if (!filtering.test(stack))
|
||||
timer = getTimerSpeed() * 10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (filtering.getFilter().isEmpty() && player.getHeldItemMainhand().isEmpty())
|
||||
if (filtering.getFilter().isEmpty() && stack.isEmpty())
|
||||
extracting.extract(1);
|
||||
|
||||
if (player.getHeldItemMainhand().getItem() instanceof BlockItem) {
|
||||
if (!world.getBlockState(pos.offset(getBlockState().get(FACING), 2)).getMaterial().isReplaceable()) {
|
||||
Direction facing = getBlockState().get(FACING);
|
||||
if (stack.getItem() instanceof BlockItem) {
|
||||
if (!world.getBlockState(pos.offset(facing, 2)).getMaterial().isReplaceable()) {
|
||||
timer = getTimerSpeed() * 10;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.getItem() instanceof BucketItem) {
|
||||
BucketItem bucketItem = (BucketItem) stack.getItem();
|
||||
Fluid fluid = bucketItem.getFluid();
|
||||
if (fluid != Fluids.EMPTY && world.getFluidState(pos.offset(facing, 2)).getFluid() == fluid) {
|
||||
timer = getTimerSpeed() * 10;
|
||||
return;
|
||||
}
|
||||
|
@ -161,7 +208,7 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f));
|
||||
Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f));
|
||||
RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE,
|
||||
FluidMode.SOURCE_ONLY, player);
|
||||
FluidMode.NONE, player);
|
||||
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
|
||||
reach = (float) (.5f + Math.min(result.getHitVec().subtract(rayOrigin).length(), .75f));
|
||||
|
||||
|
@ -171,7 +218,12 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
|
||||
if (state == State.EXPANDING) {
|
||||
Multimap<String, AttributeModifier> attributeModifiers = stack
|
||||
.getAttributeModifiers(EquipmentSlotType.MAINHAND);
|
||||
player.getAttributes().applyAttributeModifiers(attributeModifiers);
|
||||
activate();
|
||||
player.getAttributes().removeAttributeModifiers(attributeModifiers);
|
||||
|
||||
state = State.RETRACTING;
|
||||
timer = 1000;
|
||||
sendData();
|
||||
|
@ -189,57 +241,180 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
|
||||
protected void activate() {
|
||||
// Update player position and angle
|
||||
Vec3d movementVector = getMovementVector();
|
||||
Direction direction = getBlockState().get(FACING);
|
||||
Vec3d center = VecHelper.getCenterOf(pos);
|
||||
Vec3d rayOrigin = center.add(movementVector.scale(3 / 2f + 1 / 64f));
|
||||
Vec3d rayTarget = center.add(movementVector.scale(5 / 2f - 1 / 64f));
|
||||
BlockPos clickedPos = pos.offset(direction, 2);
|
||||
|
||||
player.rotationYaw = AngleHelper.horizontalAngle(direction);
|
||||
player.rotationYaw = AngleHelper.horizontalAngle(direction) + 180;
|
||||
player.rotationPitch = direction == Direction.UP ? -90 : direction == Direction.DOWN ? 90 : 0;
|
||||
player.setPosition(rayOrigin.x, rayOrigin.y, rayOrigin.z);
|
||||
|
||||
BlockPos clicked = pos.offset(direction, 2);
|
||||
ItemStack stack = player.getHeldItemMainhand();
|
||||
Item item = stack.getItem();
|
||||
|
||||
List<LivingEntity> entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(clicked));
|
||||
// Check for entities
|
||||
World world = this.world;
|
||||
List<LivingEntity> entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(clickedPos));
|
||||
Hand hand = Hand.MAIN_HAND;
|
||||
if (!entities.isEmpty()) {
|
||||
stack.interactWithEntity(player, entities.get(world.rand.nextInt(entities.size())), Hand.MAIN_HAND);
|
||||
LivingEntity entity = entities.get(world.rand.nextInt(entities.size()));
|
||||
List<ItemEntity> capturedDrops = new ArrayList<>();
|
||||
boolean success = false;
|
||||
entity.captureDrops(capturedDrops);
|
||||
|
||||
// Use on entity
|
||||
if (mode == Mode.USE) {
|
||||
ActionResultType cancelResult = ForgeHooks.onInteractEntity(player, entity, hand);
|
||||
if (cancelResult == ActionResultType.FAIL) {
|
||||
entity.captureDrops(null);
|
||||
return;
|
||||
}
|
||||
if (cancelResult == null) {
|
||||
if (entity.processInitialInteract(player, hand))
|
||||
success = true;
|
||||
else if (stack.interactWithEntity(player, entity, hand))
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Punch entity
|
||||
if (mode == Mode.PUNCH) {
|
||||
player.resetCooldown();
|
||||
player.attackTargetEntityWithCurrentItem(entity);
|
||||
success = true;
|
||||
}
|
||||
|
||||
entity.captureDrops(null);
|
||||
capturedDrops.forEach(e -> player.inventory.placeItemBackInInventory(this.world, e.getItem()));
|
||||
if (success)
|
||||
return;
|
||||
}
|
||||
|
||||
// Shoot ray
|
||||
RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE,
|
||||
player);
|
||||
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
|
||||
BlockState clickedState = world.getBlockState(clickedPos);
|
||||
|
||||
// Left click
|
||||
if (mode == Mode.PUNCH) {
|
||||
LeftClickBlock event = ForgeHooks.onLeftClickBlock(player, clickedPos, direction.getOpposite());
|
||||
if (event.isCanceled())
|
||||
return;
|
||||
if (!world.isBlockModifiable(player, clickedPos))
|
||||
return;
|
||||
if (world.extinguishFire(player, clickedPos, direction.getOpposite()))
|
||||
return;
|
||||
if (clickedState.isAir(world, clickedPos))
|
||||
return;
|
||||
if (event.getUseBlock() != Result.DENY)
|
||||
clickedState.onBlockClicked(world, clickedPos, player);
|
||||
if (stack.isEmpty())
|
||||
return;
|
||||
|
||||
float progress = clickedState.getPlayerRelativeBlockHardness(player, world, clickedPos) * 16;
|
||||
float before = 0;
|
||||
if (blockBreakingProgress != null)
|
||||
before = blockBreakingProgress.getValue();
|
||||
progress += before;
|
||||
|
||||
if (progress >= 1) {
|
||||
player.interactionManager.tryHarvestBlock(clickedPos);
|
||||
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, -1);
|
||||
blockBreakingProgress = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) (before * 10) != (int) (progress * 10))
|
||||
world.sendBlockBreakProgress(player.getEntityId(), clickedPos, (int) (progress * 10));
|
||||
blockBreakingProgress = Pair.of(clickedPos, progress);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f + 1 / 64f));
|
||||
Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f - 1 / 64f));
|
||||
RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE,
|
||||
FluidMode.SOURCE_ONLY, player);
|
||||
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
|
||||
ItemUseContext itemusecontext = new ItemUseContext(player, Hand.MAIN_HAND, result);
|
||||
|
||||
RightClickBlock event = ForgeHooks.onRightClickBlock(player, Hand.MAIN_HAND, clicked, direction.getOpposite());
|
||||
// Right click
|
||||
ItemUseContext itemusecontext = new ItemUseContext(player, hand, result);
|
||||
RightClickBlock event = ForgeHooks.onRightClickBlock(player, hand, clickedPos, direction.getOpposite());
|
||||
|
||||
// Item has active use (food for instance)
|
||||
if (event.getUseItem() != DENY) {
|
||||
ActionResultType actionresult = stack.onItemUseFirst(itemusecontext);
|
||||
if (actionresult != ActionResultType.PASS)
|
||||
return;
|
||||
player.setHeldItem(Hand.MAIN_HAND, stack.onItemUseFinish(world, player));
|
||||
player.setHeldItem(hand, stack.onItemUseFinish(world, player));
|
||||
}
|
||||
|
||||
BlockState clickedState = world.getBlockState(clicked);
|
||||
boolean holdingSomething = !player.getHeldItemMainhand().isEmpty();
|
||||
boolean flag1 = !(player.isSneaking() && holdingSomething)
|
||||
|| (stack.doesSneakBypassUse(world, clicked, player));
|
||||
|| (stack.doesSneakBypassUse(world, clickedPos, player));
|
||||
|
||||
if (event.getUseBlock() != DENY && flag1
|
||||
&& clickedState.onBlockActivated(world, player, Hand.MAIN_HAND, result))
|
||||
// Use on block
|
||||
if (event.getUseBlock() != DENY && flag1 && clickedState.onBlockActivated(world, player, hand, result))
|
||||
return;
|
||||
if (stack.isEmpty())
|
||||
return;
|
||||
if (event.getUseItem() == DENY)
|
||||
return;
|
||||
if (stack.getItem() instanceof BlockItem
|
||||
&& !clickedState.isReplaceable(new BlockItemUseContext(itemusecontext)))
|
||||
if (item instanceof BlockItem && !clickedState.isReplaceable(new BlockItemUseContext(itemusecontext)))
|
||||
return;
|
||||
|
||||
// Reposition fire placement for convenience
|
||||
if (item == Items.FLINT_AND_STEEL) {
|
||||
Direction newFace = result.getFace();
|
||||
BlockPos newPos = result.getPos();
|
||||
if (!FlintAndSteelItem.canSetFire(clickedState, world, clickedPos))
|
||||
newFace = Direction.UP;
|
||||
if (clickedState.getMaterial() == Material.AIR)
|
||||
newPos = newPos.offset(direction);
|
||||
result = new BlockRayTraceResult(result.getHitVec(), newFace, newPos, result.isInside());
|
||||
itemusecontext = new ItemUseContext(player, hand, result);
|
||||
}
|
||||
|
||||
// 'Inert' item use behaviour & block placement
|
||||
ActionResultType onItemUse = stack.onItemUse(itemusecontext);
|
||||
if (onItemUse == ActionResultType.SUCCESS)
|
||||
return;
|
||||
stack.getItem().onItemRightClick(world, player, Hand.MAIN_HAND);
|
||||
|
||||
// some items use hard-coded eye positions
|
||||
if (item == Items.SNOWBALL || item == Items.EGG)
|
||||
player.posY -= 1.5f;
|
||||
if (item == Items.ENDER_PEARL)
|
||||
return;
|
||||
|
||||
// buckets create their own ray, We use a fake wall to contain the active area
|
||||
if (item instanceof BucketItem) {
|
||||
world = new WrappedWorld(world) {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos position) {
|
||||
if (pos.offset(direction, 3).equals(position) || pos.offset(direction, 1).equals(position))
|
||||
return Blocks.BEDROCK.getDefaultState();
|
||||
return world.getBlockState(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPos pos, BlockState oldState, BlockState newState, int flags) {
|
||||
world.notifyBlockUpdate(pos, oldState, newState, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITickList<Block> getPendingBlockTicks() {
|
||||
return world.getPendingBlockTicks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITickList<Fluid> getPendingFluidTicks() {
|
||||
return world.getPendingFluidTicks();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
ActionResult<ItemStack> onItemRightClick = item.onItemRightClick(world, player, hand);
|
||||
player.setHeldItem(hand, onItemRightClick.getResult());
|
||||
}
|
||||
|
||||
protected void returnAndDeposit() {
|
||||
|
@ -264,8 +439,21 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
}
|
||||
|
||||
protected void tryDisposeOfItems() {
|
||||
boolean noInv = extracting.getInventories().isEmpty();
|
||||
for (Iterator<ItemStack> iterator = overflowItems.iterator(); iterator.hasNext();) {
|
||||
ItemStack itemStack = iterator.next();
|
||||
|
||||
if (noInv) {
|
||||
Vec3d offset = getMovementVector();
|
||||
Vec3d outPos = VecHelper.getCenterOf(pos).add(offset.scale(-.65f));
|
||||
Vec3d motion = offset.scale(-.25f);
|
||||
ItemEntity e = new ItemEntity(world, outPos.x, outPos.y, outPos.z, itemStack.copy());
|
||||
e.setMotion(motion);
|
||||
world.addEntity(e);
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
itemStack = insert(itemStack, false);
|
||||
if (itemStack.isEmpty())
|
||||
iterator.remove();
|
||||
|
@ -292,6 +480,8 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
state = NBTHelper.readEnum(compound.getString("State"), State.class);
|
||||
mode = NBTHelper.readEnum(compound.getString("Mode"), Mode.class);
|
||||
timer = compound.getInt("Timer");
|
||||
deferredInventoryList = compound.getList("Inventory", NBT.TAG_COMPOUND);
|
||||
overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND));
|
||||
super.read(compound);
|
||||
}
|
||||
|
||||
|
@ -300,6 +490,12 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
compound.putString("Mode", NBTHelper.writeEnum(mode));
|
||||
compound.putString("State", NBTHelper.writeEnum(state));
|
||||
compound.putInt("Timer", timer);
|
||||
if (player != null) {
|
||||
ListNBT invNBT = new ListNBT();
|
||||
player.inventory.write(invNBT);
|
||||
compound.put("Inventory", invNBT);
|
||||
compound.put("Overflow", NBTHelper.writeItemList(overflowItems));
|
||||
}
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
|
@ -326,6 +522,8 @@ public class DeployerTileEntity extends KineticTileEntity {
|
|||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (!world.isRemote && blockBreakingProgress != null)
|
||||
world.sendBlockBreakProgress(player.getEntityId(), blockBreakingProgress.getKey(), -1);
|
||||
super.remove();
|
||||
player = null;
|
||||
}
|
||||
|
|
|
@ -52,15 +52,23 @@ public class DeployerTileEntityRenderer extends TileEntityRenderer<DeployerTileE
|
|||
GlStateManager.translated(offset.x + x, offset.y + y, offset.z + z);
|
||||
|
||||
Direction facing = deployerState.get(FACING);
|
||||
boolean punching = te.mode == Mode.PUNCH;
|
||||
|
||||
float yRot = AngleHelper.horizontalAngle(facing) + 180;
|
||||
float zRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0;
|
||||
|
||||
GlStateManager.rotatef(yRot, 0, 1, 0);
|
||||
GlStateManager.rotatef(zRot, 1, 0, 0);
|
||||
GlStateManager.translated(0, 0, -11 / 16f);
|
||||
float scale = .5f;
|
||||
|
||||
if (punching) {
|
||||
GlStateManager.translatef(0, 1/8f, -1/16f);
|
||||
// GlStateManager.rotatef(punching ? -45 : 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
float scale = punching ? .75f : .5f;
|
||||
GlStateManager.scaled(scale, scale, scale);
|
||||
|
||||
TransformType transform = te.mode == Mode.PUNCH ? TransformType.FIRST_PERSON_RIGHT_HAND : TransformType.FIXED;
|
||||
TransformType transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED;
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(te.heldItem, transform);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
|
|
@ -22,6 +22,7 @@ import net.minecraft.state.BooleanProperty;
|
|||
import net.minecraft.state.StateContainer.Builder;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
|
@ -180,6 +181,11 @@ public class FunnelBlock extends AttachedLogisticalBlock implements IBeltAttachm
|
|||
protected boolean isVertical() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getLootTable() {
|
||||
return AllBlocks.BELT_FUNNEL.get().getLootTable();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,11 +67,12 @@ public class FlexcrateContainer extends Container {
|
|||
return ItemStack.EMPTY;
|
||||
|
||||
ItemStack stack = clickedSlot.getStack();
|
||||
if (index < 16) {
|
||||
mergeItemStack(stack, 16, inventorySlots.size(), false);
|
||||
int crateSize = doubleCrate ? 32 : 16;
|
||||
if (index < crateSize) {
|
||||
mergeItemStack(stack, crateSize, inventorySlots.size(), false);
|
||||
te.inventory.onContentsChanged(index);
|
||||
} else
|
||||
mergeItemStack(stack, 0, 15, false);
|
||||
mergeItemStack(stack, 0, crateSize - 1, false);
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
|
|
@ -107,11 +107,11 @@ public class FlexcrateTileEntity extends SyncedTileEntity implements INamedConta
|
|||
public void onDestroyed() {
|
||||
FlexcrateTileEntity other = getOtherCrate();
|
||||
if (other == null) {
|
||||
for (int slot = 0; slot < inventory.getSlots(); slot++)
|
||||
for (int slot = 0; slot < inventory.getSlots(); slot++)
|
||||
drop(slot);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FlexcrateTileEntity main = getMainCrate();
|
||||
if (this == main) {
|
||||
for (int slot = 0; slot < inventory.getSlots(); slot++) {
|
||||
|
@ -120,11 +120,14 @@ public class FlexcrateTileEntity extends SyncedTileEntity implements INamedConta
|
|||
}
|
||||
other.allowedAmount = Math.min(1024, allowedAmount);
|
||||
}
|
||||
|
||||
for (int slot = 16; slot < other.inventory.getSlots(); slot++)
|
||||
|
||||
for (int slot = 16; slot < other.inventory.getSlots(); slot++)
|
||||
other.drop(slot);
|
||||
|
||||
other.invHandler.invalidate();
|
||||
other.invHandler = LazyOptional.of(() -> other.inventory);
|
||||
}
|
||||
|
||||
|
||||
private void drop(int slot) {
|
||||
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), inventory.getStackInSlot(slot));
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@
|
|||
"death.attack.create.fan_fire": "%1$s was burned to death by hot air",
|
||||
"death.attack.create.fan_lava": "%1$s was burned to death by lava fan",
|
||||
"death.attack.create.drill": "%1$s was impaled by Mechanical Drill",
|
||||
"create.block.deployer.damage_source_name": "a rogue Deployer",
|
||||
|
||||
"create.recipe.crushing": "Crushing",
|
||||
"create.recipe.splashing": "Bulk Washing",
|
||||
|
|
Loading…
Reference in a new issue