diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java index 1af570dc3..48ddd8cab 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java @@ -8,6 +8,7 @@ import net.minecraft.block.Blocks; import net.minecraft.block.DispenserBlock; import net.minecraft.dispenser.DefaultDispenseItemBehavior; import net.minecraft.dispenser.IDispenseItemBehavior; +import net.minecraft.dispenser.ProjectileDispenseBehavior; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; @@ -45,12 +46,20 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour { ItemStack backup = itemstack.copy(); // If none is there, try vanilla registry try { + IDispenseItemBehavior idispenseitembehavior = BEHAVIOUR_LOOKUP.getBehavior(itemstack); + if (idispenseitembehavior instanceof ProjectileDispenseBehavior) { // Projectile behaviours can be converted most of the time + IMovedDispenseItemBehaviour iMovedDispenseItemBehaviour = MovedProjectileDispenserBehaviour.of((ProjectileDispenseBehavior) idispenseitembehavior); + setItemStackAt(location, iMovedDispenseItemBehaviour.dispense(itemstack, context, pos), context); + registerMovedDispenseItemBehaviour(itemstack.getItem(), iMovedDispenseItemBehaviour); // buffer conversion if successful + return; + } + 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 = BEHAVIOUR_LOOKUP.getBehavior(itemstack); + if (idispenseitembehavior.getClass() != DefaultDispenseItemBehavior.class) { // There is a dispense item behaviour registered for the vanilla dispenser setItemStackAt(location, idispenseitembehavior.dispense(blockSource, itemstack), context); return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java index 7ef9d1748..fba60a901 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/IMovedDispenseItemBehaviour.java @@ -9,13 +9,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.IProjectile; import net.minecraft.entity.SpawnReason; -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.fluid.FlowingFluid; import net.minecraft.fluid.Fluid; -import net.minecraft.item.BucketItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.SpawnEggItem; @@ -36,70 +34,6 @@ 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; - } - }); - - MovedProjectileDispenserBehaviour movedPotionDispenseItemBehaviour = new MovedProjectileDispenserBehaviour() { @Override protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java index 924cefff0..a40a1ce32 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedProjectileDispenserBehaviour.java @@ -1,6 +1,8 @@ package com.simibubi.create.content.contraptions.components.actors.dispenser; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import net.minecraft.dispenser.IPosition; +import net.minecraft.dispenser.ProjectileDispenseBehavior; import net.minecraft.entity.Entity; import net.minecraft.entity.IProjectile; import net.minecraft.item.ItemStack; @@ -9,6 +11,8 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import java.lang.reflect.Method; + public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDispenseItemBehaviour { @Override protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) { @@ -16,6 +20,8 @@ public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDisp 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); + if (iprojectile == null) + return 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); @@ -37,4 +43,19 @@ public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDisp protected float getProjectileVelocity() { return 1.1F; } + + public static MovedProjectileDispenserBehaviour of(ProjectileDispenseBehavior vanillaBehaviour) { + return new MovedProjectileDispenserBehaviour() { + @Override + protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) { + try { + Method projectileLookup = ProjectileDispenseBehavior.class.getDeclaredMethod("getProjectileEntity", World.class, IPosition.class, ItemStack.class); + projectileLookup.setAccessible(true); + return (IProjectile) projectileLookup.invoke(vanillaBehaviour, world, new SimplePos(x, y, z) , itemStack); + } catch (Throwable ignored) { + } + return null; + } + }; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java new file mode 100644 index 000000000..14d9f9d7d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/SimplePos.java @@ -0,0 +1,30 @@ +package com.simibubi.create.content.contraptions.components.actors.dispenser; + +import net.minecraft.dispenser.IPosition; + +public class SimplePos implements IPosition { + private final int x; + private final int y; + private final int z; + + public SimplePos(double x, double y, double z) { + this.x = (int) Math.round(x); + this.y = (int) Math.round(y); + this.z = (int) Math.round(z); + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getZ() { + return z; + } +}