mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-29 08:27:03 +01:00
Add experimental dropper and dispenser movement behaviours.
WIP: (probably) unstable, definitely buggy Unfinished: Bottles, maybe spawn eggs
This commit is contained in:
parent
53e0c61da7
commit
7e4ca0475e
8 changed files with 462 additions and 1 deletions
|
@ -6,6 +6,8 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.simibubi.create.content.contraptions.components.actors.BellMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.actors.CampfireMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.actors.dispenser.DispenserMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.actors.dispenser.DropperMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||
import com.tterrag.registrate.util.nullness.NonNullConsumer;
|
||||
|
||||
|
@ -48,5 +50,9 @@ public class AllMovementBehaviours {
|
|||
static void register() {
|
||||
addMovementBehaviour(Blocks.BELL, new BellMovementBehaviour());
|
||||
addMovementBehaviour(Blocks.CAMPFIRE, new CampfireMovementBehaviour());
|
||||
|
||||
DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours();
|
||||
addMovementBehaviour(Blocks.DISPENSER, new DispenserMovementBehaviour());
|
||||
addMovementBehaviour(Blocks.DROPPER, new DropperMovementBehaviour());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.dispenser.IBlockSource;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
public class ContraptionBlockSource implements IBlockSource {
|
||||
private final BlockPos pos;
|
||||
private final MovementContext context;
|
||||
private final Direction overrideFacing;
|
||||
|
||||
public ContraptionBlockSource(MovementContext context, BlockPos pos) {
|
||||
this(context, pos, null);
|
||||
}
|
||||
|
||||
public ContraptionBlockSource(MovementContext context, BlockPos pos, @Nullable Direction overrideFacing) {
|
||||
this.pos = pos;
|
||||
this.context = context;
|
||||
this.overrideFacing = overrideFacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getX() {
|
||||
return (double)this.pos.getX() + 0.5D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getY() {
|
||||
return (double)this.pos.getY() + 0.5D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getZ() {
|
||||
return (double)this.pos.getZ() + 0.5D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getBlockPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState() {
|
||||
if(context.state.has(BlockStateProperties.FACING) && overrideFacing != null)
|
||||
return context.state.with(BlockStateProperties.FACING, overrideFacing);
|
||||
return context.state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T extends TileEntity> T getBlockTileEntity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return context.world;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.DispenserBlock;
|
||||
import net.minecraft.dispenser.IDispenseItemBehavior;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class DispenserMovementBehaviour extends DropperMovementBehaviour {
|
||||
private static final HashMap<Item, IMovedDispenseItemBehaviour> MOVED_DISPENSE_ITEM_BEHAVIOURS = new HashMap<>();
|
||||
|
||||
public static void gatherMovedDispenseItemBehaviours() {
|
||||
IMovedDispenseItemBehaviour.init();
|
||||
}
|
||||
|
||||
public static void registerMovedDispenseItemBehaviour(Item item, IMovedDispenseItemBehaviour movedDispenseItemBehaviour) {
|
||||
MOVED_DISPENSE_ITEM_BEHAVIOURS.put(item, movedDispenseItemBehaviour);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(MovementContext context, BlockPos pos) {
|
||||
int i = getDispenseSlot(context);
|
||||
if (i < 0) {
|
||||
context.world.playEvent(1001, pos, 0);
|
||||
} else {
|
||||
ItemStack itemstack = getStacks(context).get(i);
|
||||
if (MOVED_DISPENSE_ITEM_BEHAVIOURS.containsKey(itemstack.getItem())) {
|
||||
MOVED_DISPENSE_ITEM_BEHAVIOURS.get(itemstack.getItem()).dispense(itemstack, context, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int count = itemstack.getCount();
|
||||
// Try vanilla registry
|
||||
try {
|
||||
Vec3d facingVec = new Vec3d(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
||||
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
||||
facingVec.normalize();
|
||||
Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z);
|
||||
ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing);
|
||||
IDispenseItemBehavior idispenseitembehavior = ((DispenserBlock) Blocks.DISPENSER).getBehavior(itemstack);
|
||||
idispenseitembehavior.dispense(blockSource, itemstack);
|
||||
} catch (NullPointerException e) {
|
||||
itemstack.setCount(count);
|
||||
defaultBehaviour.dispense(itemstack, context, pos); // Something went wrong with the TE being null in ContraptionBlockSource, just drop the item
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import com.simibubi.create.content.logistics.item.filter.FilterItem;
|
||||
import com.simibubi.create.foundation.item.ItemHelper;
|
||||
import net.minecraft.inventory.ItemStackHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class DropperMovementBehaviour extends MovementBehaviour {
|
||||
protected static final MovedDefaultDispenseItemBehaviour defaultBehaviour = new MovedDefaultDispenseItemBehaviour();
|
||||
private static final Random RNG = new Random();
|
||||
|
||||
protected void activate(MovementContext context, BlockPos pos) {
|
||||
int i = getDispenseSlot(context);
|
||||
if (i < 0) {
|
||||
context.world.playEvent(1001, pos, 0);
|
||||
} else {
|
||||
defaultBehaviour.dispense(getStacks(context).get(i), context, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewPosition(MovementContext context, BlockPos pos) {
|
||||
if (context.world.isRemote)
|
||||
return;
|
||||
collectItems(context);
|
||||
activate(context, pos);
|
||||
}
|
||||
|
||||
private void collectItems(MovementContext context) {
|
||||
getStacks(context).stream().filter(itemStack -> !itemStack.isEmpty() && itemStack.getItem() != Items.AIR && itemStack.getMaxStackSize() > itemStack.getCount()).forEach(itemStack -> itemStack.grow(
|
||||
ItemHelper.extract(context.contraption.inventory, stack -> FilterItem.test(context.world, stack, itemStack), ItemHelper.ExtractionCountMode.UPTO, itemStack.getMaxStackSize() - itemStack.getCount(), false).getCount()));
|
||||
}
|
||||
|
||||
protected NonNullList<ItemStack> getStacks(MovementContext context) {
|
||||
if (!(context.temporaryData instanceof NonNullList) && context.world instanceof ServerWorld) {
|
||||
NonNullList<ItemStack> stacks = NonNullList.withSize(9, ItemStack.EMPTY);
|
||||
ItemStackHelper.loadAllItems(context.tileData, stacks);
|
||||
context.temporaryData = stacks;
|
||||
}
|
||||
return (NonNullList<ItemStack>) context.temporaryData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExtraData(MovementContext context) {
|
||||
NonNullList<ItemStack> stacks = getStacks(context);
|
||||
if (stacks == null)
|
||||
return;
|
||||
ItemStackHelper.saveAllItems(context.tileData, stacks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopMoving(MovementContext context) {
|
||||
super.stopMoving(context);
|
||||
writeExtraData(context);
|
||||
}
|
||||
|
||||
protected int getDispenseSlot(MovementContext context) {
|
||||
int i = -1;
|
||||
int j = 1;
|
||||
NonNullList<ItemStack> stacks = getStacks(context);
|
||||
for (int k = 0; k < stacks.size(); ++k) {
|
||||
if (!stacks.get(k).isEmpty() && RNG.nextInt(j++) == 0 && stacks.get(k).getCount() >= 2) {
|
||||
i = k;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import net.minecraft.entity.IProjectile;
|
||||
import net.minecraft.entity.item.ExperienceBottleEntity;
|
||||
import net.minecraft.entity.item.FireworkRocketEntity;
|
||||
import net.minecraft.entity.item.TNTEntity;
|
||||
import net.minecraft.entity.projectile.*;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public interface IMovedDispenseItemBehaviour {
|
||||
static void init() {
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.ARROW, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
ArrowEntity arrowEntity = new ArrowEntity(world, x, y, z);
|
||||
arrowEntity.pickupStatus = AbstractArrowEntity.PickupStatus.ALLOWED;
|
||||
return arrowEntity;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.TIPPED_ARROW, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
ArrowEntity arrowEntity = new ArrowEntity(world, x, y, z);
|
||||
arrowEntity.setPotionEffect(itemStack);
|
||||
arrowEntity.pickupStatus = AbstractArrowEntity.PickupStatus.ALLOWED;
|
||||
return arrowEntity;
|
||||
}
|
||||
});
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.SPECTRAL_ARROW, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
AbstractArrowEntity arrowEntity = new SpectralArrowEntity(world, x, y, z);
|
||||
arrowEntity.pickupStatus = AbstractArrowEntity.PickupStatus.ALLOWED;
|
||||
return arrowEntity;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.EGG, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
return Util.make(new EggEntity(world, x, y, z), p_218408_1_ -> p_218408_1_.setItem(itemStack));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.SNOWBALL, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
return Util.make(new SnowballEntity(world, x, y, z), p_218409_1_ -> p_218409_1_.setItem(itemStack));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.EXPERIENCE_BOTTLE, new MovedProjectileDispenserBehaviour() {
|
||||
@Override
|
||||
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {
|
||||
return Util.make(new ExperienceBottleEntity(world, x, y, z), p_218409_1_ -> p_218409_1_.setItem(itemStack));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getProjectileInaccuracy() {
|
||||
return super.getProjectileInaccuracy() * 0.5F;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getProjectileVelocity() {
|
||||
return super.getProjectileVelocity() * 1.25F;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.TNT, new MovedDefaultDispenseItemBehaviour() {
|
||||
@Override
|
||||
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) {
|
||||
double x = pos.getX() + facing.x * .7 + .5;
|
||||
double y = pos.getY() + facing.y * .7 + .5;
|
||||
double z = pos.getZ() + facing.z * .7 + .5;
|
||||
TNTEntity tntentity = new TNTEntity(context.world, x, y, z, null);
|
||||
tntentity.addVelocity(context.motion.x, context.motion.y, context.motion.z);
|
||||
context.world.addEntity(tntentity);
|
||||
context.world.playSound(null, tntentity.getX(), tntentity.getY(), tntentity.getZ(), SoundEvents.ENTITY_TNT_PRIMED, SoundCategory.BLOCKS, 1.0F, 1.0F);
|
||||
itemStack.shrink(1);
|
||||
return itemStack;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.FIREWORK_ROCKET, new MovedDefaultDispenseItemBehaviour() {
|
||||
@Override
|
||||
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) {
|
||||
double x = pos.getX() + facing.x * .7 + .5;
|
||||
double y = pos.getY() + facing.y * .7 + .5;
|
||||
double z = pos.getZ() + facing.z * .7 + .5;
|
||||
FireworkRocketEntity fireworkrocketentity = new FireworkRocketEntity(context.world, itemStack, x, y, z, true);
|
||||
fireworkrocketentity.shoot(facing.x, facing.y, facing.z, 0.5F, 1.0F);
|
||||
context.world.addEntity(fireworkrocketentity);
|
||||
itemStack.shrink(1);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void playDispenseSound(IWorld world, BlockPos pos) {
|
||||
world.playEvent(1004, pos, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
DispenserMovementBehaviour.registerMovedDispenseItemBehaviour(Items.FIRE_CHARGE, new MovedDefaultDispenseItemBehaviour() {
|
||||
@Override
|
||||
protected void playDispenseSound(IWorld world, BlockPos pos) {
|
||||
world.playEvent(1018, pos, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) {
|
||||
Random random = context.world.rand;
|
||||
double x = pos.getX() + facing.x * .7 + .5;
|
||||
double y = pos.getY() + facing.y * .7 + .5;
|
||||
double z = pos.getZ() + facing.z * .7 + .5;
|
||||
context.world.addEntity(Util.make(new SmallFireballEntity(context.world, x, y, z,
|
||||
random.nextGaussian() * 0.05D + facing.x + context.motion.x, random.nextGaussian() * 0.05D + facing.y + context.motion.y, random.nextGaussian() * 0.05D + facing.z + context.motion.z), (p_229425_1_) -> p_229425_1_.setStack(itemStack)));
|
||||
itemStack.shrink(1);
|
||||
return itemStack;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import net.minecraft.block.DispenserBlock;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBehaviour {
|
||||
|
||||
public static void doDispense(World p_82486_0_, ItemStack p_82486_1_, int p_82486_2_, Vec3d facing, BlockPos p_82486_4_) {
|
||||
double d0 = p_82486_4_.getX() + facing.x + .5;
|
||||
double d1 = p_82486_4_.getY() + facing.y + .5;
|
||||
double d2 = p_82486_4_.getZ() + facing.z + .5;
|
||||
if (Direction.getFacingFromVector(facing.x, facing.y, facing.z).getAxis() == Direction.Axis.Y) {
|
||||
d1 = d1 - 0.125D;
|
||||
} else {
|
||||
d1 = d1 - 0.15625D;
|
||||
}
|
||||
|
||||
ItemEntity itementity = new ItemEntity(p_82486_0_, d0, d1, d2, p_82486_1_);
|
||||
double d3 = p_82486_0_.rand.nextDouble() * 0.1D + 0.2D;
|
||||
itementity.setMotion(p_82486_0_.rand.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.getX() * d3, p_82486_0_.rand.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.getY() * d3, p_82486_0_.rand.nextGaussian() * (double) 0.0075F * (double) p_82486_2_ + facing.getZ() * d3);
|
||||
p_82486_0_.addEntity(itementity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos) {
|
||||
Vec3d facingVec = new Vec3d(context.state.get(DispenserBlock.FACING).getDirectionVec());
|
||||
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
|
||||
facingVec.normalize();
|
||||
|
||||
ItemStack itemstack = this.dispenseStack(itemStack, context, pos, facingVec);
|
||||
this.playDispenseSound(context.world, pos);
|
||||
this.spawnDispenseParticles(context.world, pos, facingVec);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispense the specified stack, play the dispense sound and spawn particles.
|
||||
*/
|
||||
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) {
|
||||
ItemStack itemstack = itemStack.split(1);
|
||||
doDispense(context.world, itemstack, 6, facing, pos);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the dispense sound from the specified block.
|
||||
*/
|
||||
protected void playDispenseSound(IWorld world, BlockPos pos) {
|
||||
world.playEvent(1000, pos, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order clients to display dispense particles from the specified block and facing.
|
||||
*/
|
||||
protected void spawnDispenseParticles(IWorld world, BlockPos pos, Vec3d facing) {
|
||||
world.playEvent(2000, pos, Direction.getFacingFromVector(facing.x, facing.y, facing.z).getIndex());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.simibubi.create.content.contraptions.components.actors.dispenser;
|
||||
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.IProjectile;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDispenseItemBehaviour {
|
||||
@Override
|
||||
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) {
|
||||
double x = pos.getX() + facing.x * .7 + .5;
|
||||
double y = pos.getY() + facing.y * .7 + .5;
|
||||
double z = pos.getZ() + facing.z * .7 + .5;
|
||||
IProjectile iprojectile = this.getProjectileEntity(context.world, x, y, z, itemStack);
|
||||
Vec3d effectiveMovementVec = facing.scale(getProjectileVelocity()).add(context.motion);
|
||||
iprojectile.shoot(effectiveMovementVec.x, effectiveMovementVec.y, effectiveMovementVec.z, (float) effectiveMovementVec.length(), this.getProjectileInaccuracy());
|
||||
context.world.addEntity((Entity) iprojectile);
|
||||
itemStack.shrink(1);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void playDispenseSound(IWorld world, BlockPos pos) {
|
||||
world.playEvent(1002, pos, 0);
|
||||
}
|
||||
|
||||
protected abstract IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack);
|
||||
|
||||
protected float getProjectileInaccuracy() {
|
||||
return 6.0F;
|
||||
}
|
||||
|
||||
protected float getProjectileVelocity() {
|
||||
return 1.1F;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
public net.minecraft.network.play.ServerPlayNetHandler field_147365_f # floatingTickCount
|
||||
|
||||
# CubeParticle
|
||||
protected net.minecraft.client.particle.Particle field_228343_B_ # collidedY
|
||||
protected net.minecraft.client.particle.Particle field_228343_B_ # collidedY
|
||||
|
||||
# Dispenser movement behaviour default
|
||||
public net.minecraft.block.DispenserBlock func_149940_a(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/dispenser/IDispenseItemBehavior; # getBehavior
|
Loading…
Reference in a new issue