Added indirect projectile dispense behaviours for compatibility with modded projectiles right out of the box. Removed the direct projectile behaviours from vanilla as they are now covered from the indirect implementation.

This commit is contained in:
grimmauld 2020-09-10 16:28:55 +02:00
parent 3d006e7e87
commit 34f9516d54
4 changed files with 61 additions and 67 deletions

View File

@ -8,6 +8,7 @@ import net.minecraft.block.Blocks;
import net.minecraft.block.DispenserBlock; import net.minecraft.block.DispenserBlock;
import net.minecraft.dispenser.DefaultDispenseItemBehavior; import net.minecraft.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.dispenser.IDispenseItemBehavior; import net.minecraft.dispenser.IDispenseItemBehavior;
import net.minecraft.dispenser.ProjectileDispenseBehavior;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -45,12 +46,20 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour {
ItemStack backup = itemstack.copy(); ItemStack backup = itemstack.copy();
// If none is there, try vanilla registry // If none is there, try vanilla registry
try { 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()); Vec3d facingVec = new Vec3d(context.state.get(DispenserBlock.FACING).getDirectionVec());
facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z); facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
facingVec.normalize(); facingVec.normalize();
Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z); Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z);
ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing); 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 if (idispenseitembehavior.getClass() != DefaultDispenseItemBehavior.class) { // There is a dispense item behaviour registered for the vanilla dispenser
setItemStackAt(location, idispenseitembehavior.dispense(blockSource, itemstack), context); setItemStackAt(location, idispenseitembehavior.dispense(blockSource, itemstack), context);
return; return;

View File

@ -9,13 +9,11 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.IProjectile; import net.minecraft.entity.IProjectile;
import net.minecraft.entity.SpawnReason; import net.minecraft.entity.SpawnReason;
import net.minecraft.entity.item.ExperienceBottleEntity;
import net.minecraft.entity.item.FireworkRocketEntity; import net.minecraft.entity.item.FireworkRocketEntity;
import net.minecraft.entity.item.TNTEntity; import net.minecraft.entity.item.TNTEntity;
import net.minecraft.entity.projectile.*; import net.minecraft.entity.projectile.*;
import net.minecraft.fluid.FlowingFluid; import net.minecraft.fluid.FlowingFluid;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
import net.minecraft.item.BucketItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.item.SpawnEggItem; import net.minecraft.item.SpawnEggItem;
@ -36,70 +34,6 @@ import java.util.Random;
public interface IMovedDispenseItemBehaviour { public interface IMovedDispenseItemBehaviour {
static void init() { 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() { MovedProjectileDispenserBehaviour movedPotionDispenseItemBehaviour = new MovedProjectileDispenserBehaviour() {
@Override @Override
protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) { protected IProjectile getProjectileEntity(World world, double x, double y, double z, ItemStack itemStack) {

View File

@ -1,6 +1,8 @@
package com.simibubi.create.content.contraptions.components.actors.dispenser; package com.simibubi.create.content.contraptions.components.actors.dispenser;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; 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.Entity;
import net.minecraft.entity.IProjectile; import net.minecraft.entity.IProjectile;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -9,6 +11,8 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.lang.reflect.Method;
public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDispenseItemBehaviour { public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDispenseItemBehaviour {
@Override @Override
protected ItemStack dispenseStack(ItemStack itemStack, MovementContext context, BlockPos pos, Vec3d facing) { 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 y = pos.getY() + facing.y * .7 + .5;
double z = pos.getZ() + facing.z * .7 + .5; double z = pos.getZ() + facing.z * .7 + .5;
IProjectile iprojectile = this.getProjectileEntity(context.world, x, y, z, itemStack); IProjectile iprojectile = this.getProjectileEntity(context.world, x, y, z, itemStack);
if (iprojectile == null)
return itemStack;
Vec3d effectiveMovementVec = facing.scale(getProjectileVelocity()).add(context.motion); Vec3d effectiveMovementVec = facing.scale(getProjectileVelocity()).add(context.motion);
iprojectile.shoot(effectiveMovementVec.x, effectiveMovementVec.y, effectiveMovementVec.z, (float) effectiveMovementVec.length(), this.getProjectileInaccuracy()); iprojectile.shoot(effectiveMovementVec.x, effectiveMovementVec.y, effectiveMovementVec.z, (float) effectiveMovementVec.length(), this.getProjectileInaccuracy());
context.world.addEntity((Entity) iprojectile); context.world.addEntity((Entity) iprojectile);
@ -37,4 +43,19 @@ public abstract class MovedProjectileDispenserBehaviour extends MovedDefaultDisp
protected float getProjectileVelocity() { protected float getProjectileVelocity() {
return 1.1F; 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;
}
};
}
} }

View File

@ -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;
}
}