Portable Belts

- Belts can now be moved and rotated by a contraption, holding on to its items if possible.
- Fixed belts not transporting entities when moving at less than 32 rpm
- Fixed belt initialization to allow migration old belts and re-initialization of moved belts
- Added a little in-world tooltip for kinetic blocks rotating below their required speed level
- Fixed kinetic tileentities keeping their previous speed when animated in a contraption
- Fixed motors not trying to overpower a network when directly attached on placement
- Belts now spawn a reasonable amount of particles when broken
- Coloured belts now spawn coloured particles when broken
- Fixed belts segments dropping too many connectors when not broken by a player
- Fixed falldamage being applied after an entity has left the belt it fell upon
- Fixed belt voxelshapes not being cached properly, leading to some bad performance hit when broken or looked at
- Fixed blazing tools not always smelting mob drops
This commit is contained in:
simibubi 2020-03-10 16:34:04 +01:00
parent 59e9a76e49
commit 8c793b8d28
19 changed files with 535 additions and 241 deletions

View file

@ -6,8 +6,8 @@ import static com.simibubi.create.foundation.item.AllToolTypes.PICKAXE;
import static com.simibubi.create.foundation.item.AllToolTypes.SHOVEL; import static com.simibubi.create.foundation.item.AllToolTypes.SHOVEL;
import static com.simibubi.create.foundation.item.AllToolTypes.SWORD; import static com.simibubi.create.foundation.item.AllToolTypes.SWORD;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.simibubi.create.foundation.packet.SimplePacketBase; import com.simibubi.create.foundation.packet.SimplePacketBase;
@ -126,7 +126,7 @@ public abstract class AbstractToolItem extends ToolItem {
return false; return false;
} }
public void modifyDrops(final List<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) { public void modifyDrops(final Collection<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) {
} }
public void spawnParticles(IWorld world, BlockPos pos, ItemStack tool, BlockState state) { public void spawnParticles(IWorld world, BlockPos pos, ItemStack tool, BlockState state) {

View file

@ -0,0 +1,21 @@
package com.simibubi.create.foundation.utility;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
public class Iterate {
public static final boolean[] trueAndFalse = { true, false };
public static final int[] positiveAndNegative = { 1, -1 };
public static final Direction[] directions = Direction.values();
public static final Direction[] horizontalDirections = getHorizontals();
public static final Axis[] axes = Axis.values();
private static Direction[] getHorizontals() {
Direction[] directions = new Direction[4];
for (int i = 0; i < 4; i++)
directions[i] = Direction.byHorizontalIndex(i);
return directions;
}
}

View file

@ -22,6 +22,8 @@ public class BlockMovementTraits {
return false; return false;
if (blockState.getBlock() == Blocks.OBSIDIAN) if (blockState.getBlock() == Blocks.OBSIDIAN)
return false; return false;
if (AllBlocks.BELT.typeOf(blockState))
return true;
return blockState.getPushReaction() != PushReaction.BLOCK; return blockState.getPushReaction() != PushReaction.BLOCK;
} }

View file

@ -26,6 +26,8 @@ import com.simibubi.create.modules.contraptions.components.contraptions.chassis.
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock; import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import com.simibubi.create.modules.contraptions.redstone.ContactBlock; import com.simibubi.create.modules.contraptions.redstone.ContactBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.inventories.FlexcrateBlock; import com.simibubi.create.modules.logistics.block.inventories.FlexcrateBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@ -48,6 +50,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.common.util.Constants.BlockFlags;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.items.wrapper.CombinedInvWrapper;
@ -150,6 +153,14 @@ public abstract class Contraption {
return false; return false;
if (AllBlocks.FLEXCRATE.typeOf(state)) if (AllBlocks.FLEXCRATE.typeOf(state))
FlexcrateBlock.splitCrate(world, pos); FlexcrateBlock.splitCrate(world, pos);
if (AllBlocks.BELT.typeOf(state)) {
BlockPos nextPos = BeltBlock.nextSegmentPosition(state, pos, true);
BlockPos prevPos = BeltBlock.nextSegmentPosition(state, pos, false);
if (nextPos != null && !visited.contains(nextPos))
frontier.add(nextPos);
if (prevPos != null && !visited.contains(prevPos))
frontier.add(prevPos);
}
if (state.getBlock() instanceof SlimeBlock) if (state.getBlock() instanceof SlimeBlock)
for (Direction offset : Direction.values()) { for (Direction offset : Direction.values()) {
@ -248,6 +259,7 @@ public abstract class Contraption {
NBTUtil.readBlockState(comp.getCompound("Block")), NBTUtil.readBlockState(comp.getCompound("Block")),
comp.contains("Data") ? comp.getCompound("Data") : null); comp.contains("Data") ? comp.getCompound("Data") : null);
blocks.put(info.pos, info); blocks.put(info.pos, info);
if (world.isRemote) { if (world.isRemote) {
Block block = info.state.getBlock(); Block block = info.state.getBlock();
BlockRenderLayer renderLayer = block.getRenderLayer(); BlockRenderLayer renderLayer = block.getRenderLayer();
@ -255,23 +267,27 @@ public abstract class Contraption {
renderOrder.add(info.pos); renderOrder.add(info.pos);
else else
renderOrder.add(0, info.pos); renderOrder.add(0, info.pos);
if (info.nbt == null || block instanceof IPortableBlock) CompoundNBT tag = info.nbt;
if (tag == null || block instanceof IPortableBlock)
return; return;
info.nbt.putInt("x", info.pos.getX()); tag.putInt("x", info.pos.getX());
info.nbt.putInt("y", info.pos.getY()); tag.putInt("y", info.pos.getY());
info.nbt.putInt("z", info.pos.getZ()); tag.putInt("z", info.pos.getZ());
TileEntity te = TileEntity.create(info.nbt);
TileEntity te = TileEntity.create(tag);
te.setWorld(new WrappedWorld(world) { te.setWorld(new WrappedWorld(world) {
@Override @Override
public BlockState getBlockState(BlockPos pos) { public BlockState getBlockState(BlockPos pos) {
if (isOutsideBuildHeight(pos) || !pos.equals(te.getPos())) if (!pos.equals(te.getPos()))
return Blocks.AIR.getDefaultState(); return Blocks.AIR.getDefaultState();
return info.state; return info.state;
} }
}); });
if (te instanceof KineticTileEntity)
((KineticTileEntity) te).setSpeed(0);
te.getBlockState(); te.getBlockState();
customRenderTEs.add(te); customRenderTEs.add(te);
} }
@ -392,13 +408,21 @@ public abstract class Contraption {
state = state.with(SawBlock.RUNNING, false); state = state.with(SawBlock.RUNNING, false);
world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty()); world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty());
world.setBlockState(targetPos, state, 3); world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING);
TileEntity tileEntity = world.getTileEntity(targetPos); TileEntity tileEntity = world.getTileEntity(targetPos);
if (tileEntity != null && block.nbt != null) { CompoundNBT tag = block.nbt;
block.nbt.putInt("x", targetPos.getX()); if (tileEntity != null && tag != null) {
block.nbt.putInt("y", targetPos.getY()); tag.putInt("x", targetPos.getX());
block.nbt.putInt("z", targetPos.getZ()); tag.putInt("y", targetPos.getY());
tileEntity.read(block.nbt); tag.putInt("z", targetPos.getZ());
if (tileEntity instanceof BeltTileEntity) {
tag.remove("Length");
tag.remove("Index");
tag.putBoolean("DontClearAttachments", true);
}
tileEntity.read(tag);
if (tileEntity instanceof KineticTileEntity) { if (tileEntity instanceof KineticTileEntity) {
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity; KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;

View file

@ -1,7 +1,10 @@
package com.simibubi.create.modules.contraptions.components.contraptions; package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.SlabBlock; import net.minecraft.block.SlabBlock;
@ -93,9 +96,49 @@ public class StructureTransform {
return state; return state;
} }
if (AllBlocks.BELT.typeOf(state)) {
if (state.get(BeltBlock.HORIZONTAL_FACING).getAxis() != rotationAxis) {
for (int i = 0; i < rotation.ordinal(); i++) {
Slope slope = state.get(BeltBlock.SLOPE);
Direction direction = state.get(BeltBlock.HORIZONTAL_FACING);
// Rotate diagonal
if (slope != Slope.HORIZONTAL && slope != Slope.VERTICAL) {
if (direction.getAxisDirection() == AxisDirection.POSITIVE ^ slope == Slope.DOWNWARD
^ direction.getAxis() == Axis.Z) {
state =
state.with(BeltBlock.SLOPE, slope == Slope.UPWARD ? Slope.DOWNWARD : Slope.UPWARD);
} else {
state = state.with(BeltBlock.HORIZONTAL_FACING, direction.getOpposite());
}
// Rotate horizontal/vertical
} else {
if (slope == Slope.HORIZONTAL ^ direction.getAxis() == Axis.Z) {
state = state.with(BeltBlock.HORIZONTAL_FACING, direction.getOpposite());
}
state = state.with(BeltBlock.SLOPE,
slope == Slope.HORIZONTAL ? Slope.VERTICAL : Slope.HORIZONTAL);
}
}
} else {
if (rotation == Rotation.CLOCKWISE_180) {
Slope slope = state.get(BeltBlock.SLOPE);
Direction direction = state.get(BeltBlock.HORIZONTAL_FACING);
if (slope == Slope.UPWARD || slope == Slope.DOWNWARD) {
state = state.with(BeltBlock.SLOPE, slope == Slope.UPWARD ? Slope.DOWNWARD
: slope == Slope.DOWNWARD ? Slope.UPWARD : slope);
} else if (slope == Slope.VERTICAL) {
state = state.with(BeltBlock.HORIZONTAL_FACING, direction.getOpposite());
}
}
}
return state;
}
if (state.has(BlockStateProperties.FACING)) { if (state.has(BlockStateProperties.FACING)) {
state = state.with(BlockStateProperties.FACING, state =
transformFacing(state.get(BlockStateProperties.FACING))); state.with(BlockStateProperties.FACING, transformFacing(state.get(BlockStateProperties.FACING)));
} else if (state.has(BlockStateProperties.AXIS)) { } else if (state.has(BlockStateProperties.AXIS)) {
state = state.with(BlockStateProperties.AXIS, transformAxis(state.get(BlockStateProperties.AXIS))); state = state.with(BlockStateProperties.AXIS, transformAxis(state.get(BlockStateProperties.AXIS)));

View file

@ -38,6 +38,7 @@ import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; import net.minecraftforge.event.entity.living.LivingExperienceDropEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent; import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@ -86,7 +87,7 @@ public class DeployerFakePlayer extends FakePlayer {
event.setNewHeight(0); event.setNewHeight(0);
} }
@SubscribeEvent @SubscribeEvent(priority = EventPriority.LOWEST)
public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) { public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) {
if (!(event.getSource() instanceof EntityDamageSource)) if (!(event.getSource() instanceof EntityDamageSource))
return; return;

View file

@ -41,7 +41,7 @@ public class MotorTileEntity extends GeneratingKineticTileEntity {
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); super.initialize();
if (!hasSource()) if (!hasSource() || getGeneratedSpeed() > getTheoreticalSpeed())
updateGeneratedRotation(); updateGeneratedRotation();
} }

View file

@ -1,22 +1,30 @@
package com.simibubi.create.modules.contraptions.relays.belt; package com.simibubi.create.modules.contraptions.relays.belt;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.block.IHaveColorHandler;
import com.simibubi.create.foundation.block.IHaveNoBlockItem; import com.simibubi.create.foundation.block.IHaveNoBlockItem;
import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo; import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.client.particle.DiggingParticle;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.renderer.color.IBlockColor;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.MobEntity; import net.minecraft.entity.MobEntity;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
@ -40,19 +48,21 @@ import net.minecraft.util.Hand;
import net.minecraft.util.IStringSerializable; import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IEnviromentBlockReader;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraftforge.common.Tags; import net.minecraftforge.common.Tags;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockItem, IWithTileEntity<BeltTileEntity> { public class BeltBlock extends HorizontalKineticBlock
implements IHaveNoBlockItem, IWithTileEntity<BeltTileEntity>, IHaveColorHandler {
public static final IProperty<Slope> SLOPE = EnumProperty.create("slope", Slope.class); public static final IProperty<Slope> SLOPE = EnumProperty.create("slope", Slope.class);
public static final IProperty<Part> PART = EnumProperty.create("part", Part.class); public static final IProperty<Part> PART = EnumProperty.create("part", Part.class);
@ -90,10 +100,11 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@Override @Override
public List<ItemStack> getDrops(BlockState state, net.minecraft.world.storage.loot.LootContext.Builder builder) { public List<ItemStack> getDrops(BlockState state, net.minecraft.world.storage.loot.LootContext.Builder builder) {
List<ItemStack> drops = super.getDrops(state, builder); List<ItemStack> drops = new ArrayList<>();
if (state.get(PART) == Part.START || builder.get(LootParameters.THIS_ENTITY) != null)
drops.addAll(super.getDrops(state, builder));
if (state.get(CASING)) if (state.get(CASING))
drops.addAll(AllBlocks.BRASS_CASING.getDefault() drops.addAll(AllBlocks.BRASS_CASING.getDefault().getDrops(builder));
.getDrops(builder));
return drops; return drops;
} }
@ -170,8 +181,10 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
TransportedEntityInfo info = controller.passengers.get(entityIn); TransportedEntityInfo info = controller.passengers.get(entityIn);
if (info.ticksSinceLastCollision != 0 || pos.equals(entityIn.getPosition())) if (info.ticksSinceLastCollision != 0 || pos.equals(entityIn.getPosition()))
info.refresh(pos, state); info.refresh(pos, state);
} else } else {
controller.passengers.put(entityIn, new TransportedEntityInfo(pos, state)); controller.passengers.put(entityIn, new TransportedEntityInfo(pos, state));
entityIn.onGround = true;
}
} }
@Override @Override
@ -295,12 +308,52 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
@Override @Override
public PathNodeType getAiPathNodeType(BlockState state, IBlockReader world, BlockPos pos, MobEntity entity) { public PathNodeType getAiPathNodeType(BlockState state, IBlockReader world, BlockPos pos, MobEntity entity) {
return PathNodeType.DANGER_OTHER; return PathNodeType.RAIL;
}
@Override
public boolean addDestroyEffects(BlockState state, World world, BlockPos pos, ParticleManager manager) {
// From Particle Manager, but reduced density for belts with lots of boxes
VoxelShape voxelshape = state.getShape(world, pos);
MutableInt amtBoxes = new MutableInt(0);
voxelshape.forEachBox((x1, y1, z1, x2, y2, z2) -> amtBoxes.increment());
double chance = 1d / amtBoxes.getValue();
voxelshape.forEachBox((x1, y1, z1, x2, y2, z2) -> {
double d1 = Math.min(1.0D, x2 - x1);
double d2 = Math.min(1.0D, y2 - y1);
double d3 = Math.min(1.0D, z2 - z1);
int i = Math.max(2, MathHelper.ceil(d1 / 0.25D));
int j = Math.max(2, MathHelper.ceil(d2 / 0.25D));
int k = Math.max(2, MathHelper.ceil(d3 / 0.25D));
for (int l = 0; l < i; ++l) {
for (int i1 = 0; i1 < j; ++i1) {
for (int j1 = 0; j1 < k; ++j1) {
if (world.rand.nextDouble() > chance)
continue;
double d4 = ((double) l + 0.5D) / (double) i;
double d5 = ((double) i1 + 0.5D) / (double) j;
double d6 = ((double) j1 + 0.5D) / (double) k;
double d7 = d4 * d1 + x1;
double d8 = d5 * d2 + y1;
double d9 = d6 * d3 + z1;
manager.addEffect(
(new DiggingParticle(world, (double) pos.getX() + d7, (double) pos.getY() + d8,
(double) pos.getZ() + d9, d4 - 0.5D, d5 - 0.5D, d6 - 0.5D, state))
.setBlockPos(pos));
}
}
}
});
return true;
} }
@Override @Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return VoxelShapes.or(BeltShapes.getShape(state), BeltShapes.getCasingShape(state)); return BeltShapes.getShape(state);
} }
@Override @Override
@ -314,7 +367,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
if (controller == null) if (controller == null)
return shape; return shape;
if (controller.passengers == null || !controller.passengers.containsKey(context.getEntity())) { if (controller.passengers == null || !controller.passengers.containsKey(context.getEntity())) {
return VoxelShapes.combine(AllShapes.BELT_COLLISION_MASK, shape, IBooleanFunction.AND); return BeltShapes.getCollisionShape(state);
} }
return shape; return shape;
@ -326,41 +379,112 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
} }
@Override @Override
public boolean canRenderInLayer(BlockState state, BlockRenderLayer layer) { public BlockRenderType getRenderType(BlockState state) {
return state.get(CASING) && layer == getRenderLayer(); return state.get(CASING) && state.get(SLOPE) != Slope.VERTICAL ? BlockRenderType.MODEL
: BlockRenderType.ENTITYBLOCK_ANIMATED;
} }
@Override @Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { public boolean canRenderInLayer(BlockState state, BlockRenderLayer layer) {
if (worldIn.isRemote) return state.get(CASING) && state.get(SLOPE) != Slope.VERTICAL && layer == getRenderLayer();
}
public static void initBelt(World world, BlockPos pos) {
if (world.isRemote)
return;
BlockState state = world.getBlockState(pos);
if (!AllBlocks.BELT.typeOf(state))
return;
// Find controller
int limit = 1000;
BlockPos currentPos = pos;
while (limit-- > 0) {
BlockState currentState = world.getBlockState(currentPos);
if (!AllBlocks.BELT.typeOf(currentState)) {
world.destroyBlock(pos, true);
return;
}
BlockPos nextSegmentPosition = nextSegmentPosition(currentState, currentPos, false);
if (nextSegmentPosition == null)
break;
if (!world.isAreaLoaded(nextSegmentPosition, 0))
return;
currentPos = nextSegmentPosition;
}
// Init belts
int index = 0;
List<BlockPos> beltChain = getBeltChain(world, pos);
if (beltChain.size() < 2) {
world.destroyBlock(pos, true);
return;
}
for (BlockPos beltPos : beltChain) {
TileEntity tileEntity = world.getTileEntity(beltPos);
if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity te = (BeltTileEntity) tileEntity;
te.setController(pos);
te.beltLength = beltChain.size();
te.index = index;
te.attachKinetics();
te.markDirty();
te.sendData();
BlockState currentState = world.getBlockState(beltPos);
boolean isVertical = currentState.get(BeltBlock.SLOPE) == Slope.VERTICAL;
if (currentState.get(CASING) && isVertical) {
Block.spawnAsEntity(world, beltPos, new ItemStack(AllBlocks.BRASS_CASING.get()));
world.setBlockState(beltPos, currentState.with(CASING, false), 2);
}
if (te.isController() && isVertical) {
BeltInventory inventory = te.getInventory();
for (TransportedItemStack s : inventory.items)
inventory.eject(s);
inventory.items.clear();
}
} else {
world.destroyBlock(pos, true);
return;
}
index++;
}
}
@Override
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
if (world.isRemote)
return; return;
if (state.getBlock() == newState.getBlock()) if (state.getBlock() == newState.getBlock())
return; return;
updateNeighbouringTunnel(worldIn, pos, state);
updateNeighbouringTunnel(world, pos, state);
if (isMoving)
return;
TileEntity belt = world.getTileEntity(pos);
if (belt instanceof BeltTileEntity)
belt.remove();
// Destroy chain // Destroy chain
boolean endWasDestroyed = state.get(PART) == Part.END; for (boolean forward : Iterate.trueAndFalse) {
TileEntity tileEntity = worldIn.getTileEntity(pos); BlockPos currentPos = nextSegmentPosition(state, pos, forward);
if (tileEntity == null) if (currentPos == null)
return; continue;
if (!(tileEntity instanceof BeltTileEntity)) BlockState currentState = world.getBlockState(currentPos);
return; if (!AllBlocks.BELT.typeOf(currentState))
BeltTileEntity beltEntity = (BeltTileEntity) tileEntity; continue;
BlockPos controller = beltEntity.getController(); if (currentState.get(CASING))
beltEntity.remove(); Block.spawnAsEntity(world, currentPos, new ItemStack(AllBlocks.BRASS_CASING.get()));
int limit = 1000; boolean hasPulley = false;
BlockPos toDestroy = controller; TileEntity tileEntity = world.getTileEntity(currentPos);
BlockState destroyedBlock = null; if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity te = (BeltTileEntity) tileEntity;
do {
if (!toDestroy.equals(pos)) {
destroyedBlock = worldIn.getBlockState(toDestroy);
if (!AllBlocks.BELT.typeOf(destroyedBlock))
break;
BeltTileEntity te = (BeltTileEntity) worldIn.getTileEntity(toDestroy);
if (te.isController()) { if (te.isController()) {
BeltInventory inv = te.getInventory(); BeltInventory inv = te.getInventory();
for (TransportedItemStack stack : inv.items) for (TransportedItemStack stack : inv.items)
@ -368,36 +492,14 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
} }
te.remove(); te.remove();
hasPulley = te.hasPulley();
if (destroyedBlock.get(CASING))
Block.spawnAsEntity(worldIn, toDestroy, new ItemStack(AllBlocks.BRASS_CASING.get()));
if (te.hasPulley())
worldIn.setBlockState(toDestroy, AllBlocks.SHAFT.get().getDefaultState()
.with(BlockStateProperties.AXIS, getRotationAxis(destroyedBlock)), 3);
else
worldIn.destroyBlock(toDestroy, false);
if (destroyedBlock.get(PART) == Part.END)
break;
} else {
if (endWasDestroyed)
break;
} }
Slope slope = state.get(SLOPE); BlockState shaftState =
Direction direction = state.get(HORIZONTAL_FACING); AllBlocks.SHAFT.get().getDefaultState().with(BlockStateProperties.AXIS, getRotationAxis(currentState));
world.setBlockState(currentPos, hasPulley ? shaftState : Blocks.AIR.getDefaultState(), 3);
if (slope == Slope.VERTICAL) { world.playEvent(2001, currentPos, Block.getStateId(currentState));
toDestroy = toDestroy.up(direction.getAxisDirection() == AxisDirection.POSITIVE ? 1 : -1); }
continue;
}
toDestroy = toDestroy.offset(direction);
if (slope != Slope.HORIZONTAL)
toDestroy = toDestroy.up(slope == Slope.UPWARD ? 1 : -1);
} while (limit-- > 0);
} }
private void updateNeighbouringTunnel(World world, BlockPos pos, BlockState beltState) { private void updateNeighbouringTunnel(World world, BlockPos pos, BlockState beltState) {
@ -435,30 +537,36 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
if (!AllBlocks.BELT.typeOf(blockState)) if (!AllBlocks.BELT.typeOf(blockState))
return positions; return positions;
Slope slope = blockState.get(SLOPE);
Direction direction = blockState.get(HORIZONTAL_FACING);
int limit = 1000; int limit = 1000;
BlockPos current = controllerPos; BlockPos current = controllerPos;
do { while (limit-- > 0 && current != null) {
positions.add(current); positions.add(current);
BlockState state = world.getBlockState(current);
if (!AllBlocks.BELT.typeOf(world.getBlockState(current))) if (!AllBlocks.BELT.typeOf(state))
break; break;
if (world.getBlockState(current).get(PART) == Part.END) current = nextSegmentPosition(state, current, true);
break; }
if (slope == Slope.VERTICAL) {
current = current.up(direction.getAxisDirection() == AxisDirection.POSITIVE ? 1 : -1);
continue;
}
current = current.offset(direction);
if (slope != Slope.HORIZONTAL)
current = current.up(slope == Slope.UPWARD ? 1 : -1);
} while (limit-- > 0);
return positions; return positions;
} }
public static BlockPos nextSegmentPosition(BlockState state, BlockPos pos, boolean forward) {
Direction direction = state.get(HORIZONTAL_FACING);
Slope slope = state.get(SLOPE);
Part part = state.get(PART);
int offset = forward ? 1 : -1;
if (part == Part.END && forward || part == Part.START && !forward)
return null;
if (slope == Slope.VERTICAL)
return pos.up(direction.getAxisDirection() == AxisDirection.POSITIVE ? offset : -offset);
pos = pos.offset(direction, offset);
if (slope != Slope.HORIZONTAL)
return pos.up(slope == Slope.UPWARD ? offset : -offset);
return pos;
}
@Override @Override
protected boolean hasStaticPart() { protected boolean hasStaticPart() {
return false; return false;
@ -489,4 +597,26 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
return true; return true;
} }
@Override
public IBlockColor getColorHandler() {
return color;
}
private static BeltColor color = new BeltColor();
private static class BeltColor implements IBlockColor {
@Override
public int getColor(BlockState state, IEnviromentBlockReader reader, BlockPos pos, int layer) {
TileEntity tileEntity = reader.getTileEntity(pos);
if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity te = (BeltTileEntity) tileEntity;
if (te.color != -1)
return te.color;
}
return 0;
}
}
} }

View file

@ -102,7 +102,6 @@ public class BeltConnectorItem extends BlockItem implements IAddedByOther {
List<BlockPos> beltsToCreate = getBeltChainBetween(start, end, slope, facing); List<BlockPos> beltsToCreate = getBeltChainBetween(start, end, slope, facing);
BlockState beltBlock = AllBlocks.BELT.get().getDefaultState(); BlockState beltBlock = AllBlocks.BELT.get().getDefaultState();
int index = 0;
for (BlockPos pos : beltsToCreate) { for (BlockPos pos : beltsToCreate) {
BeltBlock.Part part = pos.equals(start) ? Part.START : pos.equals(end) ? Part.END : Part.MIDDLE; BeltBlock.Part part = pos.equals(start) ? Part.START : pos.equals(end) ? Part.END : Part.MIDDLE;
boolean pulley = AllBlocks.SHAFT.typeOf(world.getBlockState(pos)); boolean pulley = AllBlocks.SHAFT.typeOf(world.getBlockState(pos));
@ -110,15 +109,6 @@ public class BeltConnectorItem extends BlockItem implements IAddedByOther {
part = Part.PULLEY; part = Part.PULLEY;
world.setBlockState(pos, beltBlock.with(BeltBlock.SLOPE, slope).with(BeltBlock.PART, part) world.setBlockState(pos, beltBlock.with(BeltBlock.SLOPE, slope).with(BeltBlock.PART, part)
.with(BeltBlock.HORIZONTAL_FACING, facing), 3); .with(BeltBlock.HORIZONTAL_FACING, facing), 3);
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(pos);
if (te != null) {
te.setController(start);
te.beltLength = beltsToCreate.size();
te.index = index;
}
index++;
} }
} }

View file

@ -91,8 +91,8 @@ public class BeltInventory {
float diff = stackInFront.beltPosition - currentPos; float diff = stackInFront.beltPosition - currentPos;
if (Math.abs(diff) <= spacing) if (Math.abs(diff) <= spacing)
continue; continue;
movement = beltMovementPositive ? Math.min(movement, diff - spacing) movement =
: Math.max(movement, diff + spacing); beltMovementPositive ? Math.min(movement, diff - spacing) : Math.max(movement, diff + spacing);
} }
// Determine current segment // Determine current segment
@ -104,8 +104,8 @@ public class BeltInventory {
// Don't move beyond the edge // Don't move beyond the edge
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos; float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
float limitedMovement = beltMovementPositive ? Math.min(movement, diffToEnd) float limitedMovement =
: Math.max(movement, diffToEnd); beltMovementPositive ? Math.min(movement, diffToEnd) : Math.max(movement, diffToEnd);
float nextOffset = current.beltPosition + limitedMovement; float nextOffset = current.beltPosition + limitedMovement;
if (!onClient) { if (!onClient) {
@ -204,12 +204,12 @@ public class BeltInventory {
if (AllBlocks.BASIN.typeOf(state) || AllBlocks.SAW.typeOf(state)) { if (AllBlocks.BASIN.typeOf(state) || AllBlocks.SAW.typeOf(state)) {
TileEntity te = world.getTileEntity(nextPosition); TileEntity te = world.getTileEntity(nextPosition);
if (te != null) { if (te != null) {
LazyOptional<IItemHandler> optional = te LazyOptional<IItemHandler> optional =
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP); te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
if (optional.isPresent()) { if (optional.isPresent()) {
IItemHandler itemHandler = optional.orElse(null); IItemHandler itemHandler = optional.orElse(null);
ItemStack remainder = ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(), ItemStack remainder =
false); ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(), false);
if (remainder.equals(current.stack, false)) if (remainder.equals(current.stack, false))
continue; continue;
@ -385,6 +385,7 @@ public class BeltInventory {
outPos.add(outMotion.normalize()); outPos.add(outMotion.normalize());
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y + 6 / 16f, outPos.z, ejected); ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y + 6 / 16f, outPos.z, ejected);
entity.setMotion(outMotion); entity.setMotion(outMotion);
entity.setDefaultPickupDelay();
entity.velocityChanged = true; entity.velocityChanged = true;
belt.getWorld().addEntity(entity); belt.getWorld().addEntity(entity);
} }
@ -398,8 +399,12 @@ public class BeltInventory {
verticalMovement = verticalMovement * (Math.min(offset, belt.beltLength - .5f) - .5f); verticalMovement = verticalMovement * (Math.min(offset, belt.beltLength - .5f) - .5f);
Vec3d vec = VecHelper.getCenterOf(belt.getPos()); Vec3d vec = VecHelper.getCenterOf(belt.getPos());
vec = vec.add(new Vec3d(belt.getBeltFacing().getDirectionVec()).scale(offset - .5f)).add(0, verticalMovement, Vec3d horizontalMovement = new Vec3d(belt.getBeltFacing().getDirectionVec()).scale(offset - .5f);
0);
if (slope == Slope.VERTICAL)
horizontalMovement = Vec3d.ZERO;
vec = vec.add(horizontalMovement).add(0, verticalMovement, 0);
return vec; return vec;
} }

View file

@ -78,7 +78,7 @@ public class BeltMovementHandler {
// Too slow // Too slow
boolean notHorizontal = beltTe.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL; boolean notHorizontal = beltTe.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL;
if (Math.abs(beltTe.getSpeed()) < (notHorizontal ? 32 : 1)) if (Math.abs(beltTe.getSpeed()) < 1)
return; return;
// Not on top // Not on top
@ -158,6 +158,8 @@ public class BeltMovementHandler {
} }
} }
entityIn.fallDistance = 0;
if (movingUp) { if (movingUp) {
float minVelocity = .13f; float minVelocity = .13f;
float yMovement = (float) -(Math.max(Math.abs(movement.y), minVelocity)); float yMovement = (float) -(Math.max(Math.abs(movement.y), minVelocity));

View file

@ -2,6 +2,9 @@ package com.simibubi.create.modules.contraptions.relays.belt;
import static net.minecraft.block.Block.makeCuboidShape; import static net.minecraft.block.Block.makeCuboidShape;
import java.util.HashMap;
import java.util.Map;
import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.VoxelShaper; import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part; import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
@ -98,6 +101,8 @@ public class BeltShapes {
private static final VoxelShaper private static final VoxelShaper
PARTIAL_CASING = VoxelShaper.forHorizontal(makeCuboidShape(0, 0, 5, 16, 11, 16), Direction.SOUTH); PARTIAL_CASING = VoxelShaper.forHorizontal(makeCuboidShape(0, 0, 5, 16, 11, 16), Direction.SOUTH);
static Map<BlockState, VoxelShape> cache = new HashMap<>();
static Map<BlockState, VoxelShape> collisionCache = new HashMap<>();
private static VoxelShape compose(VoxelShape southPart, VoxelShape northPart){ private static VoxelShape compose(VoxelShape southPart, VoxelShape northPart){
return VoxelShapes.or( return VoxelShapes.or(
@ -134,6 +139,22 @@ public class BeltShapes {
} }
public static VoxelShape getShape(BlockState state) { public static VoxelShape getShape(BlockState state) {
if (cache.containsKey(state))
return cache.get(state);
VoxelShape createdShape = VoxelShapes.or(getBeltShape(state), getCasingShape(state));
cache.put(state, createdShape);
return createdShape;
}
public static VoxelShape getCollisionShape(BlockState state) {
if (collisionCache.containsKey(state))
return collisionCache.get(state);
VoxelShape createdShape = VoxelShapes.combine(AllShapes.BELT_COLLISION_MASK, getShape(state), IBooleanFunction.AND);
collisionCache.put(state, createdShape);
return createdShape;
}
private static VoxelShape getBeltShape(BlockState state) {
Direction facing = state.get(BeltBlock.HORIZONTAL_FACING); Direction facing = state.get(BeltBlock.HORIZONTAL_FACING);
Axis axis = facing.getAxis(); Axis axis = facing.getAxis();
Part part = state.get(BeltBlock.PART); Part part = state.get(BeltBlock.PART);
@ -166,10 +187,9 @@ public class BeltShapes {
//bad state //bad state
return VoxelShapes.empty(); return VoxelShapes.empty();
} }
public static VoxelShape getCasingShape(BlockState state) { private static VoxelShape getCasingShape(BlockState state) {
if (!state.get(BeltBlock.CASING)) if (!state.get(BeltBlock.CASING))
return VoxelShapes.empty(); return VoxelShapes.empty();

View file

@ -61,23 +61,21 @@ public class BeltTileEntity extends KineticTileEntity {
attachmentTracker = new Tracker(this); attachmentTracker = new Tracker(this);
itemHandler = LazyOptional.empty(); itemHandler = LazyOptional.empty();
color = -1; color = -1;
beltLength = -1;
index = -1;
} }
@Override @Override
public void initialize() { public void initialize() {
super.initialize(); super.initialize();
// 0.1 belt
if (beltLength == 0) {
world.destroyBlock(pos, true);
}
} }
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
// Init belt
if (beltLength == 0)
BeltBlock.initBelt(world, pos);
// Initialize Belt Attachments // Initialize Belt Attachments
if (world != null && trackerUpdateTag != null) { if (world != null && trackerUpdateTag != null) {
attachmentTracker.readAndSearch(trackerUpdateTag, this); attachmentTracker.readAndSearch(trackerUpdateTag, this);
@ -100,9 +98,8 @@ public class BeltTileEntity extends KineticTileEntity {
List<Entity> toRemove = new ArrayList<>(); List<Entity> toRemove = new ArrayList<>();
passengers.forEach((entity, info) -> { passengers.forEach((entity, info) -> {
boolean canBeTransported = BeltMovementHandler.canBeTransported(entity); boolean canBeTransported = BeltMovementHandler.canBeTransported(entity);
boolean leftTheBelt = info.ticksSinceLastCollision > ((getBlockState().get(BeltBlock.SLOPE) != HORIZONTAL) boolean leftTheBelt =
? 3 info.ticksSinceLastCollision > ((getBlockState().get(BeltBlock.SLOPE) != HORIZONTAL) ? 3 : 1);
: 1);
if (!canBeTransported || leftTheBelt) { if (!canBeTransported || leftTheBelt) {
toRemove.add(entity); toRemove.add(entity);
return; return;
@ -165,6 +162,7 @@ public class BeltTileEntity extends KineticTileEntity {
public CompoundNBT write(CompoundNBT compound) { public CompoundNBT write(CompoundNBT compound) {
attachmentTracker.write(compound); attachmentTracker.write(compound);
compound.put("Controller", NBTUtil.writeBlockPos(controller)); compound.put("Controller", NBTUtil.writeBlockPos(controller));
compound.putBoolean("IsController", isController());
compound.putInt("Color", color); compound.putInt("Color", color);
compound.putInt("Length", beltLength); compound.putInt("Length", beltLength);
compound.putInt("Index", index); compound.putInt("Index", index);
@ -177,8 +175,13 @@ public class BeltTileEntity extends KineticTileEntity {
@Override @Override
public void read(CompoundNBT compound) { public void read(CompoundNBT compound) {
super.read(compound); super.read(compound);
trackerUpdateTag = compound; if (compound.getBoolean("IsController"))
controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); controller = pos;
else
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
if (!compound.contains("DontClearAttachments"))
trackerUpdateTag = compound;
color = compound.getInt("Color"); color = compound.getInt("Color");
beltLength = compound.getInt("Length"); beltLength = compound.getInt("Length");
index = compound.getInt("Index"); index = compound.getInt("Index");
@ -249,8 +252,8 @@ public class BeltTileEntity extends KineticTileEntity {
if (part == MIDDLE) if (part == MIDDLE)
return false; return false;
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1)) boolean movingPositively =
^ direction.getAxis() == Axis.X; (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1)) ^ direction.getAxis() == Axis.X;
return part == Part.START ^ movingPositively; return part == Part.START ^ movingPositively;
} }
@ -305,8 +308,9 @@ public class BeltTileEntity extends KineticTileEntity {
return controllerTE.getInventory(); return controllerTE.getInventory();
return null; return null;
} }
if (inventory == null) if (inventory == null) {
inventory = new BeltInventory(this); inventory = new BeltInventory(this);
}
return inventory; return inventory;
} }

View file

@ -28,6 +28,7 @@ import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.Vec3i;
@ -47,15 +48,15 @@ public class BeltTileEntityRenderer extends SafeTileEntityRenderer<BeltTileEntit
} }
@Override @Override
public void renderFast(BeltTileEntity te, double x, double y, double z, float partialTicks, public void renderFast(BeltTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
int destroyStage, BufferBuilder buffer) { BufferBuilder buffer) {
BlockState blockState = te.getBlockState(); BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.typeOf(blockState)) if (!AllBlocks.BELT.typeOf(blockState))
return; return;
BlockState renderedState = getBeltState(te); BlockState renderedState = getBeltState(te);
SuperByteBuffer beltBuffer = CreateClient.bufferCache.renderBlockIn(KineticTileEntityRenderer.KINETIC_TILE, SuperByteBuffer beltBuffer =
renderedState); CreateClient.bufferCache.renderBlockIn(KineticTileEntityRenderer.KINETIC_TILE, renderedState);
beltBuffer.color(te.color == -1 ? 0x808080 : te.color); beltBuffer.color(te.color == -1 ? 0x808080 : te.color);
@ -64,8 +65,8 @@ public class BeltTileEntityRenderer extends SafeTileEntityRenderer<BeltTileEntit
if (animatedTexture == null) if (animatedTexture == null)
animatedTexture = SpriteShifter.get("block/belt", "block/belt_animated"); animatedTexture = SpriteShifter.get("block/belt", "block/belt_animated");
if (speed != 0) { if (speed != 0) {
float time = AnimationTickHolder.getRenderTick() float time =
* blockState.get(HORIZONTAL_FACING).getAxisDirection().getOffset(); AnimationTickHolder.getRenderTick() * blockState.get(HORIZONTAL_FACING).getAxisDirection().getOffset();
if (renderedState.get(BeltBlock.HORIZONTAL_FACING).getAxis() == Axis.X) if (renderedState.get(BeltBlock.HORIZONTAL_FACING).getAxis() == Axis.X)
speed = -speed; speed = -speed;
int textureIndex = (int) ((speed * time / 36) % 16); int textureIndex = (int) ((speed * time / 36) % 16);
@ -92,93 +93,95 @@ public class BeltTileEntityRenderer extends SafeTileEntityRenderer<BeltTileEntit
} }
protected void renderItems(BeltTileEntity te, double x, double y, double z, float partialTicks) { protected void renderItems(BeltTileEntity te, double x, double y, double z, float partialTicks) {
if (te.isController()) { if (!te.isController())
return;
if (te.beltLength == 0)
return;
GlStateManager.pushMatrix();
Vec3i directionVec = te.getBeltFacing().getDirectionVec();
Vec3d beltStartOffset = new Vec3d(directionVec).scale(-.5).add(.5, 13 / 16f + .125f, .5);
GlStateManager.translated(x + beltStartOffset.x, y + beltStartOffset.y, z + beltStartOffset.z);
Slope slope = te.getBlockState().get(BeltBlock.SLOPE);
int verticality = slope == Slope.DOWNWARD ? -1 : slope == Slope.UPWARD ? 1 : 0;
boolean slopeAlongX = te.getBeltFacing().getAxis() == Axis.X;
for (TransportedItemStack transported : te.getInventory().items) {
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
TessellatorHelper.fightZFighting(transported.angle);
float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition);
float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset);
float verticalMovement = verticality;
Vec3i directionVec = te.getBeltFacing().getDirectionVec(); if (te.getSpeed() == 0) {
Vec3d beltStartOffset = new Vec3d(directionVec).scale(-.5).add(.5, 13 / 16f + .125f, .5); offset = transported.beltPosition;
GlStateManager.translated(x + beltStartOffset.x, y + beltStartOffset.y, z + beltStartOffset.z); sideOffset = transported.sideOffset;
Slope slope = te.getBlockState().get(BeltBlock.SLOPE);
int verticality = slope == Slope.DOWNWARD ? -1 : slope == Slope.UPWARD ? 1 : 0;
boolean slopeAlongX = te.getBeltFacing().getAxis() == Axis.X;
for (TransportedItemStack transported : te.getInventory().items) {
GlStateManager.pushMatrix();
TessellatorHelper.fightZFighting(transported.angle);
float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition);
float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset);
float verticalMovement = verticality;
if (te.getSpeed() == 0) {
offset = transported.beltPosition;
sideOffset = transported.sideOffset;
}
if (offset < .5)
verticalMovement = 0;
verticalMovement = verticalMovement * (Math.min(offset, te.beltLength - .5f) - .5f);
Vec3d offsetVec = new Vec3d(directionVec).scale(offset).add(0, verticalMovement, 0);
boolean onSlope = slope != Slope.HORIZONTAL
&& MathHelper.clamp(offset, .5f, te.beltLength - .5f) == offset;
float slopeAngle = onSlope
? slope == Slope.DOWNWARD ^ te.getDirectionAwareBeltMovementSpeed() > 0
^ te.getBeltMovementSpeed() < 0 ? -45 : 45
: 0;
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
boolean alongX = te.getBeltFacing().rotateY().getAxis() == Axis.X;
if (!alongX)
sideOffset *= -1;
GlStateManager.translated(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset);
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
boolean blockItem = itemRenderer.getModelWithOverrides(transported.stack).isGui3d();
if (Minecraft.getInstance().gameSettings.fancyGraphics) {
Vec3d shadowPos = new Vec3d(te.getPos()).add(beltStartOffset.scale(1).add(offsetVec)
.add(alongX ? sideOffset : 0, .39, alongX ? 0 : sideOffset));
IndependentShadowRenderer.renderShadow(shadowPos.x, shadowPos.y, shadowPos.z, .75f,
blockItem ? .2f : .2f);
}
RenderHelper.enableStandardItemLighting();
int count = (int) (MathHelper.log2((int) (transported.stack.getCount()))) / 2;
GlStateManager.rotated(slopeAngle, slopeAlongX ? 0 : 1, 0, slopeAlongX ? 1 : 0);
if (onSlope)
GlStateManager.translated(0, 1 / 8f, 0);
Random r = new Random(transported.angle);
for (int i = 0; i <= count; i++) {
GlStateManager.pushMatrix();
GlStateManager.rotated(transported.angle, 0, 1, 0);
if (!blockItem) {
GlStateManager.translated(0, -.09375, 0);
GlStateManager.rotated(90, 1, 0, 0);
}
if (blockItem) {
GlStateManager.translated(r.nextFloat() * .0625f * i, 0, r.nextFloat() * .0625f * i);
}
GlStateManager.scaled(.5, .5, .5);
itemRenderer.renderItem(transported.stack, TransformType.FIXED);
GlStateManager.popMatrix();
if (!blockItem)
GlStateManager.rotated(10, 0, 1, 0);
GlStateManager.translated(0, blockItem ? 1 / 64d : 1 / 16d, 0);
}
RenderHelper.disableStandardItemLighting();
GlStateManager.popMatrix();
} }
GlStateManager.disableBlend(); if (offset < .5)
verticalMovement = 0;
verticalMovement = verticalMovement * (Math.min(offset, te.beltLength - .5f) - .5f);
Vec3d offsetVec = new Vec3d(directionVec).scale(offset).add(0, verticalMovement, 0);
boolean onSlope = slope != Slope.HORIZONTAL && MathHelper.clamp(offset, .5f, te.beltLength - .5f) == offset;
boolean tiltForward =
(slope == Slope.DOWNWARD ^ te.getBeltFacing().getAxisDirection() == AxisDirection.POSITIVE) == (te
.getBeltFacing().getAxis() == Axis.Z);
float slopeAngle = onSlope ? tiltForward ? -45 : 45 : 0;
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
boolean alongX = te.getBeltFacing().rotateY().getAxis() == Axis.X;
if (!alongX)
sideOffset *= -1;
GlStateManager.translated(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset);
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
boolean blockItem = itemRenderer.getModelWithOverrides(transported.stack).isGui3d();
if (Minecraft.getInstance().gameSettings.fancyGraphics) {
Vec3d shadowPos = new Vec3d(te.getPos()).add(beltStartOffset.scale(1).add(offsetVec)
.add(alongX ? sideOffset : 0, .39, alongX ? 0 : sideOffset));
IndependentShadowRenderer.renderShadow(shadowPos.x, shadowPos.y, shadowPos.z, .75f,
blockItem ? .2f : .2f);
}
RenderHelper.enableStandardItemLighting();
int count = (int) (MathHelper.log2((int) (transported.stack.getCount()))) / 2;
GlStateManager.rotated(slopeAngle, slopeAlongX ? 0 : 1, 0, slopeAlongX ? 1 : 0);
if (onSlope)
GlStateManager.translated(0, 1 / 8f, 0);
Random r = new Random(transported.angle);
for (int i = 0; i <= count; i++) {
GlStateManager.pushMatrix();
GlStateManager.rotated(transported.angle, 0, 1, 0);
if (!blockItem) {
GlStateManager.translated(0, -.09375, 0);
GlStateManager.rotated(90, 1, 0, 0);
}
if (blockItem) {
GlStateManager.translated(r.nextFloat() * .0625f * i, 0, r.nextFloat() * .0625f * i);
}
GlStateManager.scaled(.5, .5, .5);
itemRenderer.renderItem(transported.stack, TransformType.FIXED);
GlStateManager.popMatrix();
if (!blockItem)
GlStateManager.rotated(10, 0, 1, 0);
GlStateManager.translated(0, blockItem ? 1 / 64d : 1 / 16d, 0);
}
RenderHelper.disableStandardItemLighting();
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
GlStateManager.disableBlend();
GlStateManager.popMatrix();
} }
protected BlockState getBeltState(KineticTileEntity te) { protected BlockState getBeltState(KineticTileEntity te) {

View file

@ -13,6 +13,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.gui.ScreenElementRenderer; import com.simibubi.create.foundation.gui.ScreenElementRenderer;
import com.simibubi.create.foundation.item.ItemDescription; import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity; import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
@ -22,6 +23,7 @@ import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -56,21 +58,28 @@ public class GaugeInformationRenderer {
BlockPos pos = result.getPos(); BlockPos pos = result.getPos();
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
ItemStack goggles = mc.player.getItemStackFromSlot(EquipmentSlotType.HEAD); ItemStack goggles = mc.player.getItemStackFromSlot(EquipmentSlotType.HEAD);
TileEntity te = world.getTileEntity(pos);
boolean notFastEnough = (te instanceof KineticTileEntity)
&& !((KineticTileEntity) te).isSpeedRequirementFulfilled() && ((KineticTileEntity) te).getSpeed() != 0;
if (!AllItems.GOGGLES.typeOf(goggles)) if (!AllItems.GOGGLES.typeOf(goggles) && !notFastEnough)
return; return;
if (mc.player.isSneaking()) if (mc.player.isSneaking())
return; return;
List<String> tooltip = new ArrayList<>(); List<String> tooltip = new ArrayList<>();
TileEntity te = world.getTileEntity(pos);
if (state.getBlock() instanceof GaugeBlock) if (notFastEnough) {
addSpeedRequirementMessage(state, tooltip, (KineticTileEntity) te);
goggles = AllItems.GOGGLES.asStack();
} else if (state.getBlock() instanceof GaugeBlock)
addGaugeTooltip(state, tooltip, te); addGaugeTooltip(state, tooltip, te);
if (te instanceof GeneratingKineticTileEntity) else {
addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te); if (te instanceof GeneratingKineticTileEntity)
if (te instanceof KineticTileEntity) addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te);
addStressTooltip(state, tooltip, (KineticTileEntity) te); if (te instanceof KineticTileEntity)
addStressTooltip(state, tooltip, (KineticTileEntity) te);
}
if (tooltip.isEmpty()) if (tooltip.isEmpty())
return; return;
@ -91,14 +100,22 @@ public class GaugeInformationRenderer {
tooltipScreen.init(mc, mc.mainWindow.getScaledWidth(), mc.mainWindow.getScaledHeight()); tooltipScreen.init(mc, mc.mainWindow.getScaledWidth(), mc.mainWindow.getScaledHeight());
tooltipScreen.renderTooltip(tooltip, tooltipScreen.width / 2, tooltipScreen.height / 2); tooltipScreen.renderTooltip(tooltip, tooltipScreen.width / 2, tooltipScreen.height / 2);
ItemStack item = goggles;
ScreenElementRenderer.render3DItem(() -> { ScreenElementRenderer.render3DItem(() -> {
GlStateManager.translated(tooltipScreen.width / 2 + 10, tooltipScreen.height / 2 - 16, 0); GlStateManager.translated(tooltipScreen.width / 2 + 10, tooltipScreen.height / 2 - 16, 0);
return goggles; return item;
}); });
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
private static void addSpeedRequirementMessage(BlockState state, List<String> tooltip, KineticTileEntity te) {
String spacing = " ";
tooltip.addAll(TooltipHelper.cutString(spacing
+ Lang.translate("gui.contraptions.not_fast_enough", I18n.format(state.getBlock().getTranslationKey())),
GRAY, TextFormatting.WHITE));
}
private static void addStressTooltip(BlockState state, List<String> tooltip, KineticTileEntity te) { private static void addStressTooltip(BlockState state, List<String> tooltip, KineticTileEntity te) {
String spacing = " "; String spacing = " ";
float stressApplied = te.getStressApplied(); float stressApplied = te.getStressApplied();

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.curiosities.tools; package com.simibubi.create.modules.curiosities.tools;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -63,13 +64,15 @@ public class BlazingToolItem extends AbstractToolItem {
} }
@Override @Override
public void modifyDrops(List<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) { public void modifyDrops(Collection<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) {
super.modifyDrops(drops, world, pos, tool, state); super.modifyDrops(drops, world, pos, tool, state);
World worldIn = world.getWorld(); World worldIn = world.getWorld();
helperFurnace.setWorld(worldIn); helperFurnace.setWorld(worldIn);
RecipeManager recipeManager = worldIn.getRecipeManager(); RecipeManager recipeManager = worldIn.getRecipeManager();
int enchantmentLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, tool); int enchantmentLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, tool);
if (state == null)
enchantmentLevel = 0;
List<ItemStack> smeltedStacks = new ArrayList<>(); List<ItemStack> smeltedStacks = new ArrayList<>();
Iterator<ItemStack> dropper = drops.iterator(); Iterator<ItemStack> dropper = drops.iterator();
while (dropper.hasNext()) { while (dropper.hasNext()) {

View file

@ -1,6 +1,6 @@
package com.simibubi.create.modules.curiosities.tools; package com.simibubi.create.modules.curiosities.tools;
import java.util.List; import java.util.Collection;
import com.simibubi.create.foundation.item.AbstractToolItem; import com.simibubi.create.foundation.item.AbstractToolItem;
import com.simibubi.create.foundation.item.AllToolTypes; import com.simibubi.create.foundation.item.AllToolTypes;
@ -25,7 +25,7 @@ public class ShadowSteelToolItem extends AbstractToolItem {
} }
@Override @Override
public void modifyDrops(List<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) { public void modifyDrops(Collection<ItemStack> drops, IWorld world, BlockPos pos, ItemStack tool, BlockState state) {
drops.clear(); drops.clear();
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.curiosities.tools; package com.simibubi.create.modules.curiosities.tools;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.AllPackets; import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.item.AbstractToolItem; import com.simibubi.create.foundation.item.AbstractToolItem;
@ -12,8 +13,10 @@ import net.minecraft.block.Blocks;
import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments; import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.EntityDamageSource; import net.minecraft.util.EntityDamageSource;
@ -111,15 +114,39 @@ public class ToolEvents {
} }
@SubscribeEvent @SubscribeEvent
public static void shadowSteelToolsDoNotDropEntityLoot(LivingDropsEvent event) { public static void toolsMayModifyEntityLoot(LivingDropsEvent event) {
if (!(event.getSource() instanceof EntityDamageSource)) if (!(event.getSource() instanceof EntityDamageSource))
return; return;
EntityDamageSource source = (EntityDamageSource) event.getSource(); EntityDamageSource source = (EntityDamageSource) event.getSource();
Entity target = event.getEntity();
Entity trueSource = source.getTrueSource(); Entity trueSource = source.getTrueSource();
World world = target.getEntityWorld();
if (trueSource != null && trueSource instanceof PlayerEntity) { if (trueSource != null && trueSource instanceof PlayerEntity) {
PlayerEntity player = (PlayerEntity) trueSource; PlayerEntity player = (PlayerEntity) trueSource;
if (player.getHeldItemMainhand().getItem() instanceof ShadowSteelToolItem) ItemStack heldItemMainhand = player.getHeldItemMainhand();
Item item = heldItemMainhand.getItem();
if (item instanceof ShadowSteelToolItem)
event.setCanceled(true); event.setCanceled(true);
if (item instanceof BlazingToolItem) {
BlazingToolItem blazingToolItem = (BlazingToolItem) item;
List<ItemStack> drops = event.getDrops().stream().map(entity -> {
ItemStack stack = entity.getItem();
entity.remove();
return stack;
}).collect(Collectors.toList());
blazingToolItem.modifyDrops(drops, world, player.getPosition(), heldItemMainhand, null);
event.getDrops().clear();
drops.stream().map(stack -> {
ItemEntity entity = new ItemEntity(world, target.posX, target.posY, target.posZ, stack);
world.addEntity(entity);
return entity;
}).forEach(event.getDrops()::add);
}
} }
} }

View file

@ -409,6 +409,8 @@
"create.gui.stress_gauge.overstressed": "Overstressed", "create.gui.stress_gauge.overstressed": "Overstressed",
"create.gui.stress_gauge.no_rotation": "No Rotation", "create.gui.stress_gauge.no_rotation": "No Rotation",
"create.gui.contraptions.not_fast_enough": "It appears that this %1$s is _not_ rotating with _enough_ _speed._",
"create.gui.flexcrate.title": "Adjustable Crate", "create.gui.flexcrate.title": "Adjustable Crate",
"create.gui.flexcrate.storageSpace": "Storage Space", "create.gui.flexcrate.storageSpace": "Storage Space",
@ -1115,7 +1117,7 @@
"item.create.slot_cover.tooltip.summary": "Used to mark a _Mechanical_ _Crafter_ as an empty slot in a recipe. Crafters do not necessarily have to form a full square grid, this cover find its use when there are recipes where _ingredients_ _are_ _diagonal_ to each other.", "item.create.slot_cover.tooltip.summary": "Used to mark a _Mechanical_ _Crafter_ as an empty slot in a recipe. Crafters do not necessarily have to form a full square grid, this cover find its use when there are recipes where _ingredients_ _are_ _diagonal_ to each other.",
"tool.create.shadow_steel.tooltip": "SHADOW STEEL TOOLS", "tool.create.shadow_steel.tooltip": "SHADOW STEEL TOOLS",
"tool.create.shadow_steel.tooltip.summary": "This tool breaks blocks _extremely_ _quick,_ but _shatters_ all of their _drops_ with them. Killed mobs can drop _more_ _experience_ based on the _Looting_ modifier of this tool.", "tool.create.shadow_steel.tooltip.summary": "A fast and powerful tool that _destroys_ _drops_ from any block or entity. Killed mobs can drop _more_ _experience_ based on the _Looting_ modifier of this tool.",
"tool.create.blazing.tooltip": "BLAZING TOOLS", "tool.create.blazing.tooltip": "BLAZING TOOLS",
"tool.create.blazing.tooltip.summary": "This tool will _melt_ _broken_ _blocks_ and _ignite_ _attacked_ _mobs._ It will not lose Durability while being used in the _Nether._", "tool.create.blazing.tooltip.summary": "This tool will _melt_ _broken_ _blocks_ and _ignite_ _attacked_ _mobs._ It will not lose Durability while being used in the _Nether._",