diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 1b453aa7d..b4e8735af 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -17,7 +17,6 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalP import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonHeadBlock; import com.simibubi.create.modules.contraptions.receivers.constructs.PistonPoleBlock; import com.simibubi.create.modules.contraptions.redstone.ContactBlock; -import com.simibubi.create.modules.contraptions.relays.BeltBlock; import com.simibubi.create.modules.contraptions.relays.ClutchBlock; import com.simibubi.create.modules.contraptions.relays.CogWheelBlock; import com.simibubi.create.modules.contraptions.relays.EncasedBeltBlock; @@ -26,11 +25,14 @@ import com.simibubi.create.modules.contraptions.relays.GearboxBlock; import com.simibubi.create.modules.contraptions.relays.GearshiftBlock; import com.simibubi.create.modules.contraptions.relays.ShaftBlock; import com.simibubi.create.modules.contraptions.relays.ShaftHalfBlock; +import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock; import com.simibubi.create.modules.economy.ShopShelfBlock; import com.simibubi.create.modules.gardens.CocoaLogBlock; +import com.simibubi.create.modules.logistics.block.BeltFunnelBlock; import com.simibubi.create.modules.logistics.block.ExtractorBlock; import com.simibubi.create.modules.logistics.block.FlexcrateBlock; import com.simibubi.create.modules.logistics.block.LinkedExtractorBlock; +import com.simibubi.create.modules.logistics.block.PulseRepeaterBlock; import com.simibubi.create.modules.logistics.block.RedstoneBridgeBlock; import com.simibubi.create.modules.logistics.block.StockswitchBlock; import com.simibubi.create.modules.schematics.block.CreativeCrateBlock; @@ -98,11 +100,13 @@ public enum AllBlocks { CONTACT(new ContactBlock()), // Logistics + PULSE_REPEATER(new PulseRepeaterBlock()), REDSTONE_BRIDGE(new RedstoneBridgeBlock()), STOCKSWITCH(new StockswitchBlock()), FLEXCRATE(new FlexcrateBlock()), EXTRACTOR(new ExtractorBlock()), LINKED_EXTRACTOR(new LinkedExtractorBlock()), + BELT_FUNNEL(new BeltFunnelBlock()), // Symmetry SYMMETRY_PLANE(new PlaneSymmetryBlock()), diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 8c5ec7cc1..de2f8a85d 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -1,6 +1,6 @@ package com.simibubi.create; -import com.simibubi.create.modules.contraptions.relays.BeltItem; +import com.simibubi.create.modules.contraptions.relays.belt.BeltItem; import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunItem; import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunItemRenderer; import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunModel; diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 4ca05afc8..c7c93feae 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -14,17 +14,18 @@ import com.simibubi.create.modules.contraptions.receivers.EncasedFanTileEntityRe import com.simibubi.create.modules.contraptions.receivers.TurntableTileEntity; import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonTileEntity; import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonTileEntityRenderer; -import com.simibubi.create.modules.contraptions.relays.ShaftTileEntity; +import com.simibubi.create.modules.contraptions.relays.ClutchTileEntity; import com.simibubi.create.modules.contraptions.relays.EncasedShaftTileEntity; import com.simibubi.create.modules.contraptions.relays.EncasedShaftTileEntityRenderer; -import com.simibubi.create.modules.contraptions.relays.BeltTileEntity; -import com.simibubi.create.modules.contraptions.relays.BeltTileEntityRenderer; -import com.simibubi.create.modules.contraptions.relays.ClutchTileEntity; import com.simibubi.create.modules.contraptions.relays.GearboxTileEntity; import com.simibubi.create.modules.contraptions.relays.GearboxTileEntityRenderer; import com.simibubi.create.modules.contraptions.relays.GearshiftTileEntity; +import com.simibubi.create.modules.contraptions.relays.ShaftTileEntity; import com.simibubi.create.modules.contraptions.relays.SplitShaftTileEntityRenderer; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntityRenderer; import com.simibubi.create.modules.economy.ShopShelfTileEntity; +import com.simibubi.create.modules.logistics.block.BeltFunnelTileEntity; import com.simibubi.create.modules.logistics.block.ExtractorTileEntity; import com.simibubi.create.modules.logistics.block.FlexcrateTileEntity; import com.simibubi.create.modules.logistics.block.LinkedExtractorTileEntity; @@ -73,8 +74,10 @@ public enum AllTileEntities { // Logistics REDSTONE_BRIDGE(RedstoneBridgeTileEntity::new, AllBlocks.REDSTONE_BRIDGE), STOCKSWITCH(StockswitchTileEntity::new, AllBlocks.STOCKSWITCH), - FLEXCRATE(FlexcrateTileEntity::new, AllBlocks.FLEXCRATE), EXTRACTOR(ExtractorTileEntity::new, AllBlocks.EXTRACTOR), + FLEXCRATE(FlexcrateTileEntity::new, AllBlocks.FLEXCRATE), + EXTRACTOR(ExtractorTileEntity::new, AllBlocks.EXTRACTOR), LINKED_EXTRACTOR(LinkedExtractorTileEntity::new, AllBlocks.LINKED_EXTRACTOR), + BELT_FUNNEL(BeltFunnelTileEntity::new, AllBlocks.BELT_FUNNEL), // Economy SHOP_SHELF(ShopShelfTileEntity::new, AllBlocks.SHOP_SHELF), diff --git a/src/main/java/com/simibubi/create/foundation/block/IWithTileEntity.java b/src/main/java/com/simibubi/create/foundation/block/IWithTileEntity.java new file mode 100644 index 000000000..317644539 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/block/IWithTileEntity.java @@ -0,0 +1,19 @@ +package com.simibubi.create.foundation.block; + +import java.util.function.Consumer; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; + +public interface IWithTileEntity { + + default void withTileEntityDo(IWorld world, BlockPos pos, Consumer action) { + @SuppressWarnings("unchecked") + T te = (T) world.getTileEntity(pos); + if (te == null) + return; + action.accept(te); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java b/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java index 8620ecc33..844dd0ebd 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java @@ -6,10 +6,10 @@ import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.modules.contraptions.base.IRotate; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -import com.simibubi.create.modules.contraptions.relays.BeltTileEntity; import com.simibubi.create.modules.contraptions.relays.EncasedBeltBlock; import com.simibubi.create.modules.contraptions.relays.GearboxTileEntity; import com.simibubi.create.modules.contraptions.relays.SplitShaftTileEntity; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import net.minecraft.block.BlockState; import net.minecraft.state.IProperty; @@ -66,6 +66,12 @@ public class RotationPropagator { && stateTo.get(EncasedBeltBlock.CONNECTED_FACE) == direction.getOpposite(); return connected ? 1 : 0; } + + // Attached Fans + if (AllBlocks.ENCASED_FAN.typeOf(stateFrom) && AllBlocks.ENCASED_FAN.typeOf(stateTo)) { + if (stateFrom.get(BlockStateProperties.AXIS) == stateTo.get(BlockStateProperties.AXIS)) + return 1; + } // Gear <-> Large Gear if (isLargeToSmallGear(stateFrom, stateTo, diff)) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java index 9a8f6c76a..042fed0fa 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java @@ -34,13 +34,6 @@ public abstract class KineticTileEntity extends SyncedTileEntity { public void onSpeedChanged() { } - @Override - public void onLoad() { - if (!hasWorld()) - return; - super.onLoad(); - } - @Override public void remove() { if (world.isRemote) { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java index 07437a2b2..bad72d061 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java @@ -47,12 +47,6 @@ public class WaterWheelTileEntity extends KineticTileEntity { flows.put(direction, speed); } - @Override - public void onLoad() { - super.onLoad(); -// updateSpeed(); - } - public void updateSpeed() { float speed = 0; for (Integer i : flows.values()) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java index 8b715e2fa..619dff525 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanBlock.java @@ -1,29 +1,70 @@ package com.simibubi.create.modules.contraptions.receivers; +import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.utility.ItemDescription; import com.simibubi.create.modules.contraptions.relays.EncasedShaftBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Direction.AxisDirection; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; -public class EncasedFanBlock extends EncasedShaftBlock { +public class EncasedFanBlock extends EncasedShaftBlock implements IWithTileEntity { @Override public ItemDescription getDescription() { - return new ItemDescription(color) - .withSummary("Exchange rotational power for air flow and back.").createTabs(); + return new ItemDescription(color).withSummary("Exchange rotational power for air flow and back.").createTabs(); } - + @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new EncasedFanTileEntity(); } - + + @Override + public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + Axis axisIn = state.get(AXIS); + notifyFanTile(worldIn, pos, Direction.getFacingFromAxisDirection(axisIn, AxisDirection.POSITIVE)); + notifyFanTile(worldIn, pos, Direction.getFacingFromAxisDirection(axisIn, AxisDirection.NEGATIVE)); + } + + @Override + public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, + boolean isMoving) { + Axis axisIn = state.get(AXIS); + notifyFanTile(worldIn, pos, Direction.getFacingFromAxisDirection(axisIn, AxisDirection.POSITIVE)); + notifyFanTile(worldIn, pos, Direction.getFacingFromAxisDirection(axisIn, AxisDirection.NEGATIVE)); + } + + @Override + public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn, + BlockPos currentPos, BlockPos facingPos) { + if (facing.getAxis() == stateIn.get(AXIS)) + notifyFanTile(worldIn, currentPos, facing); + return stateIn; + } + + protected void notifyFanTile(IWorld world, BlockPos pos, Direction facing) { + withTileEntityDo(world, pos, te -> te.setNeighbour(facing, world.getBlockState(pos.offset(facing)))); + } + @Override public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT; } - + + public static boolean canAirPassThrough(World world, BlockPos pos, Direction direction) { + if (!world.isBlockPresent(pos)) + return true; + BlockState state = world.getBlockState(pos); + return !Block.hasSolidSide(state, world, pos, direction.getOpposite()); + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java index 464f943ef..49f5673e6 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java @@ -1,12 +1,400 @@ package com.simibubi.create.modules.contraptions.receivers; +import static net.minecraft.state.properties.BlockStateProperties.AXIS; +import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; +import static net.minecraft.util.Direction.AxisDirection.POSITIVE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -public class EncasedFanTileEntity extends KineticTileEntity { +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.IParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.particles.RedstoneParticleData; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; + +public class EncasedFanTileEntity extends KineticTileEntity implements ITickableTileEntity { + + public static final int PUSH_DISTANCE_MAX = 20; + public static final int PULL_DISTANCE_MAX = 5; + public static final int DISTANCE_ARGMAX = 6400; + + public static final float PUSH_FORCE_MAX = 20; + public static final float PULL_FORCE_MAX = 10; + public static final int FORCE_ARGMAX = 6400; + + public static final int BLOCK_CHECK_UPDATE_DELAY = 100; + public static final Map> effects = new HashMap<>(); + + private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled() + .setFireDamage(); + private static DamageSource damageSourceLava = new DamageSource("create.fan_lava").setDifficultyScaled() + .setFireDamage(); + + protected BlockState frontBlock; + protected BlockState backBlock; + protected float pushDistance; + protected float pullDistance; + protected float pushForce; + protected float pullForce; + protected AxisAlignedBB frontBB; + protected AxisAlignedBB backBB; + protected int blockCheckCooldown; + protected boolean findLoadedItems; + public List items; + + public class ProcessedItem { + private UUID loadedUUID; + private ItemEntity entity; + private int processingTimeLeft; + + public ProcessedItem(UUID uuid, int timeLeft) { + loadedUUID = uuid; + processingTimeLeft = timeLeft; + } + + public ProcessedItem(ItemEntity item) { + entity = item; + } + + } + + protected static class FanEffect { + private IParticleData particle; + private float density; + private float chance; + private float spread; + private float speed; + private Random r; + + public FanEffect(IParticleData particle, float density, float chance, float spread, float speed) { + r = new Random(); + this.particle = particle; + this.density = density; + this.chance = chance; + this.spread = spread; + this.speed = speed; + } + + public void render(Vec3i directionVec, boolean front, EncasedFanTileEntity te) { + render(directionVec, front ? .5f : -te.pullDistance, front ? te.pushDistance : -.5f, te); + } + + private void render(Vec3i directionVec, float start, float end, EncasedFanTileEntity te) { + float x = directionVec.getX(); + float y = directionVec.getY(); + float z = directionVec.getZ(); + float speed = this.speed * Math.abs(te.speed) / 512f; + + for (float offset = start; offset < end; offset += density) { + if (r.nextFloat() > chance) + continue; + float xs = rollOffset() * spread; + float ys = rollOffset() * spread; + float zs = rollOffset() * spread; + float xs2 = rollOffset() * spread; + float ys2 = rollOffset() * spread; + float zs2 = rollOffset() * spread; + te.world.addParticle(particle, te.pos.getX() + .5f + x * offset + xs2, + te.pos.getY() + .5f + y * offset + ys2, te.pos.getZ() + .5f + z * offset + zs2, x * speed + xs, + y * speed + ys, z * speed + zs); + } + } + + private float rollOffset() { + return (r.nextFloat() - .5f) * 2; + } + } public EncasedFanTileEntity() { super(AllTileEntities.ENCASED_FAN.type); + blockCheckCooldown = BLOCK_CHECK_UPDATE_DELAY; + frontBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + backBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + items = new ArrayList<>(); + if (effects.isEmpty()) + initEffects(); + } + + private static void initEffects() { + effects.clear(); + + List standardFX = new ArrayList<>(2); + standardFX.add(new FanEffect(ParticleTypes.BUBBLE_POP, 1 / 4f, 1 / 8f, 1 / 8f, 1)); + standardFX.add(new FanEffect(new RedstoneParticleData(1, 1, 1, 1), 1 / 2f, 1 / 32f, 0f, 512f)); + effects.put(Blocks.AIR, standardFX); + + List waterFX = new ArrayList<>(2); + waterFX.add(new FanEffect(new BlockParticleData(ParticleTypes.BLOCK, Blocks.WATER.getDefaultState()), 1 / 4f, + 1 / 2f, 1 / 4f, 1)); + waterFX.add(new FanEffect(ParticleTypes.SPLASH, 1 / 4f, 1 / 2f, 0.5f, 1)); + effects.put(Blocks.WATER, waterFX); + + List fireFX = new ArrayList<>(2); + fireFX.add(new FanEffect(ParticleTypes.LARGE_SMOKE, 1 / 4f, 1 / 8f, 0.125f, .5f)); + fireFX.add(new FanEffect(ParticleTypes.FLAME, 1 / 4f, 1 / 8f, 1 / 32f, 1 / 256f)); + effects.put(Blocks.FIRE, fireFX); + + List lavaFX = new ArrayList<>(3); + lavaFX.add(new FanEffect(new BlockParticleData(ParticleTypes.BLOCK, Blocks.LAVA.getDefaultState()), 1 / 4f, + 1 / 2f, 1 / 4f, 1)); + lavaFX.add(new FanEffect(ParticleTypes.LAVA, 1 / 2f, 1 / 32f, 0, .25f)); + lavaFX.add(new FanEffect(ParticleTypes.FLAME, 1 / 4f, 1 / 32f, 1 / 32f, 1 / 256f)); + effects.put(Blocks.LAVA, lavaFX); + } + + @Override + public void readClientUpdate(CompoundNBT tag) { + super.readClientUpdate(tag); + pushDistance = tag.getFloat("PushDistance"); + pullDistance = tag.getFloat("PullDistance"); + pushForce = tag.getFloat("PushForce"); + pullForce = tag.getFloat("PullForce"); + updateBothNeighbours(); + updateBBs(); + } + + @Override + public CompoundNBT writeToClient(CompoundNBT tag) { + super.writeToClient(tag); + tag.putFloat("PushDistance", pushDistance); + tag.putFloat("PullDistance", pullDistance); + tag.putFloat("PushForce", pushForce); + tag.putFloat("PullForce", pullForce); + return tag; + } + + @Override + public void onLoad() { + blockCheckCooldown = 0; + } + + @Override + public void read(CompoundNBT compound) { + super.read(compound); + ListNBT itemsNBT = compound.getList("Items", 10); + items.clear(); + for (INBT iNBT : itemsNBT) { + CompoundNBT itemNBT = (CompoundNBT) iNBT; + items.add(new ProcessedItem(NBTUtil.readUniqueId(itemNBT.getCompound("UUID")), itemNBT.getInt("TimeLeft"))); + } + findLoadedItems = true; + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + ListNBT itemsNBT = new ListNBT(); + for (ProcessedItem item : items) { + CompoundNBT itemNBT = new CompoundNBT(); + itemNBT.put("UUID", NBTUtil.writeUniqueId(item.entity.getUniqueID())); + itemNBT.putInt("TimeLeft", item.processingTimeLeft); + itemsNBT.add(itemNBT); + } + compound.put("Items", itemsNBT); + return super.write(compound); + } + + protected void updateReachAndForce() { + if (getWorld() == null) + return; + if (world.isRemote) + return; + + float speed = Math.abs(this.speed); + float distanceFactor = Math.min(speed / DISTANCE_ARGMAX, 1); + float forceFactor = Math.min(speed / FORCE_ARGMAX, 1); + + pushDistance = MathHelper.lerp(distanceFactor, 3, PUSH_DISTANCE_MAX); + pullDistance = MathHelper.lerp(distanceFactor, 1.5f, PULL_DISTANCE_MAX); + pushForce = MathHelper.lerp(forceFactor, 1, PUSH_FORCE_MAX); + pullForce = MathHelper.lerp(forceFactor, 1, PULL_FORCE_MAX); + + Direction direction = getAirFlow(); + if (speed != 0) { + for (int distance = 1; distance <= pushDistance; distance++) { + if (!EncasedFanBlock.canAirPassThrough(world, getPos().offset(direction, distance), direction)) { + pushDistance = distance - 1; + break; + } + } + for (int distance = 1; distance <= pullDistance; distance++) { + if (!EncasedFanBlock.canAirPassThrough(world, getPos().offset(direction, -distance), direction)) { + pullDistance = distance - 1; + break; + } + } + updateBBs(); + } else { + frontBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + backBB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + } + + sendData(); + } + + protected void updateBBs() { + Direction flow = getAirFlow(); + if (flow == null) + return; + Vec3i flowVec = flow.getDirectionVec(); + float remainder = pushDistance - (int) pushDistance; + frontBB = new AxisAlignedBB(pos.offset(flow), pos.offset(flow, (int) pushDistance)) + .expand(flowVec.getX() * remainder + 1, flowVec.getY() * remainder + 1, flowVec.getZ() * remainder + 1) + .grow(.25f); + remainder = pullDistance - (int) pullDistance; + backBB = new AxisAlignedBB(pos.offset(flow, -(int) pullDistance), pos.offset(flow, -1)) + .expand(-flowVec.getX() * remainder + 1, -flowVec.getY() * remainder + 1, + -flowVec.getZ() * remainder + 1) + .grow(.25f); + } + + public void updateBothNeighbours() { + Axis axis = getBlockState().get(AXIS); + Direction frontFacing = Direction.getFacingFromAxis(POSITIVE, axis); + Direction backFacing = Direction.getFacingFromAxis(NEGATIVE, axis); + BlockPos front = pos.offset(frontFacing); + BlockPos back = pos.offset(backFacing); + if (world.isBlockPresent(front)) + setNeighbour(frontFacing, world.getBlockState(front)); + if (world.isBlockPresent(back)) + setNeighbour(backFacing, world.getBlockState(back)); + } + + public void setNeighbour(Direction direction, BlockState neighbourState) { + if (direction.getAxisDirection() == NEGATIVE) + backBlock = neighbourState; + else + frontBlock = neighbourState; + updateReachAndForce(); + } + + public Direction getAirFlow() { + if (speed == 0) + return null; + return Direction.getFacingFromAxisDirection(getBlockState().get(AXIS), speed > 0 ? POSITIVE : NEGATIVE); + } + + @Override + public void onSpeedChanged() { + updateReachAndForce(); + } + + @Override + public void tick() { + if (speed == 0) + return; + + List frontEntities = world.getEntitiesWithinAABBExcludingEntity(null, frontBB); + for (Entity entity : frontEntities) { + moveEntity(entity, true); + if (!(entity instanceof ItemEntity)) { + if (frontBlock != null && frontBlock.getBlock() == Blocks.FIRE) { + entity.setFire(2); + entity.attackEntityFrom(damageSourceFire, 4); + } + if (frontBlock != null && frontBlock.getBlock() == Blocks.LAVA) { + entity.setFire(10); + entity.attackEntityFrom(damageSourceLava, 8); + } + } + } + for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, backBB)) { + moveEntity(entity, false); + } + + if (world.isRemote) { + makeParticles(); + return; + } + + if (blockCheckCooldown-- <= 0) { + blockCheckCooldown = BLOCK_CHECK_UPDATE_DELAY; + updateReachAndForce(); + } + + if (findLoadedItems) { + findLoadedItems = false; + for (ProcessedItem item : items) { + for (Entity entity : frontEntities) { + if (!(entity instanceof ItemEntity)) + continue; + if (entity.getUniqueID().equals(item.loadedUUID)) + item.entity = (ItemEntity) entity; + } + } + } + } + + protected void moveEntity(Entity entity, boolean push) { + if ((entity instanceof ItemEntity) && AllBlocks.BELT.typeOf(world.getBlockState(entity.getPosition()))) { + return; + } + + Vec3d center = VecHelper.getCenterOf(pos); + Vec3i flow = getAirFlow().getDirectionVec(); + float modifier = entity.isSneaking() ? 4096f : 512f; + float s = (float) (speed * 1 / modifier + / (entity.getPositionVec().distanceTo(center) / (push ? pushDistance : pullDistance))); + Vec3d motion = entity.getMotion(); + double xIn = flow.getX() * s - motion.x; + double yIn = flow.getY() * s - motion.y; + double zIn = flow.getZ() * s - motion.z; + entity.setMotion(motion.add(new Vec3d(xIn, yIn, zIn).mul(flow.getX(), flow.getY(), flow.getZ()).scale(1 / 8f))); + entity.fallDistance = 0; + } + + protected void makeParticles() { + Direction direction = getAirFlow(); + Vec3i directionVec = direction.getDirectionVec(); + + boolean hasFx = false; + if (frontBlock != null) { + if (effects.containsKey(frontBlock.getBlock())) { + hasFx = true; + for (FanEffect fx : effects.get(frontBlock.getBlock())) + fx.render(directionVec, true, this); + } + } + if (backBlock != null && !hasFx) { + if (effects.containsKey(backBlock.getBlock())) { + hasFx = true; + for (FanEffect fx : effects.get(backBlock.getBlock())) + fx.render(directionVec, true, this); + } + } + + if (!hasFx) + for (FanEffect fx : effects.get(Blocks.AIR)) + fx.render(directionVec, true, this); + + for (FanEffect fx : effects.get(Blocks.AIR)) + fx.render(directionVec, false, this); } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/AllBeltAttachments.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/AllBeltAttachments.java new file mode 100644 index 000000000..969705aca --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/AllBeltAttachments.java @@ -0,0 +1,144 @@ +package com.simibubi.create.modules.contraptions.relays.belt; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import com.simibubi.create.AllBlocks; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; + +public enum AllBeltAttachments { + + BELT_FUNNEL(AllBlocks.BELT_FUNNEL), + + ; + + IBeltAttachment attachment; + + private AllBeltAttachments(AllBlocks attachment) { + this.attachment = (IBeltAttachment) attachment.get(); + } + + public interface IBeltAttachment { + public Optional getValidAttachmentFor(BeltTileEntity te); + + public Optional getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state); + + public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state); + + default void onAttachmentPlaced(IWorld world, BlockPos pos, BlockState state) { + Optional beltPos = getValidBeltPositionFor(world, pos, state); + if (!beltPos.isPresent()) + return; + BeltTileEntity te = (BeltTileEntity) world.getTileEntity(beltPos.get()); + if (te == null) + return; + te.attachmentTracker.addAttachment(world, pos); + te.sendData(); + } + + default void onAttachmentRemoved(IWorld world, BlockPos pos, BlockState state) { + Optional beltPos = getValidBeltPositionFor(world, pos, state); + if (!beltPos.isPresent()) + return; + BeltTileEntity te = (BeltTileEntity) world.getTileEntity(beltPos.get()); + if (te == null) + return; + te.attachmentTracker.removeAttachment(pos); + te.sendData(); + } + } + + public static class BeltAttachmentState { + public IBeltAttachment attachment; + public BlockPos attachmentPos; + public int processingDuration; + public Entity processingEntity; + + public BeltAttachmentState(IBeltAttachment attachment, BlockPos attachmentPos) { + this.attachment = attachment; + this.attachmentPos = attachmentPos; + } + + } + + public static class Tracker { + public List attachments; + + public Tracker() { + attachments = new ArrayList<>(0); + } + + public void findAttachments(BeltTileEntity belt) { + for (AllBeltAttachments ba : AllBeltAttachments.values()) { + Optional validAttachmentFor = ba.attachment.getValidAttachmentFor(belt); + if (validAttachmentFor.isPresent()) { + BlockPos pos = validAttachmentFor.get(); + addAttachment(belt.getWorld(), pos); + } + } + } + + public BeltAttachmentState addAttachment(IWorld world, BlockPos pos) { + BlockState state = world.getBlockState(pos); + removeAttachment(pos); + BeltAttachmentState newAttachmentState = new BeltAttachmentState((IBeltAttachment) state.getBlock(), pos); + attachments.add(newAttachmentState); + return newAttachmentState; + } + + public void removeAttachment(BlockPos pos) { + BeltAttachmentState toRemove = null; + for (BeltAttachmentState atState : attachments) + if (atState.attachmentPos.equals(pos)) + toRemove = atState; + if (toRemove != null) + attachments.remove(toRemove); + } + + public void forEachAttachment(Consumer consumer) { + attachments.forEach(consumer::accept); + } + + public void readAndSearch(CompoundNBT nbt, BeltTileEntity belt) { + attachments.clear(); + if (!nbt.contains("HasAttachments")) + return; + if (nbt.contains("AttachmentData")) { + ListNBT list = (ListNBT) nbt.get("AttachmentData"); + for (INBT data : list) { + CompoundNBT stateNBT = (CompoundNBT) data; + BlockPos attachmentPos = NBTUtil.readBlockPos(stateNBT.getCompound("Position")); + BeltAttachmentState atState = addAttachment(belt.getWorld(), attachmentPos); + atState.processingDuration = stateNBT.getInt("Duration"); + } + } + } + + public void write(CompoundNBT nbt) { + if (!attachments.isEmpty()) { + nbt.putBoolean("HasAttachments", true); + ListNBT list = new ListNBT(); + forEachAttachment(atState -> { + CompoundNBT stateNBT = new CompoundNBT(); + stateNBT.put("Position", NBTUtil.writeBlockPos(atState.attachmentPos)); + stateNBT.putInt("Duration", atState.processingDuration); + list.add(stateNBT); + }); + nbt.put("AttachmentData", list); + } + + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java similarity index 95% rename from src/main/java/com/simibubi/create/modules/contraptions/relays/BeltBlock.java rename to src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java index d1f5f369b..663dd0053 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java @@ -1,14 +1,15 @@ -package com.simibubi.create.modules.contraptions.relays; +package com.simibubi.create.modules.contraptions.relays.belt; import java.util.LinkedList; import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; +import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithoutBlockItem; import com.simibubi.create.foundation.utility.ItemDescription; import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock; -import com.simibubi.create.modules.contraptions.relays.BeltTileEntity.TransportedEntityInfo; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity.TransportedEntityInfo; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -36,7 +37,7 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; -public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockItem { +public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockItem, IWithTileEntity { public static final IProperty SLOPE = EnumProperty.create("slope", Slope.class); public static final IProperty PART = EnumProperty.create("part", Part.class); @@ -103,6 +104,8 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt if (controller == null) return; + if (controller.passengers == null) + return; if (controller.passengers.containsKey(entityIn)) controller.passengers.get(entityIn).refresh(belt.getPos(), belt.getBlockState()); @@ -132,6 +135,8 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt if (controller == null) return; + if (controller.passengers == null) + return; if (controller.passengers.containsKey(entityIn)) { TransportedEntityInfo transportedEntityInfo = controller.passengers.get(entityIn); @@ -141,6 +146,13 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt controller.passengers.put(entityIn, new TransportedEntityInfo(pos, state)); } + @Override + public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + withTileEntityDo(worldIn, pos, te -> { + te.attachmentTracker.findAttachments(te); + }); + } + @Override protected void fillStateContainer(Builder builder) { builder.add(SLOPE, PART); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItem.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java similarity index 96% rename from src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItem.java rename to src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java index 907eda565..81c0ee7b9 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItem.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java @@ -1,12 +1,12 @@ -package com.simibubi.create.modules.contraptions.relays; +package com.simibubi.create.modules.contraptions.relays.belt; import java.util.LinkedList; import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -import com.simibubi.create.modules.contraptions.relays.BeltBlock.Part; -import com.simibubi.create.modules.contraptions.relays.BeltBlock.Slope; +import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part; +import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope; import net.minecraft.block.BlockState; import net.minecraft.item.Item; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItemHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItemHandler.java similarity index 98% rename from src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItemHandler.java rename to src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItemHandler.java index 3969929f9..bebcc308c 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltItemHandler.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItemHandler.java @@ -1,4 +1,4 @@ -package com.simibubi.create.modules.contraptions.relays; +package com.simibubi.create.modules.contraptions.relays.belt; import java.util.LinkedList; import java.util.List; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java similarity index 79% rename from src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntity.java rename to src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java index 1d68ff762..48cb63294 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java @@ -1,4 +1,4 @@ -package com.simibubi.create.modules.contraptions.relays; +package com.simibubi.create.modules.contraptions.relays.belt; import java.util.ArrayList; import java.util.HashMap; @@ -8,8 +8,10 @@ import java.util.Map; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTileEntities; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -import com.simibubi.create.modules.contraptions.relays.BeltBlock.Part; -import com.simibubi.create.modules.contraptions.relays.BeltBlock.Slope; +import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState; +import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.Tracker; +import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part; +import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; @@ -34,6 +36,8 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn protected BlockPos controller; public Map passengers; + public AllBeltAttachments.Tracker attachmentTracker; + private CompoundNBT trackerUpdateTag; protected static class TransportedEntityInfo { int ticksSinceLastCollision; @@ -59,18 +63,37 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn public BeltTileEntity() { super(AllTileEntities.BELT.type); controller = BlockPos.ZERO; - passengers = new HashMap<>(); + attachmentTracker = new Tracker(); + } + + protected boolean isLastBelt() { + if (speed == 0) + return false; + + Direction direction = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING); + if (getBlockState().get(BeltBlock.SLOPE) == Slope.VERTICAL) + return false; + + Part part = getBlockState().get(BeltBlock.PART); + if (part == Part.MIDDLE) + return false; + + boolean movingPositively = (speed > 0 == (direction.getAxisDirection().getOffset() == 1)) + ^ direction.getAxis() == Axis.X; + return part == Part.START ^ movingPositively; } @Override public CompoundNBT write(CompoundNBT compound) { compound.put("Controller", NBTUtil.writeBlockPos(controller)); + attachmentTracker.write(compound); return super.write(compound); } @Override public void read(CompoundNBT compound) { controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); + trackerUpdateTag = compound; super.read(compound); } @@ -94,8 +117,14 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn @Override public void tick() { + if (world != null && trackerUpdateTag != null) { + attachmentTracker.readAndSearch(trackerUpdateTag, this); + trackerUpdateTag = null; + } if (!isController()) return; + if (passengers == null) + passengers = new HashMap<>(); passengers.forEach((entity, info) -> { transportEntity(entity, info); @@ -110,7 +139,11 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn } info.tick(); }); - toRemove.forEach(passengers::remove); + toRemove.forEach(e -> { + if (e instanceof ItemEntity) + ((ItemEntity) e).setAgeToCreativeDespawnTime(); + passengers.remove(e); + }); if (speed == 0) return; @@ -133,7 +166,16 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn return; } - if (((KineticTileEntity) te).getSpeed() == 0) + if (entityIn instanceof ItemEntity) { + if (speed == 0) { + ((ItemEntity) entityIn).setAgeToCreativeDespawnTime(); + } else { + if (((ItemEntity) entityIn).getAge() > 0) + ((ItemEntity) entityIn).setNoDespawn(); + } + } + + if (speed == 0) return; if (entityIn.posY - .25f < pos.getY()) @@ -143,6 +185,13 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn ((LivingEntity) entityIn).setIdleTime(101); } + BeltTileEntity belt = (BeltTileEntity) te; + + for (BeltAttachmentState state : belt.attachmentTracker.attachments) { + if (state.attachment.handleEntity(belt, entityIn, state)) + return; + } + final Direction beltFacing = blockState.get(BlockStateProperties.HORIZONTAL_FACING); final Slope slope = blockState.get(BeltBlock.SLOPE); final Axis axis = beltFacing.getAxis(); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntityRenderer.java similarity index 98% rename from src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntityRenderer.java rename to src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntityRenderer.java index f4e4d232e..a2e0aa4fd 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/BeltTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntityRenderer.java @@ -1,4 +1,4 @@ -package com.simibubi.create.modules.contraptions.relays; +package com.simibubi.create.modules.contraptions.relays.belt; import java.nio.ByteBuffer; diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelBlock.java b/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelBlock.java new file mode 100644 index 000000000..320660dfc --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelBlock.java @@ -0,0 +1,150 @@ +package com.simibubi.create.modules.logistics.block; + +import java.util.Optional; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.block.IWithTileEntity; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState; +import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment; +import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.HorizontalBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; + +public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment, IWithTileEntity { + + public static final VoxelShape SHAPE_NORTH = makeCuboidShape(4, 2, -1, 12, 10, 5), + SHAPE_SOUTH = makeCuboidShape(4, 2, 11, 12, 10, 17), SHAPE_WEST = makeCuboidShape(-1, 2, 4, 5, 10, 12), + SHAPE_EAST = makeCuboidShape(11, 2, 4, 17, 10, 12); + + public BeltFunnelBlock() { + super(Properties.from(Blocks.ANDESITE)); + } + + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new BeltFunnelTileEntity(); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(HORIZONTAL_FACING); + super.fillStateContainer(builder); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + BlockState state = getDefaultState(); + + if (context.getFace().getAxis().isHorizontal()) { + state = state.with(HORIZONTAL_FACING, context.getFace().getOpposite()); + } else { + state = state.with(HORIZONTAL_FACING, context.getPlacementHorizontalFacing()); + } + + return state; + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + Direction facing = state.get(HORIZONTAL_FACING); + + if (facing == Direction.EAST) + return SHAPE_EAST; + if (facing == Direction.WEST) + return SHAPE_WEST; + if (facing == Direction.SOUTH) + return SHAPE_SOUTH; + if (facing == Direction.NORTH) + return SHAPE_NORTH; + + return VoxelShapes.empty(); + } + + @Override + public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + onAttachmentPlaced(worldIn, pos, state); + updateObservedInventory(state, worldIn, pos); + } + + @Override + public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) { + if (!neighbor.equals(pos.offset(state.get(HORIZONTAL_FACING)))) + return; + updateObservedInventory(state, world, pos); + } + + private void updateObservedInventory(BlockState state, IWorldReader world, BlockPos pos) { + IInventoryManipulator te = (IInventoryManipulator) world.getTileEntity(pos); + if (te == null) + return; + te.neighborChanged(); + } + + @Override + public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + onAttachmentRemoved(worldIn, pos, state); + if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { + worldIn.removeTileEntity(pos); + } + } + + @Override + public Optional getValidAttachmentFor(BeltTileEntity te) { + BlockPos validPos = te.getPos().up(); + BlockState blockState = te.getWorld().getBlockState(validPos); + if (blockState.getBlock() != this + || blockState.get(HORIZONTAL_FACING).getAxis() != te.getBlockState().get(HORIZONTAL_FACING).getAxis()) + return Optional.empty(); + return Optional.of(validPos); + } + + @Override + public Optional getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state) { + BlockPos validPos = pos.down(); + BlockState blockState = world.getBlockState(validPos); + if (!AllBlocks.BELT.typeOf(blockState) + || blockState.get(HORIZONTAL_FACING).getAxis() != state.get(HORIZONTAL_FACING).getAxis()) + return Optional.empty(); + return Optional.of(validPos); + } + + @Override + public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) { + if (!(entity instanceof ItemEntity)) + return false; + if (entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos())) > .4f) + return false; + + entity.setMotion(Vec3d.ZERO); + withTileEntityDo(te.getWorld(), state.attachmentPos, funnelTE -> { + funnelTE.tryToInsert((ItemEntity) entity); + }); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelTileEntity.java b/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelTileEntity.java new file mode 100644 index 000000000..3d597e5c4 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/block/BeltFunnelTileEntity.java @@ -0,0 +1,115 @@ +package com.simibubi.create.modules.logistics.block; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.foundation.block.SyncedTileEntity; + +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ItemParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3i; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; + +public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableTileEntity, IInventoryManipulator { + + private LazyOptional inventory; + protected boolean waitingForInventorySpace; + private boolean initialize; + + public BeltFunnelTileEntity() { + super(AllTileEntities.BELT_FUNNEL.type); + inventory = LazyOptional.empty(); + } + + @Override + public void read(CompoundNBT compound) { + waitingForInventorySpace = compound.getBoolean("Waiting"); + super.read(compound); + } + + @Override + public void onLoad() { + initialize = true; + } + + @Override + public void readClientUpdate(CompoundNBT tag) { + super.readClientUpdate(tag); + if (!waitingForInventorySpace) + neighborChanged(); + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + compound.putBoolean("Waiting", waitingForInventorySpace); + return super.write(compound); + } + + @Override + public BlockPos getInventoryPos() { + return pos.offset(getBlockState().get(BlockStateProperties.HORIZONTAL_FACING)); + } + + @Override + public LazyOptional getInventory() { + return inventory; + } + + @Override + public void tick() { + if (initialize && hasWorld()) { + neighborChanged(); + initialize = false; + } + } + + @Override + public void setInventory(LazyOptional inventory) { + this.inventory = inventory; + } + + @Override + public void neighborChanged() { + IInventoryManipulator.super.neighborChanged(); + waitingForInventorySpace = false; + if (!world.isRemote) + sendData(); + } + + public void tryToInsert(ItemEntity entity) { + if (!inventory.isPresent()) + return; + if (waitingForInventorySpace) + return; + + ItemStack stack = entity.getItem().copy(); + IItemHandler inv = inventory.orElse(null); + for (int slot = 0; slot < inv.getSlots(); slot++) { + stack = inv.insertItem(slot, stack, world.isRemote); + if (stack.isEmpty()) { + if (!world.isRemote) + entity.remove(); + else { + Vec3i directionVec = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING).getDirectionVec(); + float xSpeed = directionVec.getX() * 1/8f; + float zSpeed = directionVec.getZ() * 1/8f; + world.addParticle(new ItemParticleData(ParticleTypes.ITEM, entity.getItem()), entity.posX, entity.posY, entity.posZ, xSpeed, 1/6f, zSpeed); + } + return; + } + } + + waitingForInventorySpace = true; + sendData(); + + if (!stack.equals(entity.getItem(), false)) + entity.setItem(stack); + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/ExtractorTileEntity.java b/src/main/java/com/simibubi/create/modules/logistics/block/ExtractorTileEntity.java index 6b71925cb..87fb62cb8 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/ExtractorTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/ExtractorTileEntity.java @@ -14,10 +14,11 @@ public class ExtractorTileEntity extends SyncedTileEntity implements IExtractor, private State state; private int cooldown; private LazyOptional inventory; + private boolean initialize; public ExtractorTileEntity() { super(AllTileEntities.EXTRACTOR.type); - state = State.WAITING_FOR_ITEM; + state = State.WAITING_FOR_INVENTORY; inventory = LazyOptional.empty(); } @@ -26,6 +27,20 @@ public class ExtractorTileEntity extends SyncedTileEntity implements IExtractor, return state; } + @Override + public void onLoad() { + initialize = true; + } + + @Override + public void tick() { + if (initialize && hasWorld()) { + neighborChanged(); + initialize = false; + } + IExtractor.super.tick(); + } + @Override public void setState(State state) { if (state == State.ON_COOLDOWN) diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/IExtractor.java b/src/main/java/com/simibubi/create/modules/logistics/block/IExtractor.java index 4054e1986..508031616 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/IExtractor.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/IExtractor.java @@ -2,27 +2,22 @@ package com.simibubi.create.modules.logistics.block; import com.simibubi.create.foundation.utility.VecHelper; -import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.ITickableTileEntity; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; // Its like delegation but better! -public interface IExtractor extends ITickableTileEntity { +public interface IExtractor extends ITickableTileEntity, IInventoryManipulator { public static final int EXTRACTOR_COOLDOWN = 20; public static final int EXTRACTION_COUNT = 16; public enum State { - WAITING_FOR_ITEM, WAITING_FOR_SPACE, RUNNING, ON_COOLDOWN, LOCKED; + WAITING_FOR_INVENTORY, WAITING_FOR_ENTITY, RUNNING, ON_COOLDOWN, LOCKED; } public State getState(); @@ -31,16 +26,6 @@ public interface IExtractor extends ITickableTileEntity { public int tickCooldown(); - public World getWorld(); - - public BlockPos getPos(); - - public BlockPos getInventoryPos(); - - public LazyOptional getInventory(); - - public void setInventory(LazyOptional inventory); - @Override default void tick() { State state = getState(); @@ -62,18 +47,18 @@ public interface IExtractor extends ITickableTileEntity { if (hasSpace && hasInventory) toExtract = extract(true); - if (state == State.WAITING_FOR_SPACE) { + if (state == State.WAITING_FOR_ENTITY) { if (hasSpace) setState(State.RUNNING); } if (state == State.RUNNING) { if (!hasSpace) { - setState(State.WAITING_FOR_SPACE); + setState(State.WAITING_FOR_ENTITY); return; } if (!hasInventory || toExtract.isEmpty()) { - setState(State.WAITING_FOR_ITEM); + setState(State.WAITING_FOR_INVENTORY); return; } @@ -88,7 +73,7 @@ public interface IExtractor extends ITickableTileEntity { public default void setLocked(boolean locked) { setState(locked ? State.LOCKED : State.ON_COOLDOWN); } - + public default void neighborChanged() { boolean hasSpace = hasSpaceForExtracting(); boolean hasInventory = getInventory().isPresent(); @@ -96,8 +81,8 @@ public interface IExtractor extends ITickableTileEntity { if (hasSpace && hasInventory) toExtract = extract(true); - - if (getState() == State.WAITING_FOR_ITEM) { + + if (getState() == State.WAITING_FOR_INVENTORY) { if (!hasInventory) { if (findNewInventory()) { setState(State.RUNNING); @@ -123,48 +108,27 @@ public interface IExtractor extends ITickableTileEntity { compare.setCount(extracting.getCount()); if (!extracting.isEmpty() && !extracting.equals(compare, false)) continue; - + if (extracting.isEmpty()) extracting = stack.copy(); else extracting.grow(stack.getCount()); - + if (!simulate) inv.extractItem(slot, stack.getCount(), false); if (extracting.getCount() >= EXTRACTION_COUNT) break; } - + if (!simulate) { World world = getWorld(); Vec3d pos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0); ItemEntity entityIn = new ItemEntity(world, pos.x, pos.y, pos.z, extracting); - entityIn.setMotion(Vec3d.ZERO); + entityIn.setMotion(Vec3d.ZERO); world.addEntity(entityIn); } return extracting; } - default boolean findNewInventory() { - BlockPos invPos = getInventoryPos(); - World world = getWorld(); - - if (!world.isBlockPresent(invPos)) - return false; - BlockState invState = world.getBlockState(invPos); - - if (!invState.hasTileEntity()) - return false; - TileEntity invTE = world.getTileEntity(invPos); - - LazyOptional inventory = invTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - setInventory(inventory); - if (inventory.isPresent()) { - return true; - } - - return false; - } - } diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/IInventoryManipulator.java b/src/main/java/com/simibubi/create/modules/logistics/block/IInventoryManipulator.java new file mode 100644 index 000000000..944d95f0a --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/block/IInventoryManipulator.java @@ -0,0 +1,51 @@ +package com.simibubi.create.modules.logistics.block; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; + +public interface IInventoryManipulator { + + public World getWorld(); + + public BlockPos getPos(); + + public BlockPos getInventoryPos(); + + public LazyOptional getInventory(); + + public void setInventory(LazyOptional inventory); + + default boolean findNewInventory() { + BlockPos invPos = getInventoryPos(); + World world = getWorld(); + + if (!world.isBlockPresent(invPos)) + return false; + BlockState invState = world.getBlockState(invPos); + + if (!invState.hasTileEntity()) + return false; + TileEntity invTE = world.getTileEntity(invPos); + + LazyOptional inventory = invTE.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + setInventory(inventory); + if (inventory.isPresent()) { + return true; + } + + return false; + } + + public default void neighborChanged() { + boolean hasInventory = getInventory().isPresent(); + if (!hasInventory) { + findNewInventory(); + } + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/LinkedExtractorTileEntity.java b/src/main/java/com/simibubi/create/modules/logistics/block/LinkedExtractorTileEntity.java index 98845da65..7945b0029 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/LinkedExtractorTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/LinkedExtractorTileEntity.java @@ -22,7 +22,7 @@ public class LinkedExtractorTileEntity extends LinkedTileEntity public LinkedExtractorTileEntity() { super(AllTileEntities.LINKED_EXTRACTOR.type); - state = State.WAITING_FOR_ITEM; + state = State.WAITING_FOR_INVENTORY; inventory = LazyOptional.empty(); } diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/PulseRepeaterBlock.java b/src/main/java/com/simibubi/create/modules/logistics/block/PulseRepeaterBlock.java new file mode 100644 index 000000000..83ee29b17 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/block/PulseRepeaterBlock.java @@ -0,0 +1,58 @@ +package com.simibubi.create.modules.logistics.block; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.RedstoneDiodeBlock; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.TickPriority; +import net.minecraft.world.World; + +public class PulseRepeaterBlock extends RedstoneDiodeBlock { + + public static BooleanProperty PULSING = BooleanProperty.create("pulsing"); + + public PulseRepeaterBlock() { + super(Properties.from(Blocks.REPEATER)); + setDefaultState(getDefaultState().with(PULSING, false).with(POWERED, false)); + } + + @Override + protected int getDelay(BlockState state) { + return 1; + } + + @Override + public void tick(BlockState state, World worldIn, BlockPos pos, Random random) { + boolean powered = state.get(POWERED); + boolean pulsing = state.get(PULSING); + boolean shouldPower = shouldBePowered(worldIn, pos, state); + + if (pulsing) { + worldIn.setBlockState(pos, state.with(POWERED, true).with(PULSING, false), 2); + } else if (powered && !shouldPower) { + worldIn.setBlockState(pos, state.with(POWERED, false).with(PULSING, false), 2); + } else if (!powered) { + worldIn.setBlockState(pos, state.with(POWERED, true).with(PULSING, true), 2); + worldIn.getPendingBlockTicks().scheduleTick(pos, this, this.getDelay(state), TickPriority.HIGH); + } + + } + + @Override + protected int getActiveSignal(IBlockReader worldIn, BlockPos pos, BlockState state) { + return state.get(PULSING) ? 15 : 0; + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(HORIZONTAL_FACING, POWERED, PULSING); + super.fillStateContainer(builder); + } + +} diff --git a/src/main/resources/assets/create/blockstates/belt_funnel.json b/src/main/resources/assets/create/blockstates/belt_funnel.json new file mode 100644 index 000000000..bec273f37 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/belt_funnel.json @@ -0,0 +1,14 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "create:block/belt_funnel" + }, + "variants": { + "facing": { + "south": { "y": 180 }, + "east": { "y": 90 }, + "north": { "y": 0 }, + "west": { "y": 270 } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/blockstates/pulse_repeater.json b/src/main/resources/assets/create/blockstates/pulse_repeater.json new file mode 100644 index 000000000..4112d7912 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/pulse_repeater.json @@ -0,0 +1,23 @@ +{ + "variants": { + "powered=false,pulsing=false,facing=south": { "model": "create:block/pulse_repeater" }, + "powered=false,pulsing=false,facing=north": { "model": "create:block/pulse_repeater", "y": 180 }, + "powered=false,pulsing=false,facing=east": { "model": "create:block/pulse_repeater", "y": 270 }, + "powered=false,pulsing=false,facing=west": { "model": "create:block/pulse_repeater", "y": 90 }, + + "powered=true,pulsing=false,facing=south": { "model": "create:block/pulse_repeater_powered" }, + "powered=true,pulsing=false,facing=north": { "model": "create:block/pulse_repeater_powered", "y": 180 }, + "powered=true,pulsing=false,facing=east": { "model": "create:block/pulse_repeater_powered", "y": 270 }, + "powered=true,pulsing=false,facing=west": { "model": "create:block/pulse_repeater_powered", "y": 90 }, + + "powered=false,pulsing=true,facing=south": { "model": "create:block/pulse_repeater_pulsing" }, + "powered=false,pulsing=true,facing=north": { "model": "create:block/pulse_repeater_pulsing", "y": 180 }, + "powered=false,pulsing=true,facing=east": { "model": "create:block/pulse_repeater_pulsing", "y": 270 }, + "powered=false,pulsing=true,facing=west": { "model": "create:block/pulse_repeater_pulsing", "y": 90 }, + + "powered=true,pulsing=true,facing=south": { "model": "create:block/pulse_repeater_pulsing" }, + "powered=true,pulsing=true,facing=north": { "model": "create:block/pulse_repeater_pulsing", "y": 180 }, + "powered=true,pulsing=true,facing=east": { "model": "create:block/pulse_repeater_pulsing", "y": 270 }, + "powered=true,pulsing=true,facing=west": { "model": "create:block/pulse_repeater_pulsing", "y": 90 } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index c5cd7fbd0..b47822141 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -41,7 +41,9 @@ "block.create.stockswitch": "Stockpile Switch", "block.create.flexcrate": "FlexCrate", "block.create.extractor": "Extractor", + "block.create.belt_funnel": "Belt Funnel", "block.create.linked_extractor": "Linked Extractor", + "block.create.pulse_repeater": "Pulse Repeater", "block.create.andesite_bricks": "Andesite Bricks", "block.create.diorite_bricks": "Diorite Bricks", @@ -74,6 +76,8 @@ "block.create.shop_shelf": "Shelf", "death.attack.create.crush": "%1$s was crushed by a dangerous contraption", + "death.attack.create.fan_fire": "%1$s was burnt to death by hot air", + "death.attack.create.fan_lava": "%1$s tried to swim up a lava fountain", "itemGroup.create": "Create" } diff --git a/src/main/resources/assets/create/models/block/belt_funnel.json b/src/main/resources/assets/create/models/block/belt_funnel.json new file mode 100644 index 000000000..10bd2f156 --- /dev/null +++ b/src/main/resources/assets/create/models/block/belt_funnel.json @@ -0,0 +1,97 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)", + "parent": "block/block", + "textures": { + "belt_funnel": "create:block/belt_funnel", + "belt": "create:block/belt", + "particle": "create:block/belt_funnel" + }, + "elements": [ + { + "name": "Bottom", + "from": [ 3, 0, -1 ], + "to": [ 13, 1, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] }, + "down": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] } + } + }, + { + "name": "Top", + "from": [ 3, 7, -1 ], + "to": [ 13, 8, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] }, + "down": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] } + } + }, + { + "name": "Side", + "from": [ 3, 1, -1 ], + "to": [ 4, 7, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 7 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Side", + "from": [ 12, 1, -1 ], + "to": [ 13, 7, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 7 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Center", + "from": [ 4, 1, -1 ], + "to": [ 12, 7, 4 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 14 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 1, 1, 9, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Top", + "from": [ 4, 6, 0 ], + "to": [ 12, 8, 4.8 ], + "rotation": { "origin": [ 8, 8, 0 ], "axis": "x", "angle": -22.5 }, + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 1, 7, 9, 9 ], "rotation": 180 }, + "east": { "texture": "#belt_funnel", "uv": [ 0, 9.6, 1.8, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 1, 7, 9, 9 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 2, 12.4 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 12.4 ], "rotation": 180 }, + "down": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 12.8 ] } + } + }, + { + "name": "Ramp", + "from": [ 4, -0.9, 4 ], + "to": [ 12, 1.1, 11 ], + "rotation": { "origin": [ 8, 1, 5 ], "axis": "x", "angle": 45.0 }, + "faces": { + "north": { "texture": "#belt", "uv": [ 0, 0, 8, 2 ] }, + "east": { "texture": "#belt", "uv": [ 14, 3, 16, 10 ], "rotation": 90 }, + "west": { "texture": "#belt", "uv": [ 0, 3, 2, 10 ], "rotation": 270 }, + "up": { "texture": "#belt", "uv": [ 4, 1, 12, 8 ] }, + "down": { "texture": "#belt", "uv": [ 0, 0, 8, 7 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/belt_funnel.json b/src/main/resources/assets/create/models/item/belt_funnel.json new file mode 100644 index 000000000..d1588d2a4 --- /dev/null +++ b/src/main/resources/assets/create/models/item/belt_funnel.json @@ -0,0 +1,101 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)", + "parent": "block/block", + "display": { + "gui": { + "rotation": [ 30, 45, 0 ], + "translation": [ 0, 0, 0], + "scale":[ 0.625, 0.625, 0.625 ] + } + }, + "textures": { + "belt_funnel": "create:block/belt_funnel", + "symbols": "create:item/symbols" + }, + "elements": [ + { + "name": "Indicator", + "from": [ 8, 7, 13 ], + "to": [ 16, 15, 13 ], + "shade": false, + "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#symbols", "uv": [ 0, 8, 8, 16 ] }, + "south": { "texture": "#symbols", "uv": [ 0, 8, 8, 16 ] } + } + }, + { + "name": "Bottom", + "from": [ 3, 0, -1 ], + "to": [ 13, 1, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] }, + "down": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] } + } + }, + { + "name": "Top", + "from": [ 3, 7, -1 ], + "to": [ 13, 8, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] }, + "down": { "texture": "#belt_funnel", "uv": [ 0, 8, 10, 14 ] } + } + }, + { + "name": "Side", + "from": [ 3, 1, -1 ], + "to": [ 4, 7, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 7 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Side", + "from": [ 12, 1, -1 ], + "to": [ 13, 7, 5 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 7 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Center", + "from": [ 4, 1, -1 ], + "to": [ 12, 7, 4 ], + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 14 ] }, + "east": { "texture": "#belt_funnel", "uv": [ 9, 8, 10, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 1, 1, 9, 7 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 1, 14 ], "rotation": 90 } + } + }, + { + "name": "Top", + "from": [ 4, 6, 0 ], + "to": [ 12, 8, 4.8 ], + "rotation": { "origin": [ 8, 8, 0 ], "axis": "x", "angle": -22.5 }, + "faces": { + "north": { "texture": "#belt_funnel", "uv": [ 1, 7, 9, 9 ], "rotation": 180 }, + "east": { "texture": "#belt_funnel", "uv": [ 0, 9.6, 1.8, 14 ], "rotation": 90 }, + "south": { "texture": "#belt_funnel", "uv": [ 1, 7, 9, 9 ] }, + "west": { "texture": "#belt_funnel", "uv": [ 0, 8, 2, 12.4 ], "rotation": 90 }, + "up": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 12.4 ], "rotation": 180 }, + "down": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 12.8 ] } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/linked_extractor.json b/src/main/resources/assets/create/models/item/linked_extractor.json index c2829e31a..7a6a21184 100644 --- a/src/main/resources/assets/create/models/item/linked_extractor.json +++ b/src/main/resources/assets/create/models/item/linked_extractor.json @@ -1,10 +1,129 @@ { - "parent": "create:block/extractor_wireless_powered", + "parent": "block/block", "display": { "gui": { "rotation": [ 30, 45, 0 ], "translation": [ 0, 0, 0], "scale":[ 0.625, 0.625, 0.625 ] } - } + }, + "textures": { + "redstone_antenna": "create:block/redstone_antenna", + "extractor": "create:block/extractor", + "symbols": "create:item/symbols" + }, + "elements": [ + { + "name": "Indicator", + "from": [ 8, 7, 13 ], + "to": [ 16, 15, 13 ], + "shade": false, + "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": -45.0 }, + "faces": { + "north": { "texture": "#symbols", "uv": [ 0, 0, 8, 8 ] }, + "south": { "texture": "#symbols", "uv": [ 0, 0, 8, 8 ] } + } + }, + { + "name": "Bottom", + "from": [ 4, 2, -1 ], + "to": [ 12, 3, 5 ], + "faces": { + "east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 }, + "south": { "texture": "#extractor", "uv": [ 6, 7, 14, 8 ] }, + "west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] }, + "up": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 90 }, + "down": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 270 } + } + }, + { + "name": "Top", + "from": [ 4, 9, -1 ], + "to": [ 12, 10, 5 ], + "faces": { + "east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 }, + "south": { "texture": "#extractor", "uv": [ 6, 0, 14, 1 ] }, + "west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] }, + "up": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 90 }, + "down": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 270 } + } + }, + { + "name": "Side", + "from": [ 4, 3, -1 ], + "to": [ 5, 9, 5 ], + "faces": { + "east": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ], "rotation": 180 }, + "south": { "texture": "#extractor", "uv": [ 6, 1, 7, 7 ] }, + "west": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ] } + } + }, + { + "name": "Side", + "from": [ 11, 3, -1 ], + "to": [ 12, 9, 5 ], + "faces": { + "east": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ], "rotation": 180 }, + "south": { "texture": "#extractor", "uv": [ 13, 1, 14, 7 ] }, + "west": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ] } + } + }, + { + "name": "Center", + "from": [ 5, 3, 3 ], + "to": [ 11, 9, 4 ], + "faces": { + "south": { "texture": "#extractor", "uv": [ 7, 1, 13, 7 ] } + } + }, + { + "name": "FilterSpot", + "from": [ 5, 10, -0.6 ], + "to": [ 11, 12, 4 ], + "rotation": { "origin": [ 8, 11, -1 ], "axis": "x", "angle": 22.5 }, + "faces": { + "north": { "texture": "#extractor", "uv": [ 13, 1, 15, 7 ], "rotation": 90 }, + "east": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ], "rotation": 180 }, + "south": { "texture": "#extractor", "uv": [ 4, 1, 5, 7 ], "rotation": 270 }, + "west": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ] }, + "up": { "texture": "#extractor", "uv": [ 0, 9, 5, 15 ], "rotation": 90 } + } + }, + { + "name": "AntennaX", + "from": [ 11, 7, 2 ], + "to": [ 14, 17, 3 ], + "faces": { + "north": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] }, + "south": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] }, + "down": { "texture": "#redstone_antenna", "uv": [ 0, 9, 3, 10 ] } + } + }, + { + "name": "AntennaZ", + "from": [ 12, 7, 1 ], + "to": [ 13, 17, 4 ], + "faces": { + "east": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] }, + "west": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] } + } + }, + { + "name": "AntennaTop", + "from": [ 12, 15, 2 ], + "to": [ 13, 16, 3 ], + "faces": { + "up": { "texture": "#redstone_antenna", "uv": [ 1, 1, 2, 2 ] } + } + }, + { + "name": "AntennaDish", + "from": [ 10, 13, 0 ], + "to": [ 15, 13, 5 ], + "faces": { + "up": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] }, + "down": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] } + } + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/pulse_repeater.json b/src/main/resources/assets/create/models/item/pulse_repeater.json new file mode 100644 index 000000000..3421ad52d --- /dev/null +++ b/src/main/resources/assets/create/models/item/pulse_repeater.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/pulse_repeater" +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/belt_funnel.png b/src/main/resources/assets/create/textures/block/belt_funnel.png new file mode 100644 index 000000000..0e505629c Binary files /dev/null and b/src/main/resources/assets/create/textures/block/belt_funnel.png differ diff --git a/src/main/resources/assets/create/textures/item/symbols.png b/src/main/resources/assets/create/textures/item/symbols.png new file mode 100644 index 000000000..37722a2e9 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/symbols.png differ