Pushing the Pusher

- Ore features no longer spawn in the "void" or "hell" biome
- Fixed Minecart contraptions killing their own mount using saws/drills
- Pistons, Bearings and Pulleys can now be moved unless they are moving something themselves
- Fixed cart assemblers blocking in the powered rail kickstart logic
- Piston poles can now be moved
- Crushing wheels no longer spawn missing texture particles when sprinting on the central block
- Deployers' hand items can now be directly inserted/extracted using hoppers, extractors, funnels, etc
- Fixed Deployers not dropping held items when destroyed
- Millstones now empty their input inventory when clicked on while their output buffer is empty
- Millstones no longer accept items they cannot process
- Fixed hoppers not being able to pull items from belts in certain cases
- Fixed adjustable crates corrupting chunks
This commit is contained in:
simibubi 2020-04-09 21:29:51 +02:00
parent e2742f6fb2
commit 72ddc1251a
19 changed files with 312 additions and 31 deletions

View file

@ -12,6 +12,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.registries.ForgeRegistries;
@ -33,8 +34,9 @@ public enum AllWorldFeatures {
;
/**
* Increment this number if all worldgen entries should be overwritten in this update.
* Worlds from the previous version will overwrite potentially changed values with the new defaults.
* Increment this number if all worldgen entries should be overwritten in this
* update. Worlds from the previous version will overwrite potentially changed
* values with the new defaults.
*/
public static final int forcedUpdateVersion = 1;
@ -51,9 +53,13 @@ public enum AllWorldFeatures {
for (AllWorldFeatures entry : AllWorldFeatures.values()) {
for (Biome biome : ForgeRegistries.BIOMES) {
if (biome == Biomes.THE_VOID)
continue;
if (biome == Biomes.NETHER)
continue;
if (entry.featureInstances.containsKey(biome))
biome.getFeatures(entry.feature.getGenerationStage()).remove(entry.featureInstances.remove(biome));
Optional<ConfiguredFeature<?>> createFeature = entry.feature.createFeature(biome);
if (!createFeature.isPresent())
continue;

View file

@ -1,12 +1,14 @@
package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.DamageSource;
@ -37,8 +39,17 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
if (damageSource == null)
return;
for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) {
if (entity instanceof ItemEntity)
return;
if (entity instanceof ContraptionEntity)
return;
if (entity instanceof AbstractMinecartEntity)
for (Entity passenger : entity.getRecursivePassengers())
if (passenger instanceof ContraptionEntity
&& ((ContraptionEntity) passenger).getContraption() == context.contraption)
return;
float damage = (float) MathHelper.clamp(Math.abs(context.relativeMotion.length() * 10) + 1, 5, 20);
entity.attackEntityFrom(damageSource, damage);
entity.setMotion(entity.getMotion().add(context.relativeMotion.scale(3)));

View file

@ -3,7 +3,15 @@ package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock;
import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyTileEntity;
import com.simibubi.create.modules.logistics.block.AttachedLogisticalBlock;
import com.simibubi.create.modules.logistics.block.RedstoneLinkBlock;
import com.simibubi.create.modules.logistics.block.extractor.ExtractorBlock;
@ -28,6 +36,7 @@ import net.minecraft.block.WallTorchBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.state.properties.AttachFace;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@ -56,6 +65,26 @@ public class BlockMovementTraits {
return false;
if (block == Blocks.OBSIDIAN)
return false;
// Move controllers only when they aren't moving
if (block instanceof MechanicalPistonBlock && blockState.get(MechanicalPistonBlock.STATE) != PistonState.MOVING)
return true;
if (block instanceof MechanicalBearingBlock) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof MechanicalBearingTileEntity)
return !((MechanicalBearingTileEntity) te).isRunning();
}
if (block instanceof ClockworkBearingBlock) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof ClockworkBearingTileEntity)
return !((ClockworkBearingTileEntity) te).isRunning();
}
if (block instanceof PulleyBlock) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof PulleyTileEntity)
return !((PulleyTileEntity) te).running && ((PulleyTileEntity) te).offset == 0;
}
if (AllBlocks.BELT.typeOf(blockState))
return true;
if (block instanceof ExtractorBlock)
@ -161,14 +190,4 @@ public class BlockMovementTraits {
return isBrittle(state);
}
public static boolean movementIgnored(BlockState state) {
if (AllBlocks.MECHANICAL_PISTON.typeOf(state))
return true;
if (AllBlocks.STICKY_MECHANICAL_PISTON.typeOf(state))
return true;
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state))
return true;
return false;
}
}

View file

@ -25,6 +25,10 @@ import com.simibubi.create.foundation.utility.WrappedWorld;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonPoleBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonHeadBlock;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import com.simibubi.create.modules.contraptions.redstone.ContactBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
@ -160,6 +164,49 @@ public abstract class Contraption {
if (prevPos != null && !visited.contains(prevPos))
frontier.add(prevPos);
}
if (state.getBlock() instanceof MechanicalPistonBlock) {
int limit = AllConfigs.SERVER.kinetics.maxPistonPoles.get();
Direction direction = state.get(MechanicalPistonBlock.FACING);
if (state.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) {
BlockPos searchPos = pos;
while (limit-- >= 0) {
searchPos = searchPos.offset(direction);
BlockState blockState = world.getBlockState(searchPos);
if (AllBlocks.PISTON_POLE.typeOf(blockState)) {
if (blockState.get(PistonPoleBlock.FACING).getAxis() != direction.getAxis())
break;
if (!visited.contains(searchPos))
frontier.add(searchPos);
continue;
}
if (blockState.getBlock() instanceof MechanicalPistonHeadBlock)
if (!visited.contains(searchPos))
frontier.add(searchPos);
break;
}
if (limit <= -1)
return false;
}
BlockPos searchPos = pos;
while (limit-- >= 0) {
searchPos = searchPos.offset(direction.getOpposite());
BlockState blockState = world.getBlockState(searchPos);
if (AllBlocks.PISTON_POLE.typeOf(blockState)) {
if (blockState.get(PistonPoleBlock.FACING).getAxis() != direction.getAxis())
break;
if (!visited.contains(searchPos))
frontier.add(searchPos);
continue;
}
break;
}
if (limit <= -1)
return false;
}
if (state.getBlock() instanceof DoorBlock) {
BlockPos otherPartPos = pos.up(state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? 1 : -1);
if (!visited.contains(otherPartPos))
@ -170,7 +217,7 @@ public abstract class Contraption {
for (Direction offset : Direction.values()) {
BlockPos offsetPos = pos.offset(offset);
BlockState blockState = world.getBlockState(offsetPos);
if (BlockMovementTraits.movementIgnored(blockState))
if (isAnchoringBlockAt(offsetPos))
continue;
if (!BlockMovementTraits.movementAllowed(world, offsetPos)) {
if (offset == forcedDirection && isSlimeBlock)
@ -188,6 +235,10 @@ public abstract class Contraption {
return true;
}
protected boolean isAnchoringBlockAt(BlockPos pos) {
return pos.equals(anchor);
}
protected static boolean isChassis(BlockState state) {
return state.getBlock() instanceof AbstractChassisBlock;
}

View file

@ -299,4 +299,8 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
return this.minuteHand == contraption;
}
public boolean isRunning() {
return running;
}
}

View file

@ -299,4 +299,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
return movedContraption == contraption;
}
public boolean isRunning() {
return running;
}
}

View file

@ -130,6 +130,11 @@ public class CartAssemblerBlock extends AbstractRailBlock {
return PushReaction.BLOCK;
}
@Override
public boolean isNormalCube(BlockState state, IBlockReader worldIn, BlockPos pos) {
return false;
}
public static class MinecartAnchorBlock extends RenderUtilityBlock {
@Override

View file

@ -9,6 +9,7 @@ import com.simibubi.create.modules.contraptions.components.contraptions.piston.M
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.EnumProperty;
@ -37,6 +38,11 @@ public class MechanicalPistonHeadBlock extends ProperDirectionalBlock implements
super.fillStateContainer(builder);
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
PlayerEntity player) {

View file

@ -7,6 +7,7 @@ import com.simibubi.create.modules.contraptions.components.contraptions.piston.M
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.properties.BlockStateProperties;
@ -26,6 +27,11 @@ public class PistonPoleBlock extends ProperDirectionalBlock {
setDefaultState(getDefaultState().with(FACING, Direction.UP));
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
public void onBlockHarvested(World worldIn, BlockPos pos, BlockState state, PlayerEntity player) {
Axis axis = state.get(FACING).getAxis();

View file

@ -30,6 +30,11 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
return super.getRenderBoundingBox().expand(0, -offset, 0);
}
@Override
public double getMaxRenderDistanceSquared() {
return super.getMaxRenderDistanceSquared() + offset * offset;
}
@Override
protected void assemble() {
if (speed == 0)
@ -151,7 +156,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
@Override
protected int getExtensionRange() {
return Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), pos.getY() - 1);
return Math.max(0, Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), pos.getY() - 1));
}
@Override

View file

@ -53,6 +53,11 @@ public class CrushingWheelControllerBlock extends Block
return false;
}
@Override
public boolean addRunningEffects(BlockState state, World world, BlockPos pos, Entity entity) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new CrushingWheelControllerTileEntity();

View file

@ -0,0 +1,104 @@
package com.simibubi.create.modules.contraptions.components.deployer;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
public class DeployerItemHandler implements IItemHandlerModifiable {
private DeployerTileEntity te;
private DeployerFakePlayer player;
public DeployerItemHandler(DeployerTileEntity te) {
this.te = te;
this.player = te.player;
}
@Override
public int getSlots() {
return 1;
}
@Override
public ItemStack getStackInSlot(int slot) {
return getHeld();
}
public ItemStack getHeld() {
if (player == null)
return ItemStack.EMPTY;
return player.getHeldItemMainhand();
}
public void set(ItemStack stack) {
if (player == null)
return;
if (te.getWorld().isRemote)
return;
player.setHeldItem(Hand.MAIN_HAND, stack);
te.markDirty();
te.sendData();
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
ItemStack held = getHeld();
if (!isItemValid(slot, stack))
return stack;
if (held.isEmpty()) {
if (!simulate)
set(stack);
return ItemStack.EMPTY;
}
if (!ItemHandlerHelper.canItemStacksStack(held, stack))
return stack;
int space = held.getMaxStackSize() - held.getCount();
ItemStack split = stack.copy().split(space);
if (space == 0)
return stack;
if (!simulate) {
held = held.copy();
held.setCount(held.getCount() + split.getCount());
set(held);
}
return split;
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
ItemStack held = getHeld();
if (amount == 0 || held.isEmpty())
return ItemStack.EMPTY;
if (simulate)
return held.copy().split(amount);
ItemStack toReturn = held.split(amount);
te.markDirty();
te.sendData();
return toReturn;
}
@Override
public int getSlotLimit(int slot) {
return Math.min(getHeld().getMaxStackSize(), 64);
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE);
return filteringBehaviour == null || filteringBehaviour.test(stack);
}
@Override
public void setStackInSlot(int slot, ItemStack stack) {
set(stack);
}
}

View file

@ -41,8 +41,12 @@ import net.minecraft.util.math.RayTraceContext.BlockMode;
import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
public class DeployerTileEntity extends KineticTileEntity {
@ -61,6 +65,7 @@ public class DeployerTileEntity extends KineticTileEntity {
protected boolean boop = false;
protected List<ItemStack> overflowItems = new ArrayList<>();
private ListNBT deferredInventoryList;
private LazyOptional<IItemHandlerModifiable> invHandler;
enum State {
WAITING, EXPANDING, RETRACTING, DUMPING;
@ -98,7 +103,10 @@ public class DeployerTileEntity extends KineticTileEntity {
heldItem = player.getHeldItemMainhand();
sendData();
}
Vec3d initialPos = VecHelper.getCenterOf(pos.offset(getBlockState().get(FACING)));
player.setPosition(initialPos.x, initialPos.y, initialPos.z);
}
invHandler = LazyOptional.of(this::createHandler);
}
protected void onExtract(ItemStack stack) {
@ -372,6 +380,10 @@ public class DeployerTileEntity extends KineticTileEntity {
super.readClientUpdate(tag);
}
private IItemHandlerModifiable createHandler() {
return new DeployerItemHandler(this);
}
@Override
public boolean hasFastRenderer() {
return false;
@ -387,15 +399,24 @@ public class DeployerTileEntity extends KineticTileEntity {
return super.getRenderBoundingBox().grow(3);
}
@Override
public void remove() {
super.remove();
invHandler.invalidate();
}
public void changeMode() {
eject();
mode = mode == Mode.PUNCH ? Mode.USE : Mode.PUNCH;
markDirty();
sendData();
}
protected void eject() {
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && invHandler != null) {
return invHandler.cast();
}
return super.getCapability(cap, side);
}
}

View file

@ -64,11 +64,24 @@ public class MillstoneBlock extends KineticBlock implements ITE<MillstoneTileEnt
return true;
withTileEntityDo(worldIn, pos, millstone -> {
boolean emptyOutput = true;
IItemHandlerModifiable inv = millstone.outputInv;
for (int slot = 0; slot < inv.getSlots(); slot++) {
ItemStack stackInSlot = inv.getStackInSlot(slot);
if (!stackInSlot.isEmpty())
emptyOutput = false;
player.inventory.placeItemBackInInventory(worldIn, stackInSlot);
inv.setStackInSlot(slot, ItemStack.EMPTY);
}
if (emptyOutput) {
inv = millstone.inputInv;
for (int slot = 0; slot < inv.getSlots(); slot++) {
player.inventory.placeItemBackInInventory(worldIn, inv.getStackInSlot(slot));
inv.setStackInSlot(slot, ItemStack.EMPTY);
}
}
millstone.markDirty();
millstone.sendData();
});

View file

@ -142,6 +142,16 @@ public class MillstoneTileEntity extends KineticTileEntity {
return super.getCapability(cap, side);
}
private boolean canProcess(ItemStack stack) {
ItemStackHandler tester = new ItemStackHandler(1);
tester.setStackInSlot(0, stack);
RecipeWrapper inventoryIn = new RecipeWrapper(tester);
if (lastRecipe != null && lastRecipe.matches(inventoryIn, world))
return true;
return world.getRecipeManager().getRecipe(AllRecipes.MILLING.getType(), inventoryIn, world).isPresent();
}
private class MillstoneInventoryHandler extends CombinedInvWrapper {
public MillstoneInventoryHandler() {
@ -152,13 +162,15 @@ public class MillstoneTileEntity extends KineticTileEntity {
public boolean isItemValid(int slot, ItemStack stack) {
if (outputInv == getHandlerFromIndex(getIndexForSlot(slot)))
return false;
return super.isItemValid(slot, stack);
return canProcess(stack) && super.isItemValid(slot, stack);
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (outputInv == getHandlerFromIndex(getIndexForSlot(slot)))
return stack;
if (!isItemValid(slot, stack))
return stack;
return super.insertItem(slot, stack, simulate);
}

View file

@ -379,7 +379,7 @@ public class BeltInventory {
float max = offset + .5f + (SEGMENT_WINDOW / 2);
for (TransportedItemStack stack : getItems()) {
if (stack.beltPosition > max)
break;
continue;
if (stack.beltPosition > min)
return stack;
}

View file

@ -6,14 +6,15 @@ import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.linked.LinkBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
@ -97,9 +98,13 @@ public class RedstoneLinkTileEntity extends SmartTileEntity {
return;
if (world.isRemote)
return;
if (receivedSignal != getBlockState().get(POWERED)) {
world.setBlockState(pos, getBlockState().cycle(POWERED));
Direction attachedFace = getBlockState().get(BlockStateProperties.FACING).getOpposite();
BlockState blockState = getBlockState();
if (!AllBlocks.REDSTONE_BRIDGE.typeOf(blockState))
return;
if (receivedSignal != blockState.get(POWERED)) {
world.setBlockState(pos, blockState.cycle(POWERED));
Direction attachedFace = blockState.get(RedstoneLinkBlock.FACING).getOpposite();
BlockPos attachedPos = pos.offset(attachedFace);
world.notifyNeighbors(attachedPos, world.getBlockState(attachedPos).getBlock());
return;

View file

@ -86,11 +86,15 @@ public class FlexcrateTileEntity extends SyncedTileEntity implements INamedConta
}
public FlexcrateTileEntity getMainCrate() {
if (isDoubleCrate() && getFacing().getAxisDirection() == AxisDirection.NEGATIVE)
if (isSecondaryCrate())
return getOtherCrate();
return this;
}
public boolean isSecondaryCrate() {
return isDoubleCrate() && getFacing().getAxisDirection() == AxisDirection.NEGATIVE;
}
public FlexcrateTileEntity getOtherCrate() {
if (!AllBlocks.FLEXCRATE.typeOf(getBlockState()))
return null;
@ -158,7 +162,7 @@ public class FlexcrateTileEntity extends SyncedTileEntity implements INamedConta
@Override
public CompoundNBT write(CompoundNBT compound) {
if (getMainCrate() == this) {
if (!isSecondaryCrate()) {
compound.putBoolean("Main", true);
compound.putInt("AllowedAmount", allowedAmount);
compound.put("Inventory", inventory.serializeNBT());