diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 4812b071a..f189fed6a 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -26,10 +26,12 @@ import com.simibubi.create.modules.contraptions.components.contraptions.piston.M import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonHeadBlock; import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonPoleBlock; import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterBlock; +import com.simibubi.create.modules.contraptions.components.crank.HandCrankBlock; import com.simibubi.create.modules.contraptions.components.crusher.CrushingWheelBlock; import com.simibubi.create.modules.contraptions.components.crusher.CrushingWheelControllerBlock; import com.simibubi.create.modules.contraptions.components.deployer.DeployerBlock; import com.simibubi.create.modules.contraptions.components.fan.EncasedFanBlock; +import com.simibubi.create.modules.contraptions.components.fan.NozzleBlock; import com.simibubi.create.modules.contraptions.components.mixer.MechanicalMixerBlock; import com.simibubi.create.modules.contraptions.components.motor.MotorBlock; import com.simibubi.create.modules.contraptions.components.press.MechanicalPressBlock; @@ -120,8 +122,11 @@ public enum AllBlocks { WATER_WHEEL(new WaterWheelBlock()), ENCASED_FAN(new EncasedFanBlock()), ENCASED_FAN_INNER(new RenderUtilityDirectionalBlock()), + NOZZLE(new NozzleBlock()), TURNTABLE(new TurntableBlock()), SHAFT_HALF(new ShaftHalfBlock()), + HAND_CRANK(new HandCrankBlock()), + HAND_CRANK_HANDLE(new RenderUtilityDirectionalBlock()), CRUSHING_WHEEL(new CrushingWheelBlock()), CRUSHING_WHEEL_CONTROLLER(new CrushingWheelControllerBlock()), diff --git a/src/main/java/com/simibubi/create/AllParticles.java b/src/main/java/com/simibubi/create/AllParticles.java index 3dabf05e2..fda759efa 100644 --- a/src/main/java/com/simibubi/create/AllParticles.java +++ b/src/main/java/com/simibubi/create/AllParticles.java @@ -47,7 +47,7 @@ public enum AllParticles { public ParticleType get() { return entry.getType(); } - + public String parameter() { return Lang.asId(name()); } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 0c320be7d..987c58bc4 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -16,12 +16,15 @@ import com.simibubi.create.modules.contraptions.components.contraptions.piston.M import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntity; import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntityRenderer; +import com.simibubi.create.modules.contraptions.components.crank.HandCrankTileEntity; +import com.simibubi.create.modules.contraptions.components.crank.HandCrankTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.crusher.CrushingWheelControllerTileEntity; import com.simibubi.create.modules.contraptions.components.crusher.CrushingWheelTileEntity; import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntity; import com.simibubi.create.modules.contraptions.components.deployer.DeployerTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.fan.EncasedFanTileEntity; import com.simibubi.create.modules.contraptions.components.fan.EncasedFanTileEntityRenderer; +import com.simibubi.create.modules.contraptions.components.fan.NozzleTileEntity; import com.simibubi.create.modules.contraptions.components.mixer.MechanicalMixerTileEntity; import com.simibubi.create.modules.contraptions.components.mixer.MechanicalMixerTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.motor.MotorTileEntity; @@ -91,8 +94,10 @@ public enum AllTileEntities { TURNTABLE(TurntableTileEntity::new, AllBlocks.TURNTABLE), ENCASED_SHAFT(EncasedShaftTileEntity::new, AllBlocks.ENCASED_SHAFT, AllBlocks.ENCASED_BELT), ENCASED_FAN(EncasedFanTileEntity::new, AllBlocks.ENCASED_FAN), + NOZZLE(NozzleTileEntity::new, AllBlocks.NOZZLE), CLUTCH(ClutchTileEntity::new, AllBlocks.CLUTCH), GEARSHIFT(GearshiftTileEntity::new, AllBlocks.GEARSHIFT), + HAND_CRANK(HandCrankTileEntity::new, AllBlocks.HAND_CRANK), BELT(BeltTileEntity::new, AllBlocks.BELT), BELT_TUNNEL(BeltTunnelTileEntity::new, AllBlocks.BELT_TUNNEL), MECHANICAL_PISTON(MechanicalPistonTileEntity::new, AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON), @@ -179,6 +184,7 @@ public enum AllTileEntities { bind(ClutchTileEntity.class, new SplitShaftTileEntityRenderer()); bind(BeltTileEntity.class, new BeltTileEntityRenderer()); bind(WaterWheelTileEntity.class, new KineticTileEntityRenderer()); + bind(HandCrankTileEntity.class, new HandCrankTileEntityRenderer()); bind(MechanicalPistonTileEntity.class, new MechanicalPistonTileEntityRenderer()); bind(MechanicalBearingTileEntity.class, new MechanicalBearingTileEntityRenderer()); diff --git a/src/main/java/com/simibubi/create/CreateConfig.java b/src/main/java/com/simibubi/create/CreateConfig.java index 04857caf0..29c8371c1 100644 --- a/src/main/java/com/simibubi/create/CreateConfig.java +++ b/src/main/java/com/simibubi/create/CreateConfig.java @@ -61,7 +61,7 @@ public class CreateConfig { // Contraptions public IntValue maxBeltLength, crushingDamage, maxMotorSpeed, maxRotationSpeed; - public IntValue fanMaxPushDistance, fanMaxPullDistance, fanBlockCheckRate, fanRotationArgmax, generatingFanSpeed, + public IntValue fanPushDistance, fanPullDistance, fanBlockCheckRate, fanRotationArgmax, generatingFanSpeed, inWorldProcessingTime; public IntValue maxChassisForTranslation, maxChassisForRotation, maxChassisRange, maxPistonPoles; @@ -206,13 +206,13 @@ public class CreateConfig { .comment("", "Game ticks between Fans checking for anything blocking their air flow.") .translation(basePath + name).defineInRange(name, 30, 10, Integer.MAX_VALUE); - name = "fanMaxPushDistance"; - fanMaxPushDistance = builder.comment("", "Maximum distance in blocks Fans can push entities.") - .translation(basePath + name).defineInRange(name, 20, 1, Integer.MAX_VALUE); + name = "fanPushDistance"; + fanPushDistance = builder.comment("", "Maximum distance in blocks Fans can push entities.") + .translation(basePath + name).defineInRange(name, 20, 5, Integer.MAX_VALUE); - name = "fanMaxPullDistance"; - fanMaxPullDistance = builder.comment("", "Maximum distance in blocks from where Fans can pull entities.") - .translation(basePath + name).defineInRange(name, 10, 1, Integer.MAX_VALUE); + name = "fanPullDistance"; + fanPullDistance = builder.comment("", "Maximum distance in blocks from where Fans can pull entities.") + .translation(basePath + name).defineInRange(name, 20, 5, Integer.MAX_VALUE); name = "fanRotationArgmax"; fanRotationArgmax = builder.comment("", "Rotation speed at which the maximum stats of fans are reached.") @@ -438,6 +438,7 @@ public class CreateConfig { case MOTOR: return 1024; case ENCASED_FAN: + case HAND_CRANK: return 64; case WATER_WHEEL: return 32; @@ -485,6 +486,7 @@ public class CreateConfig { case SHAFT: case SPEED_GAUGE: case STRESS_GAUGE: + case HAND_CRANK: default: return 1; } diff --git a/src/main/java/com/simibubi/create/foundation/utility/AllShapes.java b/src/main/java/com/simibubi/create/foundation/utility/AllShapes.java index 0537cb350..e0613c64e 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AllShapes.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AllShapes.java @@ -70,7 +70,17 @@ public class AllShapes { makeCuboidShape(0, 14, 6, 16, 18, 1)), GAUGE_SHAPE_UP = VoxelShapes.or( makeCuboidShape(1, 0, 0, 15, 2, 16),//plate - makeCuboidShape(2, 2, 1, 14, 14, 15))//log + makeCuboidShape(2, 2, 1, 14, 14, 15)),//log + NOZZLE_SHAPE_UP = VoxelShapes.or( + makeCuboidShape(2, 0, 2, 14, 14, 14), + VoxelShapes.combine( + makeCuboidShape(1, 13, 1, 15, 15, 15), + makeCuboidShape(3, 13, 3, 13, 15, 13), + IBooleanFunction.ONLY_FIRST)), + CRANK_SHAPE_UP = VoxelShapes.or( + makeCuboidShape(5, 0, 5, 11, 6, 11), + makeCuboidShape(1, 3, 1, 15, 8, 15) + ) ; @@ -105,6 +115,8 @@ public class AllShapes { public static final VoxelShaper LOGISTICAL_CASING_MIDDLE = VoxelShaper.forDirectional(LOGISTICAL_CASING_MIDDLE_SHAPE, Direction.UP), LOGISTICAL_CASING_CAP = VoxelShaper.forDirectional(LOGISTICAL_CASING_CAP_SHAPE, Direction.UP), + NOZZLE = VoxelShaper.forDirectional(NOZZLE_SHAPE_UP, Direction.UP), + CRANK = VoxelShaper.forDirectional(CRANK_SHAPE_UP, Direction.UP), CART_ASSEMBLER = VoxelShaper.forHorizontalAxis(CART_ASSEMBLER_SHAPE, Direction.SOUTH), MECHANICAL_PISTON_HEAD = VoxelShaper.forDirectional(MECHANICAL_PISTON_HEAD_SHAPE_UP, Direction.UP), MECHANICAL_PISTON = SHORT_CASING_12_VOXEL, diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java index 5cc41fa23..f299ee454 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/DirectionalKineticBlock.java @@ -44,7 +44,10 @@ public abstract class DirectionalKineticBlock extends KineticBlock { @Override public BlockState getStateForPlacement(BlockItemUseContext context) { - return getDefaultState().with(FACING, context.getFace()); + Direction preferred = getPreferredFacing(context); + if (preferred == null || context.isPlacerSneaking()) + return getDefaultState().with(FACING, context.getNearestLookingDirection().getOpposite()); + return getDefaultState().with(FACING, preferred.getOpposite()); } @Override diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankBlock.java new file mode 100644 index 000000000..7deb1ee0a --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankBlock.java @@ -0,0 +1,64 @@ +package com.simibubi.create.modules.contraptions.components.crank; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.block.IWithTileEntity; +import com.simibubi.create.foundation.utility.AllShapes; +import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; + +public class HandCrankBlock extends DirectionalKineticBlock implements IWithTileEntity { + + public HandCrankBlock() { + super(Properties.from(AllBlocks.COGWHEEL.get())); + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + return AllShapes.CRANK.get(state.get(FACING)); + } + + @Override + public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, + BlockRayTraceResult hit) { + boolean handEmpty = player.getHeldItem(handIn).isEmpty(); + + if (!handEmpty && player.isSneaking()) + return false; + + withTileEntityDo(worldIn, pos, te -> te.turn(player.isSneaking())); + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new HandCrankTileEntity(); + } + + @Override + protected boolean hasStaticPart() { + return false; + } + + @Override + public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) { + return face == state.get(FACING).getOpposite(); + } + + @Override + public Axis getRotationAxis(BlockState state) { + return state.get(FACING).getAxis(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntity.java new file mode 100644 index 000000000..a6c2243aa --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntity.java @@ -0,0 +1,50 @@ +package com.simibubi.create.modules.contraptions.components.crank; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity; + +public class HandCrankTileEntity extends GeneratingKineticTileEntity { + + public int inUse; + public boolean backwards; + public float independentAngle; + public float chasingVelocity; + + public HandCrankTileEntity() { + super(AllTileEntities.HAND_CRANK.type); + } + + public void turn(boolean back) { + boolean update = false; + + if (getGeneratedSpeed() == 0 || back != backwards) + update = true; + + inUse = 10; + this.backwards = back; + if (update && !world.isRemote) + updateGeneratedRotation(); + } + + @Override + public float getGeneratedSpeed() { + return inUse == 0 ? 0 : backwards ? -128 : 128; + } + + @Override + public void tick() { + super.tick(); + + float actualSpeed = getSpeed(); + chasingVelocity += (actualSpeed - chasingVelocity) * .25f; + independentAngle += chasingVelocity; + + if (inUse > 0) { + inUse--; + + if (inUse == 0 && !world.isRemote) + updateGeneratedRotation(); + } + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntityRenderer.java new file mode 100644 index 000000000..b68a28d6c --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crank/HandCrankTileEntityRenderer.java @@ -0,0 +1,35 @@ +package com.simibubi.create.modules.contraptions.components.crank; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.utility.SuperByteBuffer; +import com.simibubi.create.modules.contraptions.base.KineticTileEntity; +import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; + +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.Direction; + +public class HandCrankTileEntityRenderer extends KineticTileEntityRenderer { + + @Override + public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks, + int destroyStage, BufferBuilder buffer) { + super.renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, buffer); + + BlockState state = te.getBlockState(); + if (!AllBlocks.HAND_CRANK.typeOf(state)) + return; + + Direction facing = state.get(FACING); + SuperByteBuffer handle = CreateClient.bufferCache + .renderGenericBlockModel(AllBlocks.HAND_CRANK_HANDLE.getDefault().with(FACING, facing)); + HandCrankTileEntity crank = (HandCrankTileEntity) te; + kineticRotationTransform(handle, te, facing.getAxis(), + (crank.independentAngle + partialTicks * crank.chasingVelocity) / 360, getWorld()); + handle.translate(x, y, z).renderInto(buffer); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanTileEntity.java index c97fdb3ce..404248e7a 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanTileEntity.java @@ -71,8 +71,8 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity { public float getMaxDistance() { float speed = Math.abs(this.getSpeed()); float distanceFactor = Math.min(speed / parameters.fanRotationArgmax.get(), 1); - float pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanMaxPushDistance.get()); - float pullDistance = MathHelper.lerp(distanceFactor, 1.5f, parameters.fanMaxPullDistance.get()); + float pushDistance = MathHelper.lerp(distanceFactor, 3, parameters.fanPushDistance.get()); + float pullDistance = MathHelper.lerp(distanceFactor, 3f, parameters.fanPullDistance.get()); return this.getSpeed() > 0 ? pushDistance : pullDistance; } @@ -119,79 +119,4 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity { airCurrent.tick(); } -// public void processEntity(Entity entity) { -// if (InWorldProcessing.isFrozen()) -// return; -// -// if (entity instanceof ItemEntity) { -// if (world.rand.nextInt(4) == 0) { -// Type processingType = getProcessingType(); -// if (processingType == Type.BLASTING) -// world.addParticle(ParticleTypes.LARGE_SMOKE, entity.posX, entity.posY + .25f, entity.posZ, 0, -// 1 / 16f, 0); -// if (processingType == Type.SMOKING) -// world.addParticle(ParticleTypes.CLOUD, entity.posX, entity.posY + .25f, entity.posZ, 0, 1 / 16f, 0); -// if (processingType == Type.SPLASHING) -// world.addParticle(ParticleTypes.BUBBLE_POP, entity.posX + (world.rand.nextFloat() - .5f) * .5f, -// entity.posY + .25f, entity.posZ + (world.rand.nextFloat() - .5f) * .5f, 0, 1 / 16f, 0); -// } -// -// if (world.isRemote) -// return; -// -// if (canProcess((ItemEntity) entity)) -// InWorldProcessing.applyProcessing((ItemEntity) entity, getProcessingType()); -// -// } else { -// if (getProcessingType() == Type.SMOKING) { -// entity.setFire(2); -// entity.attackEntityFrom(damageSourceFire, 4); -// } -// if (getProcessingType() == Type.BLASTING) { -// entity.setFire(10); -// entity.attackEntityFrom(damageSourceLava, 8); -// } -// if (getProcessingType() == Type.SPLASHING) { -// if (entity.isBurning()) { -// entity.extinguish(); -// world.playSound(null, entity.getPosition(), SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, -// SoundCategory.NEUTRAL, 0.7F, -// 1.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.4F); -// } -// } -// } -// } -// -// protected boolean canProcess() { -// return getProcessingType() != null; -// } -// -// protected boolean canProcess(ItemEntity entity) { -// return canProcess() && InWorldProcessing.canProcess(entity, getProcessingType()); -// } -// -// protected void moveEntity(Entity entity, boolean push) { -// if ((entity instanceof ItemEntity) && AllBlocks.BELT.typeOf(world.getBlockState(entity.getPosition())) -// && getAirFlowDirection() != Direction.UP) { -// return; -// } -// -// Vec3d center = VecHelper.getCenterOf(pos); -// Vec3i flow = getAirFlowDirection().getDirectionVec(); -// -// float sneakModifier = entity.isSneaking() ? 4096f : 512f; -// float acceleration = (float) (getSpeed() * 1 / sneakModifier -// / (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance))); -// Vec3d previousMotion = entity.getMotion(); -// float maxAcceleration = 5; -// -// double xIn = MathHelper.clamp(flow.getX() * acceleration - previousMotion.x, -maxAcceleration, maxAcceleration); -// double yIn = MathHelper.clamp(flow.getY() * acceleration - previousMotion.y, -maxAcceleration, maxAcceleration); -// double zIn = MathHelper.clamp(flow.getZ() * acceleration - previousMotion.z, -maxAcceleration, maxAcceleration); -// -// entity.setMotion( -// previousMotion.add(new Vec3d(xIn, yIn, zIn).mul(flow.getX(), flow.getY(), flow.getZ()).scale(1 / 8f))); -// entity.fallDistance = 0; -// } - } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleBlock.java new file mode 100644 index 000000000..2e5e91fa3 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleBlock.java @@ -0,0 +1,72 @@ +package com.simibubi.create.modules.contraptions.components.fan; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.block.ProperDirectionalBlock; +import com.simibubi.create.foundation.utility.AllShapes; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; + +public class NozzleBlock extends ProperDirectionalBlock { + + public NozzleBlock() { + super(Properties.from(AllBlocks.ENCASED_FAN.get())); + } + + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new NozzleTileEntity(); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + return getDefaultState().with(FACING, context.getFace()); + } + + @Override + public BlockRenderLayer getRenderLayer() { + return BlockRenderLayer.CUTOUT_MIPPED; + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + return AllShapes.NOZZLE.get(state.get(FACING)); + } + + @Override + public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + if (worldIn.isRemote) + return; + + if (fromPos.equals(pos.offset(state.get(FACING).getOpposite()))) + if (!isValidPosition(state, worldIn, pos)) { + worldIn.destroyBlock(pos, true); + return; + } + } + + @Override + public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) { + Direction towardsFan = state.get(FACING).getOpposite(); + BlockState fanState = worldIn.getBlockState(pos.offset(towardsFan)); + return AllBlocks.ENCASED_FAN.typeOf(fanState) + && fanState.get(EncasedFanBlock.FACING) == towardsFan.getOpposite(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleTileEntity.java new file mode 100644 index 000000000..ec1847e29 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/NozzleTileEntity.java @@ -0,0 +1,171 @@ +package com.simibubi.create.modules.contraptions.components.fan; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.CreateConfig; +import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; +import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +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.Explosion.Mode; + +public class NozzleTileEntity extends SmartTileEntity { + + private List pushingEntities = new ArrayList<>(); + private float range; + private boolean pushing; + private BlockPos fanPos; + + public NozzleTileEntity() { + super(AllTileEntities.NOZZLE.type); + setLazyTickRate(5); + } + + @Override + public void addBehaviours(List behaviours) { + } + + @Override + public CompoundNBT writeToClient(CompoundNBT compound) { + compound.putFloat("Range", range); + compound.putBoolean("Pushing", pushing); + return super.writeToClient(compound); + } + + @Override + public void readClientUpdate(CompoundNBT tag) { + range = tag.getFloat("Range"); + pushing = tag.getBoolean("Pushing"); + super.readClientUpdate(tag); + } + + @Override + public void initialize() { + super.initialize(); + fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING).getOpposite()); + lazyTick(); + } + + @Override + public void tick() { + super.tick(); + + float range = calcRange(); + if (this.range != range) + setRange(range); + + Vec3d center = VecHelper.getCenterOf(pos); + if (world.isRemote && range != 0) { + if (world.rand.nextInt(MathHelper.clamp((CreateConfig.parameters.fanPushDistance.get() - (int) range), 1, 10)) == 0) { + Vec3d start = VecHelper.offsetRandomly(center, world.rand, pushing ? 1 : range / 2); + Vec3d motion = center.subtract(start).normalize().scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1)); + world.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z); + } + } + + for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { + Entity entity = iterator.next(); + Vec3d diff = entity.getPositionVec().subtract(center); + + if (!(entity instanceof PlayerEntity) && world.isRemote) + continue; + + double distance = diff.length(); + if (distance > range || entity.isSneaking() + || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { + iterator.remove(); + continue; + } + + if (!pushing && distance < 1.5f) + continue; + + float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f; + Vec3d pushVec = diff.normalize().scale((range - distance) * (pushing ? 1 : -1)); + entity.setMotion(entity.getMotion().add(pushVec.scale(factor))); + entity.fallDistance = 0; + entity.velocityChanged = true; + } + + } + + public void setRange(float range) { + this.range = range; + if (range == 0) + pushingEntities.clear(); + sendData(); + } + + private float calcRange() { + TileEntity te = world.getTileEntity(fanPos); + if (!(te instanceof EncasedFanTileEntity)) + return 0; + + EncasedFanTileEntity fan = (EncasedFanTileEntity) te; + if (fan.isGenerator) + return 0; + if (fan.airCurrent == null) + return 0; + if (fan.getSpeed() == 0) + return 0; + pushing = fan.getSpeed() > 0; + return fan.getMaxDistance(); + } + + @Override + public void lazyTick() { + super.lazyTick(); + + if (range == 0) + return; + + Vec3d center = VecHelper.getCenterOf(pos); + AxisAlignedBB bb = new AxisAlignedBB(center, center).grow(range / 2f); + + for (Entity entity : world.getEntitiesWithinAABB(Entity.class, bb)) { + Vec3d diff = entity.getPositionVec().subtract(center); + + double distance = diff.length(); + if (distance > range || entity.isSneaking() + || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { + continue; + } + + boolean canSee = canSee(entity); + if (!canSee) { + pushingEntities.remove(entity); + continue; + } + + if (!pushingEntities.contains(entity)) + pushingEntities.add(entity); + } + + if (!pushing && pushingEntities.size() > 512 && !world.isRemote) + world.createExplosion(null, center.x, center.y, center.z, 6, Mode.BREAK); + + } + + private boolean canSee(Entity entity) { + RayTraceContext context = new RayTraceContext(entity.getPositionVec(), VecHelper.getCenterOf(pos), + BlockMode.COLLIDER, FluidMode.NONE, entity); + return pos.equals(world.rayTraceBlocks(context).getPos()); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java index 7a0940aec..cf6eb288e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/particle/AirFlowParticleData.java @@ -40,13 +40,13 @@ public class AirFlowParticleData implements IParticleData, ICustomParticle