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.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;

View File

@ -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) {

View File

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

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