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.SWORD;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import com.simibubi.create.foundation.packet.SimplePacketBase;
@ -126,7 +126,7 @@ public abstract class AbstractToolItem extends ToolItem {
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) {

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;
if (blockState.getBlock() == Blocks.OBSIDIAN)
return false;
if (AllBlocks.BELT.typeOf(blockState))
return true;
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.saw.SawBlock;
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 net.minecraft.block.Block;
@ -48,6 +50,7 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
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.wrapper.CombinedInvWrapper;
@ -150,6 +153,14 @@ public abstract class Contraption {
return false;
if (AllBlocks.FLEXCRATE.typeOf(state))
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)
for (Direction offset : Direction.values()) {
@ -248,6 +259,7 @@ public abstract class Contraption {
NBTUtil.readBlockState(comp.getCompound("Block")),
comp.contains("Data") ? comp.getCompound("Data") : null);
blocks.put(info.pos, info);
if (world.isRemote) {
Block block = info.state.getBlock();
BlockRenderLayer renderLayer = block.getRenderLayer();
@ -255,23 +267,27 @@ public abstract class Contraption {
renderOrder.add(info.pos);
else
renderOrder.add(0, info.pos);
if (info.nbt == null || block instanceof IPortableBlock)
CompoundNBT tag = info.nbt;
if (tag == null || block instanceof IPortableBlock)
return;
info.nbt.putInt("x", info.pos.getX());
info.nbt.putInt("y", info.pos.getY());
info.nbt.putInt("z", info.pos.getZ());
TileEntity te = TileEntity.create(info.nbt);
tag.putInt("x", info.pos.getX());
tag.putInt("y", info.pos.getY());
tag.putInt("z", info.pos.getZ());
TileEntity te = TileEntity.create(tag);
te.setWorld(new WrappedWorld(world) {
@Override
public BlockState getBlockState(BlockPos pos) {
if (isOutsideBuildHeight(pos) || !pos.equals(te.getPos()))
if (!pos.equals(te.getPos()))
return Blocks.AIR.getDefaultState();
return info.state;
}
});
if (te instanceof KineticTileEntity)
((KineticTileEntity) te).setSpeed(0);
te.getBlockState();
customRenderTEs.add(te);
}
@ -392,13 +408,21 @@ public abstract class Contraption {
state = state.with(SawBlock.RUNNING, false);
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);
if (tileEntity != null && block.nbt != null) {
block.nbt.putInt("x", targetPos.getX());
block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt);
CompoundNBT tag = block.nbt;
if (tileEntity != null && tag != null) {
tag.putInt("x", targetPos.getX());
tag.putInt("y", targetPos.getY());
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) {
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;

View file

@ -1,7 +1,10 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.VecHelper;
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.SlabBlock;
@ -93,9 +96,49 @@ public class StructureTransform {
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)) {
state = state.with(BlockStateProperties.FACING,
transformFacing(state.get(BlockStateProperties.FACING)));
state =
state.with(BlockStateProperties.FACING, transformFacing(state.get(BlockStateProperties.FACING)));
} else if (state.has(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.LivingExperienceDropEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@ -86,7 +87,7 @@ public class DeployerFakePlayer extends FakePlayer {
event.setNewHeight(0);
}
@SubscribeEvent
@SubscribeEvent(priority = EventPriority.LOWEST)
public static void deployerCollectsDropsFromKilledEntities(LivingDropsEvent event) {
if (!(event.getSource() instanceof EntityDamageSource))
return;

View file

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

View file

@ -1,22 +1,30 @@
package com.simibubi.create.modules.contraptions.relays.belt;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.AllBlocks;
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.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.modules.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
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.MobEntity;
import net.minecraft.entity.item.ItemEntity;
@ -40,19 +48,21 @@ 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.MathHelper;
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.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IEnviromentBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraftforge.common.Tags;
import net.minecraftforge.items.CapabilityItemHandler;
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<Part> PART = EnumProperty.create("part", Part.class);
@ -90,13 +100,14 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
@SuppressWarnings("deprecation")
@Override
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))
drops.addAll(AllBlocks.BRASS_CASING.getDefault()
.getDrops(builder));
drops.addAll(AllBlocks.BRASS_CASING.getDefault().getDrops(builder));
return drops;
}
@Override
public void spawnAdditionalDrops(BlockState state, World worldIn, BlockPos pos, ItemStack stack) {
withTileEntityDo(worldIn, pos, te -> {
@ -170,8 +181,10 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
TransportedEntityInfo info = controller.passengers.get(entityIn);
if (info.ticksSinceLastCollision != 0 || pos.equals(entityIn.getPosition()))
info.refresh(pos, state);
} else
} else {
controller.passengers.put(entityIn, new TransportedEntityInfo(pos, state));
entityIn.onGround = true;
}
}
@Override
@ -295,12 +308,52 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
@Override
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
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
@ -314,7 +367,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
if (controller == null)
return shape;
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;
@ -326,41 +379,112 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
}
@Override
public boolean canRenderInLayer(BlockState state, BlockRenderLayer layer) {
return state.get(CASING) && layer == getRenderLayer();
public BlockRenderType getRenderType(BlockState state) {
return state.get(CASING) && state.get(SLOPE) != Slope.VERTICAL ? BlockRenderType.MODEL
: BlockRenderType.ENTITYBLOCK_ANIMATED;
}
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (worldIn.isRemote)
public boolean canRenderInLayer(BlockState state, BlockRenderLayer layer) {
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;
if (state.getBlock() == newState.getBlock())
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
boolean endWasDestroyed = state.get(PART) == Part.END;
TileEntity tileEntity = worldIn.getTileEntity(pos);
if (tileEntity == null)
return;
if (!(tileEntity instanceof BeltTileEntity))
return;
BeltTileEntity beltEntity = (BeltTileEntity) tileEntity;
BlockPos controller = beltEntity.getController();
beltEntity.remove();
for (boolean forward : Iterate.trueAndFalse) {
BlockPos currentPos = nextSegmentPosition(state, pos, forward);
if (currentPos == null)
continue;
BlockState currentState = world.getBlockState(currentPos);
if (!AllBlocks.BELT.typeOf(currentState))
continue;
if (currentState.get(CASING))
Block.spawnAsEntity(world, currentPos, new ItemStack(AllBlocks.BRASS_CASING.get()));
int limit = 1000;
BlockPos toDestroy = controller;
BlockState destroyedBlock = null;
do {
if (!toDestroy.equals(pos)) {
destroyedBlock = worldIn.getBlockState(toDestroy);
if (!AllBlocks.BELT.typeOf(destroyedBlock))
break;
BeltTileEntity te = (BeltTileEntity) worldIn.getTileEntity(toDestroy);
boolean hasPulley = false;
TileEntity tileEntity = world.getTileEntity(currentPos);
if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity te = (BeltTileEntity) tileEntity;
if (te.isController()) {
BeltInventory inv = te.getInventory();
for (TransportedItemStack stack : inv.items)
@ -368,36 +492,14 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
}
te.remove();
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;
hasPulley = te.hasPulley();
}
Slope slope = state.get(SLOPE);
Direction direction = state.get(HORIZONTAL_FACING);
if (slope == Slope.VERTICAL) {
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);
BlockState shaftState =
AllBlocks.SHAFT.get().getDefaultState().with(BlockStateProperties.AXIS, getRotationAxis(currentState));
world.setBlockState(currentPos, hasPulley ? shaftState : Blocks.AIR.getDefaultState(), 3);
world.playEvent(2001, currentPos, Block.getStateId(currentState));
}
}
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))
return positions;
Slope slope = blockState.get(SLOPE);
Direction direction = blockState.get(HORIZONTAL_FACING);
int limit = 1000;
BlockPos current = controllerPos;
do {
while (limit-- > 0 && current != null) {
positions.add(current);
if (!AllBlocks.BELT.typeOf(world.getBlockState(current)))
BlockState state = world.getBlockState(current);
if (!AllBlocks.BELT.typeOf(state))
break;
if (world.getBlockState(current).get(PART) == Part.END)
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);
current = nextSegmentPosition(state, current, true);
}
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
protected boolean hasStaticPart() {
return false;
@ -489,4 +597,26 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
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);
BlockState beltBlock = AllBlocks.BELT.get().getDefaultState();
int index = 0;
for (BlockPos pos : beltsToCreate) {
BeltBlock.Part part = pos.equals(start) ? Part.START : pos.equals(end) ? Part.END : Part.MIDDLE;
boolean pulley = AllBlocks.SHAFT.typeOf(world.getBlockState(pos));
@ -110,15 +109,6 @@ public class BeltConnectorItem extends BlockItem implements IAddedByOther {
part = Part.PULLEY;
world.setBlockState(pos, beltBlock.with(BeltBlock.SLOPE, slope).with(BeltBlock.PART, part)
.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;
if (Math.abs(diff) <= spacing)
continue;
movement = beltMovementPositive ? Math.min(movement, diff - spacing)
: Math.max(movement, diff + spacing);
movement =
beltMovementPositive ? Math.min(movement, diff - spacing) : Math.max(movement, diff + spacing);
}
// Determine current segment
@ -104,8 +104,8 @@ public class BeltInventory {
// Don't move beyond the edge
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
float limitedMovement = beltMovementPositive ? Math.min(movement, diffToEnd)
: Math.max(movement, diffToEnd);
float limitedMovement =
beltMovementPositive ? Math.min(movement, diffToEnd) : Math.max(movement, diffToEnd);
float nextOffset = current.beltPosition + limitedMovement;
if (!onClient) {
@ -204,12 +204,12 @@ public class BeltInventory {
if (AllBlocks.BASIN.typeOf(state) || AllBlocks.SAW.typeOf(state)) {
TileEntity te = world.getTileEntity(nextPosition);
if (te != null) {
LazyOptional<IItemHandler> optional = te
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
LazyOptional<IItemHandler> optional =
te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
if (optional.isPresent()) {
IItemHandler itemHandler = optional.orElse(null);
ItemStack remainder = ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(),
false);
ItemStack remainder =
ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(), false);
if (remainder.equals(current.stack, false))
continue;
@ -272,7 +272,7 @@ public class BeltInventory {
return false;
Direction flapFacing = movementDirection.getOpposite();
BeltTunnelTileEntity tunnel = (BeltTunnelTileEntity) te;
if (!tunnel.flaps.containsKey(flapFacing))
return false;
@ -385,6 +385,7 @@ public class BeltInventory {
outPos.add(outMotion.normalize());
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y + 6 / 16f, outPos.z, ejected);
entity.setMotion(outMotion);
entity.setDefaultPickupDelay();
entity.velocityChanged = true;
belt.getWorld().addEntity(entity);
}
@ -398,8 +399,12 @@ public class BeltInventory {
verticalMovement = verticalMovement * (Math.min(offset, belt.beltLength - .5f) - .5f);
Vec3d vec = VecHelper.getCenterOf(belt.getPos());
vec = vec.add(new Vec3d(belt.getBeltFacing().getDirectionVec()).scale(offset - .5f)).add(0, verticalMovement,
0);
Vec3d horizontalMovement = new Vec3d(belt.getBeltFacing().getDirectionVec()).scale(offset - .5f);
if (slope == Slope.VERTICAL)
horizontalMovement = Vec3d.ZERO;
vec = vec.add(horizontalMovement).add(0, verticalMovement, 0);
return vec;
}

View file

@ -78,7 +78,7 @@ public class BeltMovementHandler {
// Too slow
boolean notHorizontal = beltTe.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL;
if (Math.abs(beltTe.getSpeed()) < (notHorizontal ? 32 : 1))
if (Math.abs(beltTe.getSpeed()) < 1)
return;
// Not on top
@ -158,6 +158,8 @@ public class BeltMovementHandler {
}
}
entityIn.fallDistance = 0;
if (movingUp) {
float minVelocity = .13f;
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 java.util.HashMap;
import java.util.Map;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
@ -98,6 +101,8 @@ public class BeltShapes {
private static final VoxelShaper
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){
return VoxelShapes.or(
@ -134,6 +139,22 @@ public class BeltShapes {
}
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);
Axis axis = facing.getAxis();
Part part = state.get(BeltBlock.PART);
@ -166,10 +187,9 @@ public class BeltShapes {
//bad state
return VoxelShapes.empty();
}
public static VoxelShape getCasingShape(BlockState state) {
private static VoxelShape getCasingShape(BlockState state) {
if (!state.get(BeltBlock.CASING))
return VoxelShapes.empty();

View file

@ -61,23 +61,21 @@ public class BeltTileEntity extends KineticTileEntity {
attachmentTracker = new Tracker(this);
itemHandler = LazyOptional.empty();
color = -1;
beltLength = -1;
index = -1;
}
@Override
public void initialize() {
super.initialize();
// 0.1 belt
if (beltLength == 0) {
world.destroyBlock(pos, true);
}
}
@Override
public void tick() {
super.tick();
// Init belt
if (beltLength == 0)
BeltBlock.initBelt(world, pos);
// Initialize Belt Attachments
if (world != null && trackerUpdateTag != null) {
attachmentTracker.readAndSearch(trackerUpdateTag, this);
@ -100,9 +98,8 @@ public class BeltTileEntity extends KineticTileEntity {
List<Entity> toRemove = new ArrayList<>();
passengers.forEach((entity, info) -> {
boolean canBeTransported = BeltMovementHandler.canBeTransported(entity);
boolean leftTheBelt = info.ticksSinceLastCollision > ((getBlockState().get(BeltBlock.SLOPE) != HORIZONTAL)
? 3
: 1);
boolean leftTheBelt =
info.ticksSinceLastCollision > ((getBlockState().get(BeltBlock.SLOPE) != HORIZONTAL) ? 3 : 1);
if (!canBeTransported || leftTheBelt) {
toRemove.add(entity);
return;
@ -165,6 +162,7 @@ public class BeltTileEntity extends KineticTileEntity {
public CompoundNBT write(CompoundNBT compound) {
attachmentTracker.write(compound);
compound.put("Controller", NBTUtil.writeBlockPos(controller));
compound.putBoolean("IsController", isController());
compound.putInt("Color", color);
compound.putInt("Length", beltLength);
compound.putInt("Index", index);
@ -177,8 +175,13 @@ public class BeltTileEntity extends KineticTileEntity {
@Override
public void read(CompoundNBT compound) {
super.read(compound);
trackerUpdateTag = compound;
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
if (compound.getBoolean("IsController"))
controller = pos;
else
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
if (!compound.contains("DontClearAttachments"))
trackerUpdateTag = compound;
color = compound.getInt("Color");
beltLength = compound.getInt("Length");
index = compound.getInt("Index");
@ -249,8 +252,8 @@ public class BeltTileEntity extends KineticTileEntity {
if (part == MIDDLE)
return false;
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1))
^ direction.getAxis() == Axis.X;
boolean movingPositively =
(getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1)) ^ direction.getAxis() == Axis.X;
return part == Part.START ^ movingPositively;
}
@ -305,8 +308,9 @@ public class BeltTileEntity extends KineticTileEntity {
return controllerTE.getInventory();
return null;
}
if (inventory == null)
if (inventory == null) {
inventory = new BeltInventory(this);
}
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.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
@ -47,15 +48,15 @@ public class BeltTileEntityRenderer extends SafeTileEntityRenderer<BeltTileEntit
}
@Override
public void renderFast(BeltTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) {
public void renderFast(BeltTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
BufferBuilder buffer) {
BlockState blockState = te.getBlockState();
if (!AllBlocks.BELT.typeOf(blockState))
return;
BlockState renderedState = getBeltState(te);
SuperByteBuffer beltBuffer = CreateClient.bufferCache.renderBlockIn(KineticTileEntityRenderer.KINETIC_TILE,
renderedState);
SuperByteBuffer beltBuffer =
CreateClient.bufferCache.renderBlockIn(KineticTileEntityRenderer.KINETIC_TILE, renderedState);
beltBuffer.color(te.color == -1 ? 0x808080 : te.color);
@ -64,8 +65,8 @@ public class BeltTileEntityRenderer extends SafeTileEntityRenderer<BeltTileEntit
if (animatedTexture == null)
animatedTexture = SpriteShifter.get("block/belt", "block/belt_animated");
if (speed != 0) {
float time = AnimationTickHolder.getRenderTick()
* blockState.get(HORIZONTAL_FACING).getAxisDirection().getOffset();
float time =
AnimationTickHolder.getRenderTick() * blockState.get(HORIZONTAL_FACING).getAxisDirection().getOffset();
if (renderedState.get(BeltBlock.HORIZONTAL_FACING).getAxis() == Axis.X)
speed = -speed;
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) {
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();
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();
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();
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();
if (te.getSpeed() == 0) {
offset = transported.beltPosition;
sideOffset = transported.sideOffset;
}
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.disableBlend();
GlStateManager.popMatrix();
}
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.foundation.gui.ScreenElementRenderer;
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.modules.contraptions.base.GeneratingKineticTileEntity;
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.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ItemStack;
@ -56,21 +58,28 @@ public class GaugeInformationRenderer {
BlockPos pos = result.getPos();
BlockState state = world.getBlockState(pos);
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;
if (mc.player.isSneaking())
return;
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);
if (te instanceof GeneratingKineticTileEntity)
addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te);
if (te instanceof KineticTileEntity)
addStressTooltip(state, tooltip, (KineticTileEntity) te);
else {
if (te instanceof GeneratingKineticTileEntity)
addGeneratorTooltip(state, tooltip, (GeneratingKineticTileEntity) te);
if (te instanceof KineticTileEntity)
addStressTooltip(state, tooltip, (KineticTileEntity) te);
}
if (tooltip.isEmpty())
return;
@ -91,14 +100,22 @@ public class GaugeInformationRenderer {
tooltipScreen.init(mc, mc.mainWindow.getScaledWidth(), mc.mainWindow.getScaledHeight());
tooltipScreen.renderTooltip(tooltip, tooltipScreen.width / 2, tooltipScreen.height / 2);
ItemStack item = goggles;
ScreenElementRenderer.render3DItem(() -> {
GlStateManager.translated(tooltipScreen.width / 2 + 10, tooltipScreen.height / 2 - 16, 0);
return goggles;
return item;
});
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) {
String spacing = " ";
float stressApplied = te.getStressApplied();

View file

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

View file

@ -1,6 +1,6 @@
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.AllToolTypes;
@ -25,7 +25,7 @@ public class ShadowSteelToolItem extends AbstractToolItem {
}
@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();
}

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.curiosities.tools;
import java.util.List;
import java.util.stream.Collectors;
import com.simibubi.create.AllPackets;
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.Enchantments;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.EntityDamageSource;
@ -111,15 +114,39 @@ public class ToolEvents {
}
@SubscribeEvent
public static void shadowSteelToolsDoNotDropEntityLoot(LivingDropsEvent event) {
public static void toolsMayModifyEntityLoot(LivingDropsEvent event) {
if (!(event.getSource() instanceof EntityDamageSource))
return;
EntityDamageSource source = (EntityDamageSource) event.getSource();
Entity target = event.getEntity();
Entity trueSource = source.getTrueSource();
World world = target.getEntityWorld();
if (trueSource != null && trueSource instanceof PlayerEntity) {
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);
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

@ -408,6 +408,8 @@
"create.gui.stress_gauge.capacity": "Remaining Capacity",
"create.gui.stress_gauge.overstressed": "Overstressed",
"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.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.",
"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.summary": "This tool will _melt_ _broken_ _blocks_ and _ignite_ _attacked_ _mobs._ It will not lose Durability while being used in the _Nether._",