diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index e0fb0bb91..45fd51be7 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -826,6 +826,12 @@ "create.gui.goggles.kinetic_stats": "Kinetic Stats:", "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.pole_length": "Pole Length:", + "create.gui.assembly.exception": "This Contraption was unable to assemble:", + "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s %2$s %3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.structureTooLarge": "There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.tooManyPistonPoles": "There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.noPistonPoles": "The Piston is missing some extension Poles", "create.gui.gauge.info_header": "Gauge Information:", "create.gui.speedometer.title": "Rotation Speed", "create.gui.stressometer.title": "Network Stress", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index 52c858df4..446cd7b2c 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -827,6 +827,12 @@ "create.gui.goggles.kinetic_stats": "UNLOCALIZED: Kinetic Stats:", "create.gui.goggles.at_current_speed": "UNLOCALIZED: at current speed", "create.gui.goggles.pole_length": "UNLOCALIZED: Pole Length:", + "create.gui.assembly.exception": "UNLOCALIZED: This Contraption was unable to assemble:", + "create.gui.assembly.exception.unmovableBlock": "UNLOCALIZED: Unmovable Block (%4$s) at [%1$s %2$s %3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "UNLOCALIZED: The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.structureTooLarge": "UNLOCALIZED: There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.tooManyPistonPoles": "UNLOCALIZED: There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.noPistonPoles": "UNLOCALIZED: The Piston is missing some extension Poles", "create.gui.gauge.info_header": "UNLOCALIZED: Gauge Information:", "create.gui.speedometer.title": "UNLOCALIZED: Rotation Speed", "create.gui.stressometer.title": "UNLOCALIZED: Network Stress", diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java index aecc89232..8552f1b80 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/GeneratingKineticTileEntity.java @@ -40,7 +40,7 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity { if (!(tileEntity instanceof KineticTileEntity)) return; KineticTileEntity sourceTe = (KineticTileEntity) tileEntity; - if (reActivateSource && sourceTe != null && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed())) + if (reActivateSource && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed())) reActivateSource = false; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java new file mode 100644 index 000000000..0db500c6d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AssemblyException.java @@ -0,0 +1,91 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.simibubi.create.foundation.config.AllConfigs; +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; + +public class AssemblyException extends Exception { + public final ITextComponent component; + private BlockPos position = null; + + public static void write(CompoundNBT compound, AssemblyException exception) { + if (exception == null) + return; + + CompoundNBT nbt = new CompoundNBT(); + nbt.putString("Component", ITextComponent.Serializer.toJson(exception.component)); + if (exception.hasPosition()) + nbt.putLong("Position", exception.getPosition().toLong()); + + compound.put("LastException", nbt); + } + + public static AssemblyException read(CompoundNBT compound) { + if (!compound.contains("LastException")) + return null; + + CompoundNBT nbt = compound.getCompound("LastException"); + String string = nbt.getString("Component"); + AssemblyException exception = new AssemblyException(ITextComponent.Serializer.fromJson(string)); + if (nbt.contains("Position")) + exception.position = BlockPos.fromLong(nbt.getLong("Position")); + + return exception; + } + + public AssemblyException(ITextComponent component) { + this.component = component; + } + + public AssemblyException(String langKey, Object... objects) { + this(new TranslationTextComponent("create.gui.assembly.exception." + langKey, objects)); + } + + public static AssemblyException unmovableBlock(BlockPos pos, BlockState state) { + AssemblyException e = new AssemblyException("unmovableBlock", + pos.getX(), + pos.getY(), + pos.getZ(), + new TranslationTextComponent(state.getBlock().getTranslationKey())); + e.position = pos; + return e; + } + + public static AssemblyException unloadedChunk(BlockPos pos) { + AssemblyException e = new AssemblyException("chunkNotLoaded", + pos.getX(), + pos.getY(), + pos.getZ()); + e.position = pos; + return e; + } + + public static AssemblyException structureTooLarge() { + return new AssemblyException("structureTooLarge", + AllConfigs.SERVER.kinetics.maxBlocksMoved.get()); + } + + public static AssemblyException tooManyPistonPoles() { + return new AssemblyException("tooManyPistonPoles", + AllConfigs.SERVER.kinetics.maxPistonPoles.get()); + } + + public static AssemblyException noPistonPoles() { + return new AssemblyException("noPistonPoles"); + } + + public String getFormattedText() { + return component.getFormattedText(); + } + + public boolean hasPosition() { + return position != null; + } + + public BlockPos getPosition() { + return position; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java index ac38a8eb7..7b659a41a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java @@ -54,8 +54,7 @@ import net.minecraft.world.World; public class BlockMovementTraits { - public static boolean movementNecessary(World world, BlockPos pos) { - BlockState state = world.getBlockState(pos); + public static boolean movementNecessary(BlockState state, World world, BlockPos pos) { if (isBrittle(state)) return true; if (state.getBlock() instanceof FenceGateBlock) @@ -69,18 +68,17 @@ public class BlockMovementTraits { return true; } - public static boolean movementAllowed(World world, BlockPos pos) { - BlockState blockState = world.getBlockState(pos); - Block block = blockState.getBlock(); + public static boolean movementAllowed(BlockState state, World world, BlockPos pos) { + Block block = state.getBlock(); if (block instanceof AbstractChassisBlock) return true; - if (blockState.getBlockHardness(world, pos) == -1) + if (state.getBlockHardness(world, pos) == -1) return false; - if (AllBlockTags.NON_MOVABLE.matches(blockState)) + if (AllBlockTags.NON_MOVABLE.matches(state)) return false; // Move controllers only when they aren't moving - if (block instanceof MechanicalPistonBlock && blockState.get(MechanicalPistonBlock.STATE) != PistonState.MOVING) + if (block instanceof MechanicalPistonBlock && state.get(MechanicalPistonBlock.STATE) != PistonState.MOVING) return true; if (block instanceof MechanicalBearingBlock) { TileEntity te = world.getTileEntity(pos); @@ -98,11 +96,11 @@ public class BlockMovementTraits { return !((PulleyTileEntity) te).running; } - if (AllBlocks.BELT.has(blockState)) + if (AllBlocks.BELT.has(state)) return true; - if (blockState.getBlock() instanceof GrindstoneBlock) + if (state.getBlock() instanceof GrindstoneBlock) return true; - return blockState.getPushReaction() != PushReaction.BLOCK; + return state.getPushReaction() != PushReaction.BLOCK; } /** diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index a1de4a810..614e4bbc8 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -1,26 +1,5 @@ package com.simibubi.create.content.contraptions.components.structureMovement; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.base.IRotate; @@ -56,15 +35,7 @@ import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTProcessors; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; - -import net.minecraft.block.AbstractButtonBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.ChestBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.IWaterLoggable; -import net.minecraft.block.PressurePlateBlock; +import net.minecraft.block.*; import net.minecraft.block.material.PushReaction; import net.minecraft.entity.Entity; import net.minecraft.fluid.FluidState; @@ -97,6 +68,16 @@ import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.fluids.capability.templates.FluidTank; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.CombinedInvWrapper; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; public abstract class Contraption { @@ -140,7 +121,7 @@ public abstract class Contraption { stabilizedSubContraptions = new HashMap<>(); } - public abstract boolean assemble(World world, BlockPos pos); + public abstract boolean assemble(World world, BlockPos pos) throws AssemblyException; public abstract boolean canBeStabilized(Direction facing, BlockPos localPos); @@ -155,7 +136,7 @@ public abstract class Contraption { } protected boolean addToInitialFrontier(World world, BlockPos pos, Direction forcedDirection, - List frontier) { + Queue frontier) throws AssemblyException { return true; } @@ -166,9 +147,9 @@ public abstract class Contraption { return contraption; } - public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) { + public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) throws AssemblyException { initialPassengers.clear(); - List frontier = new ArrayList<>(); + Queue frontier = new LinkedList<>(); Set visited = new HashSet<>(); anchor = pos; @@ -182,10 +163,10 @@ public abstract class Contraption { for (int limit = 100000; limit > 0; limit--) { if (frontier.isEmpty()) return true; - if (!moveBlock(world, frontier.remove(0), forcedDirection, frontier, visited)) + if (!moveBlock(world, forcedDirection, frontier, visited)) return false; } - return false; + throw AssemblyException.structureTooLarge(); } public void onEntityCreated(AbstractContraptionEntity entity) { @@ -197,8 +178,12 @@ public abstract class Contraption { StabilizedContraption subContraption = new StabilizedContraption(face); World world = entity.world; BlockPos pos = blockFace.getPos(); - if (!subContraption.assemble(world, pos)) + try { + if (!subContraption.assemble(world, pos)) + continue; + } catch (AssemblyException e) { continue; + } subContraption.removeBlocksFromWorld(world, BlockPos.ZERO); OrientedContraptionEntity movedContraption = OrientedContraptionEntity.create(world, subContraption, Optional.of(face)); @@ -248,20 +233,25 @@ public abstract class Contraption { fluidStorage.forEach((pos, mfs) -> mfs.tick(entity, pos, world.isRemote)); } - protected boolean moveBlock(World world, BlockPos pos, @Nullable Direction forcedDirection, List frontier, - Set visited) { - visited.add(pos); - frontier.remove(pos); - - if (!world.isBlockPresent(pos)) + /** move the first block in frontier queue */ + protected boolean moveBlock(World world, @Nullable Direction forcedDirection, Queue frontier, + Set visited) throws AssemblyException { + BlockPos pos = frontier.poll(); + if (pos == null) return false; + visited.add(pos); + + if (World.isOutsideBuildHeight(pos)) + return true; + if (!world.isBlockPresent(pos)) + throw AssemblyException.unloadedChunk(pos); if (isAnchoringBlockAt(pos)) return true; - if (!BlockMovementTraits.movementNecessary(world, pos)) - return true; - if (!movementAllowed(world, pos)) - return false; BlockState state = world.getBlockState(pos); + if (!BlockMovementTraits.movementNecessary(state, world, pos)) + return true; + if (!movementAllowed(state, world, pos)) + throw AssemblyException.unmovableBlock(pos, state); if (state.getBlock() instanceof AbstractChassisBlock && !moveChassis(world, pos, forcedDirection, frontier, visited)) return false; @@ -307,9 +297,10 @@ public abstract class Contraption { } // Cart assemblers attach themselves - BlockState stateBelow = world.getBlockState(pos.down()); - if (!visited.contains(pos.down()) && AllBlocks.CART_ASSEMBLER.has(stateBelow)) - frontier.add(pos.down()); + BlockPos posDown = pos.down(); + BlockState stateBelow = world.getBlockState(posDown); + if (!visited.contains(posDown) && AllBlocks.CART_ASSEMBLER.has(stateBelow)) + frontier.add(posDown); Map superglue = SuperGlueHandler.gatherGlue(world, pos); @@ -319,9 +310,9 @@ public abstract class Contraption { BlockState blockState = world.getBlockState(offsetPos); if (isAnchoringBlockAt(offsetPos)) continue; - if (!movementAllowed(world, offsetPos)) { + if (!movementAllowed(blockState, world, offsetPos)) { if (offset == forcedDirection) - return false; + throw AssemblyException.unmovableBlock(pos, state); continue; } @@ -350,10 +341,13 @@ public abstract class Contraption { } addBlock(pos, capture(world, pos)); - return blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get(); + if (blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get()) + return true; + else + throw AssemblyException.structureTooLarge(); } - protected void movePistonHead(World world, BlockPos pos, List frontier, Set visited, + protected void movePistonHead(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) { Direction direction = state.get(MechanicalPistonHeadBlock.FACING); BlockPos offset = pos.offset(direction.getOpposite()); @@ -375,7 +369,7 @@ public abstract class Contraption { } } - protected void movePistonPole(World world, BlockPos pos, List frontier, Set visited, + protected void movePistonPole(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) { for (Direction d : Iterate.directionsInAxis(state.get(PistonExtensionPoleBlock.FACING) .getAxis())) { @@ -398,7 +392,7 @@ public abstract class Contraption { } } - protected void moveGantryPinion(World world, BlockPos pos, List frontier, Set visited, + protected void moveGantryPinion(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) { BlockPos offset = pos.offset(state.get(GantryPinionBlock.FACING)); if (!visited.contains(offset)) @@ -414,7 +408,7 @@ public abstract class Contraption { } } - protected void moveGantryShaft(World world, BlockPos pos, List frontier, Set visited, + protected void moveGantryShaft(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) { for (Direction d : Iterate.directions) { BlockPos offset = pos.offset(d); @@ -430,7 +424,7 @@ public abstract class Contraption { } } - private void moveBearing(BlockPos pos, List frontier, Set visited, BlockState state) { + private void moveBearing(BlockPos pos, Queue frontier, Set visited, BlockState state) { Direction facing = state.get(MechanicalBearingBlock.FACING); if (!canBeStabilized(facing, pos.subtract(anchor))) { BlockPos offset = pos.offset(facing); @@ -441,7 +435,7 @@ public abstract class Contraption { pendingSubContraptions.add(new BlockFace(pos, facing)); } - private void moveBelt(BlockPos pos, List frontier, Set visited, BlockState state) { + private void moveBelt(BlockPos pos, Queue frontier, Set visited, BlockState state) { BlockPos nextPos = BeltBlock.nextSegmentPosition(state, pos, true); BlockPos prevPos = BeltBlock.nextSegmentPosition(state, pos, false); if (nextPos != null && !visited.contains(nextPos)) @@ -462,7 +456,7 @@ public abstract class Contraption { } } - private void movePulley(World world, BlockPos pos, List frontier, Set visited) { + private void movePulley(World world, BlockPos pos, Queue frontier, Set visited) { int limit = AllConfigs.SERVER.kinetics.maxRopeLength.get(); BlockPos ropePos = pos; while (limit-- >= 0) { @@ -480,8 +474,8 @@ public abstract class Contraption { } } - private boolean moveMechanicalPiston(World world, BlockPos pos, List frontier, Set visited, - BlockState state) { + private boolean moveMechanicalPiston(World world, BlockPos pos, Queue frontier, Set visited, BlockState state) throws AssemblyException { + int limit = AllConfigs.SERVER.kinetics.maxPistonPoles.get(); Direction direction = state.get(MechanicalPistonBlock.FACING); PistonState pistonState = state.get(MechanicalPistonBlock.STATE); if (pistonState == PistonState.MOVING) @@ -504,7 +498,7 @@ public abstract class Contraption { return true; } - private boolean moveChassis(World world, BlockPos pos, Direction movementDirection, List frontier, + private boolean moveChassis(World world, BlockPos pos, Direction movementDirection, Queue frontier, Set visited) { TileEntity te = world.getTileEntity(pos); if (!(te instanceof ChassisTileEntity)) @@ -589,8 +583,8 @@ public abstract class Contraption { return globalPos.subtract(anchor); } - protected boolean movementAllowed(World world, BlockPos pos) { - return BlockMovementTraits.movementAllowed(world, pos); + protected boolean movementAllowed(BlockState state, World world, BlockPos pos) { + return BlockMovementTraits.movementAllowed(state, world, pos); } protected boolean isAnchoringBlockAt(BlockPos pos) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java new file mode 100644 index 000000000..33abfc9fb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IDisplayAssemblyExceptions.java @@ -0,0 +1,28 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation; +import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.util.text.TextFormatting; + +import java.util.Arrays; +import java.util.List; + +public interface IDisplayAssemblyExceptions { + + default boolean addExceptionToTooltip(List tooltip) { + AssemblyException e = getLastAssemblyException(); + if (e == null) + return false; + + if (!tooltip.isEmpty()) + tooltip.add(""); + + tooltip.add(IHaveGoggleInformation.spacing + TextFormatting.GOLD + Lang.translate("gui.assembly.exception")); + String text = e.getFormattedText(); + Arrays.stream(text.split("\n")).forEach(l -> tooltip.add(IHaveGoggleInformation.spacing + TextFormatting.GRAY + l)); + + return true; + } + + AssemblyException getLastAssemblyException(); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java index 8215a87c2..49656f15e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import net.minecraft.nbt.CompoundNBT; @@ -28,7 +29,7 @@ public class BearingContraption extends Contraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { BlockPos offset = pos.offset(facing); if (!searchMovedStructure(world, offset, null)) return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java index ae7b9e084..34c3cfbde 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java @@ -1,12 +1,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption.HandType; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.gui.AllIcons; @@ -16,7 +14,6 @@ import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOpt import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; @@ -25,8 +22,11 @@ import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import org.apache.commons.lang3.tuple.Pair; -public class ClockworkBearingTileEntity extends KineticTileEntity implements IBearingTileEntity { +import java.util.List; + +public class ClockworkBearingTileEntity extends KineticTileEntity implements IBearingTileEntity, IDisplayAssemblyExceptions { protected ControlledContraptionEntity hourHand; protected ControlledContraptionEntity minuteHand; @@ -37,6 +37,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe protected boolean running; protected boolean assembleNextTick; + protected AssemblyException lastException; protected ScrollOptionBehaviour operationMode; @@ -105,6 +106,11 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe applyRotations(); } + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + protected void applyRotations() { BlockState blockState = getBlockState(); Axis axis = Axis.X; @@ -200,8 +206,15 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe Direction direction = getBlockState().get(BlockStateProperties.FACING); // Collect Construct - Pair contraption = - ClockworkContraption.assembleClockworkAt(world, pos, direction); + Pair contraption; + try { + contraption = ClockworkContraption.assembleClockworkAt(world, pos, direction); + lastException = null; + } catch (AssemblyException e) { + lastException = e; + sendData(); + return; + } if (contraption == null) return; if (contraption.getLeft() == null) @@ -285,6 +298,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe compound.putBoolean("Running", running); compound.putFloat("HourAngle", hourAngle); compound.putFloat("MinuteAngle", minuteAngle); + AssemblyException.write(compound, lastException); super.write(compound, clientPacket); } @@ -296,6 +310,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe running = compound.getBoolean("Running"); hourAngle = compound.getFloat("HourAngle"); minuteAngle = compound.getFloat("MinuteAngle"); + lastException = AssemblyException.read(compound); super.fromTag(state, compound, clientPacket); if (!clientPacket) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java index 4a9c61992..a105ad0d2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java @@ -7,13 +7,18 @@ import java.util.Set; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.foundation.utility.NBTHelper; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; public class ClockworkContraption extends Contraption { @@ -38,7 +43,7 @@ public class ClockworkContraption extends Contraption { } public static Pair assembleClockworkAt(World world, BlockPos pos, - Direction direction) { + Direction direction) throws AssemblyException { int hourArmBlocks = 0; ClockworkContraption hourArm = new ClockworkContraption(); @@ -81,21 +86,23 @@ public class ClockworkContraption extends Contraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { return searchMovedStructure(world, pos, facing); } @Override - public boolean searchMovedStructure(World world, BlockPos pos, Direction direction) { + public boolean searchMovedStructure(World world, BlockPos pos, Direction direction) throws AssemblyException { return super.searchMovedStructure(world, pos.offset(direction, offset + 1), null); } @Override - protected boolean moveBlock(World world, BlockPos pos, Direction direction, List frontier, - Set visited) { - if (ignoreBlocks.contains(pos)) + protected boolean moveBlock(World world, Direction direction, Queue frontier, + Set visited) throws AssemblyException { + if (ignoreBlocks.contains(frontier.peek())) { + frontier.poll(); return true; - return super.moveBlock(world, pos, direction, frontier, visited); + } + return super.moveBlock(world, direction, frontier, visited); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index 5a27d7d79..7defc501b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -1,12 +1,10 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - -import java.util.List; - import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -15,7 +13,6 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; @@ -25,7 +22,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; -public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IBearingTileEntity { +import java.util.List; + +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IBearingTileEntity, IDisplayAssemblyExceptions { protected ScrollOptionBehaviour movementMode; protected ControlledContraptionEntity movedContraption; @@ -33,6 +34,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp protected boolean running; protected boolean assembleNextTick; protected float clientAngleDiff; + protected AssemblyException lastException; public MechanicalBearingTileEntity(TileEntityType type) { super(type); @@ -64,6 +66,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Running", running); compound.putFloat("Angle", angle); + AssemblyException.write(compound, lastException); super.write(compound, clientPacket); } @@ -72,8 +75,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp float angleBefore = angle; running = compound.getBoolean("Running"); angle = compound.getFloat("Angle"); + lastException = AssemblyException.read(compound); super.fromTag(state, compound, clientPacket); - if (!clientPacket) return; if (running) { @@ -107,6 +110,11 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp return speed; } + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + protected boolean isWindmill() { return false; } @@ -123,8 +131,16 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp Direction direction = getBlockState().get(FACING); BearingContraption contraption = new BearingContraption(isWindmill(), direction); - if (!contraption.assemble(world, pos)) + try { + if (!contraption.assemble(world, pos)) + return; + + lastException = null; + } catch (AssemblyException e) { + lastException = e; + sendData(); return; + } if (isWindmill()) AllTriggers.triggerForNearbyPlayers(AllTriggers.WINDMILL, world, pos, 5); @@ -284,5 +300,4 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp TooltipHelper.addHint(tooltip, "hint.empty_bearing"); return true; } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java index 653d2bcb4..8fb58fb29 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java @@ -64,27 +64,9 @@ public class SailBlock extends ProperDirectionalBlock { public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) { ItemStack heldItem = player.getHeldItem(hand); - if (AllBlocks.SAIL.isIn(heldItem) || AllBlocks.SAIL_FRAME.isIn(heldItem)) { - IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); - PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray); - - if (!offset.isReplaceable(world)) - return ActionResultType.PASS; - - offset.placeInWorld(world, ((BlockItem) heldItem.getItem()).getBlock().getDefaultState(), player, heldItem); - - /*BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock() - .getDefaultState() - .with(FACING, state.get(FACING)); - BlockPos offsetPos = new BlockPos(offset.getPos()); - if (!world.isRemote && world.getBlockState(offsetPos).getMaterial().isReplaceable()) { - world.setBlockState(offsetPos, blockState); - if (!player.isCreative()) - heldItem.shrink(1); - }*/ - - return ActionResultType.SUCCESS; - } + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (placementHelper.matchesItem(heldItem)) + return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); if (heldItem.getItem() instanceof ShearsItem) { if (!world.isRemote) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java index c8281b7c0..a8b726cd2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.bearing; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import net.minecraft.nbt.CompoundNBT; @@ -20,7 +21,7 @@ public class StabilizedContraption extends Contraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { BlockPos offset = pos.offset(facing); if (!searchMovedStructure(world, offset, null)) return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java index 832b656da..fcb4f1c1b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Queue; import java.util.Set; import com.simibubi.create.AllBlocks; @@ -76,12 +77,12 @@ public class ChassisTileEntity extends SmartTileEntity { } public List collectChassisGroup() { - List frontier = new ArrayList<>(); + Queue frontier = new LinkedList<>(); List collected = new ArrayList<>(); Set visited = new HashSet<>(); frontier.add(pos); while (!frontier.isEmpty()) { - BlockPos current = frontier.remove(0); + BlockPos current = frontier.poll(); if (visited.contains(current)) continue; visited.add(current); @@ -96,7 +97,7 @@ public class ChassisTileEntity extends SmartTileEntity { return collected; } - public boolean addAttachedChasses(List frontier, Set visited) { + public boolean addAttachedChasses(Queue frontier, Set visited) { BlockState state = getBlockState(); if (!(state.getBlock() instanceof AbstractChassisBlock)) return false; @@ -166,7 +167,7 @@ public class ChassisTileEntity extends SmartTileEntity { break; // Ignore replaceable Blocks and Air-like - if (!BlockMovementTraits.movementNecessary(world, current)) + if (!BlockMovementTraits.movementNecessary(currentState, world, current)) break; if (BlockMovementTraits.isBrittle(currentState)) break; @@ -207,7 +208,7 @@ public class ChassisTileEntity extends SmartTileEntity { continue; if (!searchPos.withinDistance(pos, chassisRange + .5f)) continue; - if (!BlockMovementTraits.movementNecessary(world, searchPos)) + if (!BlockMovementTraits.movementNecessary(searchedState, world, searchPos)) continue; if (BlockMovementTraits.isBrittle(searchedState)) continue; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java index 58ddcadcb..8bc426b3e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryContraption.java @@ -1,9 +1,9 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; - import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -21,7 +21,7 @@ public class GantryContraption extends TranslatingContraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { if (!searchMovedStructure(world, pos, null)) return false; startMoving(world); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java index 3c2b6f437..000a944ba 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/gantry/GantryPinionTileEntity.java @@ -1,23 +1,26 @@ package com.simibubi.create.content.contraptions.components.structureMovement.gantry; -import static net.minecraft.state.properties.BlockStateProperties.FACING; - import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftTileEntity; - import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; -public class GantryPinionTileEntity extends KineticTileEntity { +import static net.minecraft.state.properties.BlockStateProperties.FACING; + +public class GantryPinionTileEntity extends KineticTileEntity implements IDisplayAssemblyExceptions { boolean assembleNextTick; + protected AssemblyException lastException; public GantryPinionTileEntity(TileEntityType typeIn) { super(typeIn); @@ -50,6 +53,11 @@ public class GantryPinionTileEntity extends KineticTileEntity { } } + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + private void tryAssemble() { BlockState blockState = getBlockState(); if (!(blockState.getBlock() instanceof GantryPinionBlock)) @@ -71,8 +79,17 @@ public class GantryPinionTileEntity extends KineticTileEntity { if (pinionMovementSpeed < 0) movementDirection = movementDirection.getOpposite(); - if (!contraption.assemble(world, pos)) + try { + lastException = null; + if (!contraption.assemble(world, pos)) + return; + + sendData(); + } catch (AssemblyException e) { + lastException = e; + sendData(); return; + } if (ContraptionCollider.isCollidingWithWorld(world, contraption, pos.offset(movementDirection), movementDirection)) return; @@ -85,6 +102,18 @@ public class GantryPinionTileEntity extends KineticTileEntity { world.addEntity(movedContraption); } + @Override + protected void write(CompoundNBT compound, boolean clientPacket) { + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundNBT compound, boolean clientPacket) { + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + } + @Override public float propagateRotationTo(KineticTileEntity target, BlockState stateFrom, BlockState stateTo, BlockPos diff, boolean connectedViaAxes, boolean connectedViaCogs) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java index c4911e54a..b1c1065dc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java @@ -181,7 +181,7 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat BlockState state = world.getBlockState(pos); if (BlockMovementTraits.isBlockAttachedTowards(world, pos, state, direction)) return true; - if (!BlockMovementTraits.movementNecessary(world, pos)) + if (!BlockMovementTraits.movementNecessary(state, world, pos)) return false; if (BlockMovementTraits.notSupportive(state, direction)) return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java index baa5a5bd8..b78eef3db 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueHandler.java @@ -1,13 +1,9 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.simibubi.create.AllItems; import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.worldWrappers.RayTraceWorld; - import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -16,10 +12,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.*; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.IWorld; @@ -30,6 +23,10 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.network.PacketDistributor; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @EventBusSubscriber public class SuperGlueHandler { @@ -68,6 +65,8 @@ public class SuperGlueHandler { return; if (AllItems.WRENCH.isIn(placer.getHeldItemMainhand())) return; + if (event.getPlacedAgainst() == IPlacementHelper.ID) + return; double distance = reachAttribute.getValue(); Vector3d start = placer.getEyePosition(1); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java index 20c79a460..fac0fa81f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java @@ -11,6 +11,7 @@ import javax.annotation.Nullable; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; @@ -288,13 +289,27 @@ public class CartAssemblerBlock extends AbstractRailBlock .isCoupledThroughContraption()) return; - CartMovementMode mode = - getTileEntityOptional(world, pos).map(te -> CartMovementMode.values()[te.movementMode.value]) + + Optional assembler = getTileEntityOptional(world, pos); + CartMovementMode mode = assembler.map(te -> CartMovementMode.values()[te.movementMode.value]) .orElse(CartMovementMode.ROTATE); MountedContraption contraption = new MountedContraption(mode); - if (!contraption.assemble(world, pos)) + try { + if (!contraption.assemble(world, pos)) + return; + + assembler.ifPresent(te -> { + te.lastException = null; + te.sendData(); + }); + } catch (AssemblyException e) { + assembler.ifPresent(te -> { + te.lastException = e; + te.sendData(); + }); return; + } boolean couplingFound = contraption.connectedCart != null; Optional initialOrientation = cart.getMotion() diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java index 8586cf008..d7273dfc2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerTileEntity.java @@ -1,7 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mounted; -import java.util.List; - +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -12,17 +12,20 @@ import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOpt import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VecHelper; - +import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.RailShape; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.vector.Vector3d; -public class CartAssemblerTileEntity extends SmartTileEntity { +import java.util.List; + +public class CartAssemblerTileEntity extends SmartTileEntity implements IDisplayAssemblyExceptions { private static final int assemblyCooldown = 8; protected ScrollOptionBehaviour movementMode; private int ticksSinceMinecartUpdate; + protected AssemblyException lastException; public CartAssemblerTileEntity(TileEntityType type) { super(type); @@ -45,6 +48,23 @@ public class CartAssemblerTileEntity extends SmartTileEntity { behaviours.add(movementMode); } + @Override + public void write(CompoundNBT compound, boolean clientPacket) { + AssemblyException.write(compound, lastException); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundNBT compound, boolean clientPacket) { + lastException = AssemblyException.read(compound); + super.read(compound, clientPacket); + } + + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + protected ValueBoxTransform getMovementModeSlot() { return new CartAssemblerValueBoxTransform(); } @@ -104,5 +124,4 @@ public class CartAssemblerTileEntity extends SmartTileEntity { public boolean isMinecartUpdateValid() { return ticksSinceMinecartUpdate >= assemblyCooldown; } - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java index 3448e96b5..374c58b77 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java @@ -2,12 +2,13 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mo import static com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerBlock.RAIL_SHAPE; -import java.util.List; +import java.util.Queue; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; import com.simibubi.create.foundation.utility.BlockHelper; @@ -53,7 +54,7 @@ public class MountedContraption extends Contraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { BlockState state = world.getBlockState(pos); if (!BlockHelper.hasBlockStateProperty(state, RAIL_SHAPE)) return false; @@ -71,7 +72,7 @@ public class MountedContraption extends Contraption { } @Override - protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List frontier) { + protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, Queue frontier) { frontier.clear(); frontier.add(pos.up()); return true; @@ -105,11 +106,10 @@ public class MountedContraption extends Contraption { } @Override - protected boolean movementAllowed(World world, BlockPos pos) { - BlockState blockState = world.getBlockState(pos); - if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(blockState)) - return testSecondaryCartAssembler(world, blockState, pos); - return super.movementAllowed(world, pos); + protected boolean movementAllowed(BlockState state, World world, BlockPos pos) { + if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(state)) + return testSecondaryCartAssembler(world, state, pos); + return super.movementAllowed(state, world, pos); } protected boolean testSecondaryCartAssembler(World world, BlockState state, BlockPos pos) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java index 726e3191b..80610504f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java @@ -1,17 +1,12 @@ package com.simibubi.create.content.contraptions.components.structureMovement.piston; -import java.util.List; - import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.*; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; @@ -19,7 +14,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; -public abstract class LinearActuatorTileEntity extends KineticTileEntity implements IControlContraption { +import java.util.List; + +public abstract class LinearActuatorTileEntity extends KineticTileEntity implements IControlContraption, IDisplayAssemblyExceptions { public float offset; public boolean running; @@ -28,6 +25,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme protected boolean forceMove; protected ScrollOptionBehaviour movementMode; protected boolean waitingForSpeedChange; + protected AssemblyException lastException; // Custom position sync protected float clientOffsetDiff; @@ -81,7 +79,13 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme return; } else { if (getSpeed() != 0) - assemble(); + try { + assemble(); + lastException = null; + } catch (AssemblyException e) { + lastException = e; + } + sendData(); } return; } @@ -154,6 +158,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme compound.putBoolean("Running", running); compound.putBoolean("Waiting", waitingForSpeedChange); compound.putFloat("Offset", offset); + AssemblyException.write(compound, lastException); super.write(compound, clientPacket); if (clientPacket && forceMove) { @@ -170,6 +175,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme running = compound.getBoolean("Running"); waitingForSpeedChange = compound.getBoolean("Waiting"); offset = compound.getFloat("Offset"); + lastException = AssemblyException.read(compound); super.fromTag(state, compound, clientPacket); if (!clientPacket) @@ -184,9 +190,14 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme movedContraption = null; } + @Override + public AssemblyException getLastAssemblyException() { + return lastException; + } + public abstract void disassemble(); - protected abstract void assemble(); + protected abstract void assemble() throws AssemblyException; protected abstract int getExtensionRange(); @@ -289,5 +300,4 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme public BlockPos getBlockPosition() { return pos; } - } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java index a2a438226..bad6186c7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pi import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.IRotate; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot; @@ -42,7 +43,7 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { } @Override - public void assemble() { + public void assemble() throws AssemblyException { if (!(world.getBlockState(pos) .getBlock() instanceof MechanicalPistonBlock)) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java index 965bfe588..e0b12b263 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java @@ -1,7 +1,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.piston; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; import com.simibubi.create.foundation.config.AllConfigs; @@ -23,6 +24,7 @@ import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.List; +import java.util.Queue; import static com.simibubi.create.AllBlocks.MECHANICAL_PISTON_HEAD; import static com.simibubi.create.AllBlocks.PISTON_EXTENSION_POLE; @@ -51,7 +53,7 @@ public class PistonContraption extends TranslatingContraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { if (!collectExtensions(world, pos, orientation)) return false; int count = blocks.size(); @@ -66,7 +68,7 @@ public class PistonContraption extends TranslatingContraption { return true; } - private boolean collectExtensions(World world, BlockPos pos, Direction direction) { + private boolean collectExtensions(World world, BlockPos pos, Direction direction) throws AssemblyException { List poles = new ArrayList<>(); BlockPos actualStart = pos; BlockState nextBlock = world.getBlockState(actualStart.offset(direction)); @@ -89,7 +91,7 @@ public class PistonContraption extends TranslatingContraption { nextBlock = world.getBlockState(actualStart.offset(direction)); if (extensionsInFront > MechanicalPistonBlock.maxAllowedPistonPoles()) - return false; + throw AssemblyException.tooManyPistonPoles(); } } @@ -112,7 +114,7 @@ public class PistonContraption extends TranslatingContraption { nextBlock = world.getBlockState(end.offset(direction.getOpposite())); if (extensionsInFront + extensionsInBack > MechanicalPistonBlock.maxAllowedPistonPoles()) - return false; + throw AssemblyException.tooManyPistonPoles(); } anchor = pos.offset(direction, initialExtensionProgress + 1); @@ -124,7 +126,7 @@ public class PistonContraption extends TranslatingContraption { 1, 1); if (extensionLength == 0) - return false; + throw AssemblyException.noPistonPoles(); bounds = new AxisAlignedBB(0, 0, 0, 0, 0, 0); @@ -144,7 +146,7 @@ public class PistonContraption extends TranslatingContraption { } @Override - protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List frontier) { + protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, Queue frontier) throws AssemblyException { frontier.clear(); boolean sticky = isStickyPiston(world.getBlockState(pos.offset(orientation, -1))); boolean retracting = direction != orientation; @@ -154,17 +156,22 @@ public class PistonContraption extends TranslatingContraption { if (offset == 1 && retracting) return true; BlockPos currentPos = pos.offset(orientation, offset + initialExtensionProgress); - if (!world.isBlockPresent(currentPos)) - return false; - if (!BlockMovementTraits.movementNecessary(world, currentPos)) + if (retracting && World.isOutsideBuildHeight(currentPos)) return true; + if (!world.isBlockPresent(currentPos)) + throw AssemblyException.unloadedChunk(currentPos); BlockState state = world.getBlockState(currentPos); + if (!BlockMovementTraits.movementNecessary(state, world, currentPos)) + return true; if (BlockMovementTraits.isBrittle(state) && !(state.getBlock() instanceof CarpetBlock)) return true; if (isPistonHead(state) && state.get(FACING) == direction.getOpposite()) return true; - if (!BlockMovementTraits.movementAllowed(world, currentPos)) - return retracting; + if (!BlockMovementTraits.movementAllowed(state, world, currentPos)) + if (retracting) + return true; + else + throw AssemblyException.unmovableBlock(currentPos, state); if (retracting && state.getPushReaction() == PushReaction.PUSH_ONLY) return true; frontier.add(currentPos); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java index c2e302395..5dc1faf81 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java @@ -11,7 +11,6 @@ import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; -import com.simibubi.create.foundation.utility.placement.PlacementOffset; import com.simibubi.create.foundation.utility.placement.util.PoleHelper; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; @@ -21,6 +20,7 @@ import net.minecraft.block.material.PushReaction; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.FluidState; import net.minecraft.fluid.Fluids; +import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.StateContainer.Builder; @@ -119,28 +119,9 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements BlockRayTraceResult ray) { ItemStack heldItem = player.getHeldItem(hand); - if (AllBlocks.PISTON_EXTENSION_POLE.isIn(heldItem) && !player.isSneaking()) { - IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); - PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray); - - if (!offset.isReplaceable(world)) - return ActionResultType.PASS; - - offset.placeInWorld(world, AllBlocks.PISTON_EXTENSION_POLE.getDefaultState(), player, heldItem); - - /*BlockPos newPos = new BlockPos(offset.getPos()); - if (!world.getBlockState(newPos).getMaterial().isReplaceable()) - return ActionResultType.PASS; - - if (world.isRemote) - return ActionResultType.SUCCESS; - - world.setBlockState(newPos, offset.getTransform().apply(AllBlocks.PISTON_EXTENSION_POLE.getDefaultState())); - if (!player.isCreative()) - heldItem.shrink(1);*/ - - return ActionResultType.SUCCESS; - } + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (placementHelper.matchesItem(heldItem) && !player.isSneaking()) + return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java index d12cecad5..5c444e4da 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java @@ -1,5 +1,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pulley; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; @@ -23,7 +24,7 @@ public class PulleyContraption extends TranslatingContraption { } @Override - public boolean assemble(World world, BlockPos pos) { + public boolean assemble(World world, BlockPos pos) throws AssemblyException { if (!searchMovedStructure(world, pos, null)) return false; startMoving(world); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 4ac9d22f5..8eadef54a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pulley; import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; @@ -8,7 +9,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; - import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.IWaterLoggable; @@ -42,7 +42,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { } @Override - protected void assemble() { + protected void assemble() throws AssemblyException { if (!(world.getBlockState(pos) .getBlock() instanceof PulleyBlock)) return; @@ -176,9 +176,10 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { return; BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1); - if (!BlockMovementTraits.movementNecessary(world, posBelow)) + BlockState state = world.getBlockState(posBelow); + if (!BlockMovementTraits.movementNecessary(state, world, posBelow)) return; - if (BlockMovementTraits.isBrittle(world.getBlockState(posBelow))) + if (BlockMovementTraits.isBrittle(state)) return; disassemble(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java index 09be45515..259222e89 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/actors/FluidManipulationBehaviour.java @@ -200,7 +200,7 @@ public abstract class FluidManipulationBehaviour extends TileEntityBehaviour { } protected boolean canDrainInfinitely(Fluid fluid) { - return maxBlocks() != -1 && !AllFluidTags.NO_INFINITE_DRAINING.matches(fluid); + return maxBlocks() != -1; // && !AllFluidTags.NO_INFINITE_DRAINING.matches(fluid); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java index 706c797d4..288cdeaa5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/goggles/GoggleOverlayRenderer.java @@ -8,6 +8,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock; import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonExtensionPoleBlock; import com.simibubi.create.foundation.config.AllConfigs; @@ -92,6 +93,14 @@ public class GoggleOverlayRenderer { tooltip.remove(tooltip.size() - 1); } + if (te instanceof IDisplayAssemblyExceptions) { + boolean exceptionAdded = ((IDisplayAssemblyExceptions) te).addExceptionToTooltip(tooltip); + if (exceptionAdded) { + hasHoveringInformation = true; + hoverAddedInformation = true; + } + } + // break early if goggle or hover returned false when present if ((hasGoggleInformation && !goggleAddedInformation) && (hasHoveringInformation && !hoverAddedInformation)) return; diff --git a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java b/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java index 6a12fe7f8..32a54caa5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java +++ b/src/main/java/com/simibubi/create/content/contraptions/goggles/IHaveGoggleInformation.java @@ -18,8 +18,8 @@ public interface IHaveGoggleInformation { /** * this method will be called when looking at a TileEntity that implemented this interface * - * @return {{@code true}} if the tooltip creation was successful and should be displayed, - * or {{@code false}} if the overlay should not be displayed + * @return {@code true} if the tooltip creation was successful and should be displayed, + * or {@code false} if the overlay should not be displayed * */ default boolean addToGoggleTooltip(List tooltip, boolean isPlayerSneaking){ return false; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java index 8aa95d0ea..6af560170 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/GantryShaftBlock.java @@ -1,8 +1,5 @@ package com.simibubi.create.content.contraptions.relays.advanced; -import java.util.ArrayList; -import java.util.List; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; @@ -10,11 +7,17 @@ import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; - +import com.simibubi.create.foundation.utility.placement.IPlacementHelper; +import com.simibubi.create.foundation.utility.placement.PlacementHelpers; +import com.simibubi.create.foundation.utility.placement.PlacementOffset; +import com.simibubi.create.foundation.utility.placement.util.PoleHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.state.BooleanProperty; import net.minecraft.state.EnumProperty; @@ -25,8 +28,10 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; import net.minecraft.util.IStringSerializable; 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; @@ -34,11 +39,17 @@ import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + public class GantryShaftBlock extends DirectionalKineticBlock { public static final Property PART = EnumProperty.create("part", Part.class); public static final BooleanProperty POWERED = BlockStateProperties.POWERED; + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + public enum Part implements IStringSerializable { START, MIDDLE, END, SINGLE; @@ -53,6 +64,17 @@ public class GantryShaftBlock extends DirectionalKineticBlock { super.fillStateContainer(builder.add(PART, POWERED)); } + @Override + public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) { + ItemStack heldItem = player.getHeldItem(hand); + + IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); + if (!placementHelper.matchesItem(heldItem)) + return ActionResultType.PASS; + + return placementHelper.getOffset(world, state, pos, ray).placeInWorld(world, ((BlockItem) heldItem.getItem()), player, hand, ray); + } + @Override public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_, ISelectionContext p_220053_4_) { @@ -237,4 +259,27 @@ public class GantryShaftBlock extends DirectionalKineticBlock { && oldState.get(POWERED) == newState.get(POWERED); } + public static class PlacementHelper extends PoleHelper { + + public PlacementHelper() { + super(AllBlocks.GANTRY_SHAFT::has, s -> s.get(FACING) + .getAxis(), FACING); + } + + @Override + public Predicate getItemPredicate() { + return AllBlocks.GANTRY_SHAFT::isIn; + } + + @Override + public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + PlacementOffset offset = super.getOffset(world, state, pos, ray); + if (!offset.isSuccessful()) + return offset; + return PlacementOffset.success(offset.getPos(), offset.getTransform() + .andThen(s -> s.with(POWERED, state.get(POWERED)))); + } + + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java index 5d9071e98..8d15808c4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java @@ -1,7 +1,5 @@ package com.simibubi.create.content.contraptions.relays.advanced; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; @@ -13,11 +11,11 @@ import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -32,6 +30,8 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import java.util.function.Predicate; + public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements ITE { private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); @@ -67,19 +67,10 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) { - IPlacementHelper helper = PlacementHelpers.get(placementHelperId); ItemStack heldItem = player.getHeldItem(hand); - if (helper.matchesItem(heldItem)) { - PlacementOffset offset = helper.getOffset(world, state, pos, ray); - - if (!offset.isReplaceable(world)) - return ActionResultType.PASS; - - offset.placeInWorld(world, AllBlocks.LARGE_COGWHEEL.getDefaultState(), player, heldItem); - - return ActionResultType.SUCCESS; - - } + IPlacementHelper helper = PlacementHelpers.get(placementHelperId); + if (helper.matchesItem(heldItem)) + return helper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java index 0a61745ea..74cd06850 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java @@ -1,10 +1,5 @@ package com.simibubi.create.content.contraptions.relays.elementary; -import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; - -import java.util.List; -import java.util.function.Predicate; - import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; @@ -16,13 +11,13 @@ import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; - import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; @@ -31,6 +26,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; +import java.util.List; +import java.util.function.Predicate; + +import static com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock.AXIS; + public class CogwheelBlockItem extends BlockItem { boolean large; @@ -47,49 +47,27 @@ public class CogwheelBlockItem extends BlockItem { } @Override - public ActionResultType tryPlace(BlockItemUseContext context) { + public ActionResultType onItemUseFirst(ItemStack stack, ItemUseContext context) { World world = context.getWorld(); - BlockPos pos = context.getPos() - .offset(context.getFace() - .getOpposite()); + BlockPos pos = context.getPos(); BlockState state = world.getBlockState(pos); IPlacementHelper helper = PlacementHelpers.get(placementHelperId); PlayerEntity player = context.getPlayer(); - - if (helper.matchesState(state)) { - PlacementOffset offset = helper.getOffset(world, state, pos, - new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true)); - - if (!offset.isReplaceable(world)) - return super.tryPlace(context); - - offset.placeInWorld(world, this, player, context.getItem()); - triggerShiftingGearsAdvancement(world, new BlockPos(offset.getPos()), offset.getTransform() - .apply(getBlock().getDefaultState()), player); - - return ActionResultType.SUCCESS; + BlockRayTraceResult ray = new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true); + if (helper.matchesState(state) && player != null && !player.isSneaking()) { + return helper.getOffset(world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); } if (integratedCogHelperId != -1) { helper = PlacementHelpers.get(integratedCogHelperId); - if (helper.matchesState(state)) { - PlacementOffset offset = helper.getOffset(world, state, pos, - new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true)); - - if (!offset.isReplaceable(world)) - return super.tryPlace(context); - - offset.placeInWorld(world, this, player, context.getItem()); - triggerShiftingGearsAdvancement(world, new BlockPos(offset.getPos()), offset.getTransform() - .apply(getBlock().getDefaultState()), player); - - return ActionResultType.SUCCESS; + if (helper.matchesState(state) && player != null && !player.isSneaking()) { + return helper.getOffset(world, state, pos, ray).placeInWorld(world, this, player, context.getHand(), ray); } } - return super.tryPlace(context); + return super.onItemUseFirst(stack, context); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java index f1094dcc0..d68c293f0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java @@ -7,7 +7,6 @@ import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; -import com.simibubi.create.foundation.utility.placement.PlacementOffset; import com.simibubi.create.foundation.utility.placement.util.PoleHelper; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; @@ -77,26 +76,8 @@ public class ShaftBlock extends AbstractShaftBlock { } IPlacementHelper helper = PlacementHelpers.get(placementHelperId); - if (helper.getItemPredicate().test(heldItem)) { - PlacementOffset offset = helper.getOffset(world, state, pos, ray); - - if (!offset.isReplaceable(world)) - return ActionResultType.PASS; - - offset.placeInWorld(world, (BlockItem) heldItem.getItem(), player, heldItem); - - /*BlockPos newPos = new BlockPos(offset.getPos()); - - if (world.isRemote) - return ActionResultType.SUCCESS; - - Block block = ((BlockItem) heldItem.getItem()).getBlock(); - world.setBlockState(newPos, offset.getTransform().apply(block.getDefaultState())); - if (!player.isCreative()) - heldItem.shrink(1);*/ - - return ActionResultType.SUCCESS; - } + if (helper.matchesItem(heldItem)) + return helper.getOffset(world, state, pos, ray).placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray); return ActionResultType.PASS; } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index fe1ec78cf..cf36c3c7a 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -1,25 +1,42 @@ package com.simibubi.create.foundation.command; import com.mojang.brigadier.CommandDispatcher; - +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; +import net.minecraft.entity.player.PlayerEntity; + +import java.util.Collections; +import java.util.function.Predicate; public class AllCommands { - public static void register(CommandDispatcher dispatcher) { - dispatcher.register(Commands.literal("create") - //general purpose - .then(ToggleDebugCommand.register()) - .then(OverlayConfigCommand.register()) - .then(FixLightingCommand.register()) - .then(ReplaceInCommandBlocksCommand.register()) + public static Predicate sourceIsPlayer = (cs) -> cs.getEntity() instanceof PlayerEntity; - //dev-util - //Comment out for release - .then(ClearBufferCacheCommand.register()) - .then(ChunkUtilCommand.register()) -// .then(KillTPSCommand.register()) + public static void register(CommandDispatcher dispatcher) { + + LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") + //general purpose + .then(ToggleDebugCommand.register()) + .then(OverlayConfigCommand.register()) + .then(FixLightingCommand.register()) + .then(ReplaceInCommandBlocksCommand.register()) + .then(HighlightCommand.register()) + + //dev-util + //Comment out for release + .then(ClearBufferCacheCommand.register()) + .then(ChunkUtilCommand.register()) + //.then(KillTPSCommand.register()) + ); + + CommandNode c = dispatcher.findNode(Collections.singleton("c")); + if (c != null) + return; + + dispatcher.register(Commands.literal("c") + .redirect(createRoot) ); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/HighlightCommand.java b/src/main/java/com/simibubi/create/foundation/command/HighlightCommand.java new file mode 100644 index 000000000..6071c14f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/HighlightCommand.java @@ -0,0 +1,103 @@ +package com.simibubi.create.foundation.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; +import com.simibubi.create.content.contraptions.components.structureMovement.IDisplayAssemblyExceptions; +import com.simibubi.create.foundation.networking.AllPackets; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.BlockPosArgument; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.*; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.PacketDistributor; + +import java.util.Collection; + +public class HighlightCommand { + + public static ArgumentBuilder register() { + return Commands.literal("highlight") + .requires(cs -> cs.hasPermissionLevel(0)) + .requires(AllCommands.sourceIsPlayer) + .then(Commands.argument("pos", BlockPosArgument.blockPos()) + .requires(AllCommands.sourceIsPlayer) + .executes(ctx -> { + BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, "pos"); + + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), + new HighlightPacket(pos) + ); + + return Command.SINGLE_SUCCESS; + }) + .then(Commands.argument("players", EntityArgument.players()) + .executes(ctx -> { + Collection players = EntityArgument.getPlayers(ctx, "players"); + BlockPos pos = BlockPosArgument.getBlockPos(ctx, "pos"); + + for (ServerPlayerEntity p : players) { + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> p), + new HighlightPacket(pos) + ); + } + + return players.size(); + }) + ) + ) + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + return highlightAssemblyExceptionFor(player, ctx.getSource()); + }); + + } + + private static void sendMissMessage(CommandSource source) { + source.sendFeedback(new StringTextComponent("Try looking at a Block that has failed to assemble a Contraption and try again."), true); + } + + private static int highlightAssemblyExceptionFor(ServerPlayerEntity player, CommandSource source) { + double distance = player.getAttribute(PlayerEntity.REACH_DISTANCE).getValue(); + Vec3d start = player.getEyePosition(1); + Vec3d look = player.getLook(1); + Vec3d end = start.add(look.x * distance, look.y * distance, look.z * distance); + World world = player.world; + + BlockRayTraceResult ray = world.rayTraceBlocks(new RayTraceContext(start, end, RayTraceContext.BlockMode.OUTLINE, RayTraceContext.FluidMode.NONE, player)); + if (ray.getType() == RayTraceResult.Type.MISS) { + sendMissMessage(source); + return 0; + } + + BlockPos pos = ray.getPos(); + TileEntity te = world.getTileEntity(pos); + if (!(te instanceof IDisplayAssemblyExceptions)) { + sendMissMessage(source); + return 0; + } + + IDisplayAssemblyExceptions display = (IDisplayAssemblyExceptions) te; + AssemblyException exception = display.getLastAssemblyException(); + if (exception == null) { + sendMissMessage(source); + return 0; + } + + if (!exception.hasPosition()) { + source.sendFeedback(new StringTextComponent("Can't highlight a specific position for this issue"), true); + return Command.SINGLE_SUCCESS; + } + + BlockPos p = exception.getPosition(); + String command = "/create highlight " + p.getX() + " " + p.getY() + " " + p.getZ(); + return player.server.getCommandManager().handleCommand(source, command); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/command/HighlightPacket.java b/src/main/java/com/simibubi/create/foundation/command/HighlightPacket.java new file mode 100644 index 000000000..7b4b10a4c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/HighlightPacket.java @@ -0,0 +1,55 @@ +package com.simibubi.create.foundation.command; + +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.networking.SimplePacketBase; +import net.minecraft.client.Minecraft; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.VoxelShapes; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class HighlightPacket extends SimplePacketBase { + + private final BlockPos pos; + + public HighlightPacket(BlockPos pos) { + this.pos = pos; + } + + public HighlightPacket(PacketBuffer buffer) { + this.pos = BlockPos.fromLong(buffer.readLong()); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeLong(pos.toLong()); + } + + @Override + public void handle(Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + performHighlight(pos); + })); + + ctx.get().setPacketHandled(true); + } + + @OnlyIn(Dist.CLIENT) + public static void performHighlight(BlockPos pos) { + if (Minecraft.getInstance().world == null || !Minecraft.getInstance().world.isBlockPresent(pos)) + return; + + CreateClient.outliner.showAABB("highlightCommand", VoxelShapes.fullCube().getBoundingBox().offset(pos), 200) + .lineWidth(1 / 32f) + .colored(0xEeEeEe) + //.colored(0x243B50) + .withFaceTexture(AllSpecialTextures.SELECTION); + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 903e55fb8..355a01536 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -1,19 +1,11 @@ package com.simibubi.create.foundation.networking; -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Supplier; - import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionDisassemblyPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket; import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionUpdatePacket; import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueEffectPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionFluidPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.LimbSwingUpdatePacket; +import com.simibubi.create.content.contraptions.components.structureMovement.sync.*; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingCreationPacket; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartControllerUpdatePacket; import com.simibubi.create.content.contraptions.fluids.actors.FluidSplashPacket; @@ -25,16 +17,12 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmPlacementPac import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket; import com.simibubi.create.content.logistics.packet.ConfigureFlexcratePacket; import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; -import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket; -import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; -import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; -import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; -import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; +import com.simibubi.create.content.schematics.packet.*; import com.simibubi.create.foundation.command.ConfigureConfigPacket; +import com.simibubi.create.foundation.command.HighlightPacket; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket; import com.simibubi.create.foundation.utility.ServerSpeedProvider; - import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -46,8 +34,12 @@ import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.network.PacketDistributor.TargetPoint; import net.minecraftforge.fml.network.simple.SimpleChannel; -import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_SERVER; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_CLIENT; +import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_SERVER; public enum AllPackets { @@ -85,6 +77,7 @@ public enum AllPackets { FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new, PLAY_TO_CLIENT), CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new, PLAY_TO_CLIENT), GANTRY_UPDATE(GantryContraptionUpdatePacket.class, GantryContraptionUpdatePacket::new, PLAY_TO_CLIENT), + BLOCK_HIGHLIGHT(HighlightPacket.class, HighlightPacket::new, PLAY_TO_CLIENT) ; diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java index e531931bb..1b60a8796 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java @@ -1,24 +1,18 @@ package com.simibubi.create.foundation.utility.outliner; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox; import com.simibubi.create.foundation.utility.outliner.LineOutline.EndChasingLineOutline; import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; - import net.minecraft.client.Minecraft; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; +import java.util.*; + public class Outliner { final Map outlines; @@ -57,6 +51,13 @@ public class Outliner { return entry.outline.getParams(); } + public OutlineParams showAABB(Object slot, AxisAlignedBB bb, int ttl) { + createAABBOutlineIfMissing(slot, bb); + ChasingAABBOutline outline = getAndRefreshAABB(slot, ttl); + outline.prevBB = outline.targetBB = bb; + return outline.getParams(); + } + public OutlineParams showAABB(Object slot, AxisAlignedBB bb) { createAABBOutlineIfMissing(slot, bb); ChasingAABBOutline outline = getAndRefreshAABB(slot); @@ -112,6 +113,12 @@ public class Outliner { return (ChasingAABBOutline) entry.getOutline(); } + private ChasingAABBOutline getAndRefreshAABB(Object slot, int ttl) { + OutlineEntry entry = outlines.get(slot); + entry.ticksTillRemoval = ttl; + return (ChasingAABBOutline) entry.getOutline(); + } + // Maintenance public Outliner() { diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java index 888da89c3..c8cc88c2c 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java @@ -6,6 +6,7 @@ import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.VecHelper; import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -22,6 +23,11 @@ import java.util.stream.Collectors; @MethodsReturnNonnullByDefault public interface IPlacementHelper { + /** + * used as an identifier in SuperGlueHandler to skip blocks placed by helpers + */ + BlockState ID = new BlockState(Blocks.AIR, null, null); + /** * @return a predicate that gets tested with the items held in the players hands, * should return true if this placement helper is active with the given item @@ -61,24 +67,6 @@ public interface IPlacementHelper { CreateClient.outliner.showLine("placementArrowB" + center + target, start.add(offset), endB.add(offset)).lineWidth(1/16f); } - /*@OnlyIn(Dist.CLIENT) - static void renderArrow(Vec3d center, Direction towards, BlockRayTraceResult ray) { - Direction hitFace = ray.getFace(); - - if (hitFace.getAxis() == towards.getAxis()) - return; - - //get the two perpendicular directions to form the arrow - Direction[] directions = Arrays.stream(Direction.Axis.values()).filter(axis -> axis != hitFace.getAxis() && axis != towards.getAxis()).map(Iterate::directionsInAxis).findFirst().orElse(new Direction[]{}); - Vec3d startOffset = new Vec3d(towards.getDirectionVec()); - Vec3d start = center.add(startOffset); - for (Direction dir : directions) { - Vec3d arrowOffset = new Vec3d(dir.getDirectionVec()).scale(.25); - Vec3d target = center.add(startOffset.scale(0.75)).add(arrowOffset); - CreateClient.outliner.showLine("placementArrow" + towards + dir, start, target).lineWidth(1/16f); - } - }*/ - static List orderedByDistanceOnlyAxis(BlockPos pos, Vector3d hit, Direction.Axis axis) { return orderedByDistance(pos, hit, dir -> dir.getAxis() == axis); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java index 5025975f9..d360740a8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java @@ -1,15 +1,26 @@ package com.simibubi.create.foundation.utility.placement; +import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.block.BlockState; import net.minecraft.fluid.FluidState; import net.minecraft.util.math.vector.Vector3i; +import net.minecraft.block.SoundType; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.fluid.Fluids; import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.stats.Stats; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.event.world.BlockEvent; import java.util.function.Function; @@ -55,25 +66,49 @@ public class PlacementOffset { return world.getBlockState(new BlockPos(pos)).getMaterial().isReplaceable(); } - - public void placeInWorld(World world, BlockItem blockItem, PlayerEntity player, ItemStack item) { - placeInWorld(world, blockItem.getBlock().getDefaultState(), player, item); - } - public void placeInWorld(World world, BlockState defaultState, PlayerEntity player, ItemStack item) { - if (world.isRemote) - return; + public ActionResultType placeInWorld(World world, BlockItem blockItem, PlayerEntity player, Hand hand, BlockRayTraceResult ray) { + + ItemUseContext context = new ItemUseContext(player, hand, ray); BlockPos newPos = new BlockPos(pos); - BlockState state = stateTransform.apply(defaultState); + + if (!world.isBlockModifiable(player, newPos)) + return ActionResultType.PASS; + + if (!isReplaceable(world)) + return ActionResultType.PASS; + + BlockState state = stateTransform.apply(blockItem.getBlock().getDefaultState()); if (state.contains(BlockStateProperties.WATERLOGGED)) { FluidState fluidState = world.getFluidState(newPos); state = state.with(BlockStateProperties.WATERLOGGED, fluidState.getFluid() == Fluids.WATER); } + BlockSnapshot snapshot = BlockSnapshot.create(world.getRegistryKey(), world, newPos); world.setBlockState(newPos, state); + BlockEvent.EntityPlaceEvent event = new BlockEvent.EntityPlaceEvent(snapshot, IPlacementHelper.ID, player); + if (MinecraftForge.EVENT_BUS.post(event)) { + snapshot.restore(true, false); + return ActionResultType.FAIL; + } + + BlockState newState = world.getBlockState(newPos); + SoundType soundtype = newState.getSoundType(world, newPos, player); + world.playSound(player, newPos, soundtype.getPlaceSound(), SoundCategory.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); + + player.addStat(Stats.ITEM_USED.get(blockItem)); + + if (world.isRemote) + return ActionResultType.SUCCESS; + + if (player instanceof ServerPlayerEntity) + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayerEntity) player, newPos, context.getItem()); + if (!player.isCreative()) - item.shrink(1); + context.getItem().shrink(1); + + return ActionResultType.SUCCESS; } } diff --git a/src/main/resources/assets/create/lang/default/messages.json b/src/main/resources/assets/create/lang/default/messages.json index 57fbc9b7e..94af8ae4d 100644 --- a/src/main/resources/assets/create/lang/default/messages.json +++ b/src/main/resources/assets/create/lang/default/messages.json @@ -172,6 +172,13 @@ "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.pole_length": "Pole Length:", + "create.gui.assembly.exception": "This Contraption was unable to assemble:", + "create.gui.assembly.exception.unmovableBlock": "Unmovable Block (%4$s) at [%1$s %2$s %3$s]", + "create.gui.assembly.exception.chunkNotLoaded": "The Block at [%1$s %2$s %3$s] was not in a loaded chunk", + "create.gui.assembly.exception.structureTooLarge": "There are too many Blocks included in the contraption.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.tooManyPistonPoles": "There are too many extension Poles attached to this Piston.\nThe configured maximum is: %1$s", + "create.gui.assembly.exception.noPistonPoles": "The Piston is missing some extension Poles", + "create.gui.gauge.info_header": "Gauge Information:", "create.gui.speedometer.title": "Rotation Speed", "create.gui.stressometer.title": "Network Stress",