mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-23 21:46:40 +01:00
From Entity to Inventory
- Started work on belts no longer moving itementities around
This commit is contained in:
parent
c2814f8ad2
commit
25cac1fe8e
16 changed files with 1174 additions and 475 deletions
|
@ -6,7 +6,7 @@ import com.simibubi.create.modules.IModule;
|
|||
import com.simibubi.create.modules.contraptions.WrenchItem;
|
||||
import com.simibubi.create.modules.contraptions.WrenchItemRenderer;
|
||||
import com.simibubi.create.modules.contraptions.relays.VerticalGearboxItem;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltItem;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltConnectorItem;
|
||||
import com.simibubi.create.modules.curiosities.ChromaticCompoundCubeItem;
|
||||
import com.simibubi.create.modules.curiosities.deforester.DeforesterItem;
|
||||
import com.simibubi.create.modules.curiosities.deforester.DeforesterItemRenderer;
|
||||
|
@ -82,7 +82,7 @@ public enum AllItems {
|
|||
BLUEPRINT(new SchematicItem(standardItemProperties())),
|
||||
|
||||
__CONTRAPTIONS__(),
|
||||
BELT_CONNECTOR(new BeltItem(standardItemProperties())),
|
||||
BELT_CONNECTOR(new BeltConnectorItem(standardItemProperties())),
|
||||
VERTICAL_GEARBOX(new VerticalGearboxItem(new Properties())),
|
||||
FLOUR(ingredient()),
|
||||
DOUGH(ingredient()),
|
||||
|
|
|
@ -10,7 +10,7 @@ import com.simibubi.create.foundation.utility.TooltipHelper;
|
|||
import com.simibubi.create.modules.contraptions.KineticDebugger;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.TurntableHandler;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltItemHandler;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltConnectorItemHandler;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -56,7 +56,7 @@ public class ClientEvents {
|
|||
|
||||
public static void onGameTick() {
|
||||
CreateClient.gameTick();
|
||||
BeltItemHandler.gameTick();
|
||||
BeltConnectorItemHandler.gameTick();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
|
|||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalBearingTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.FastItemRenderer;
|
||||
|
||||
import net.minecraft.client.resources.ReloadListener;
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
|
@ -22,6 +23,7 @@ public class CachedBufferReloader extends ReloadListener<String> {
|
|||
ContraptionRenderer.invalidateCache();
|
||||
MechanicalBearingTileEntityRenderer.invalidateCache();
|
||||
ColoredIndicatorRenderer.invalidateCache();
|
||||
FastItemRenderer.invalidateCache();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -76,12 +76,6 @@ public class RotationPropagator {
|
|||
return connected ? 1 : 0;
|
||||
}
|
||||
|
||||
// Attached Fans
|
||||
if (ENCASED_FAN.typeOf(stateFrom) && ENCASED_FAN.typeOf(stateTo)) {
|
||||
if (stateFrom.get(AXIS) == stateTo.get(AXIS))
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Large Gear <-> Large Gear
|
||||
if (isLargeToLargeGear(stateFrom, stateTo, diff)) {
|
||||
Axis sourceAxis = stateFrom.get(AXIS);
|
||||
|
|
|
@ -34,7 +34,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
|||
@EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class KineticTileEntityRenderer extends TileEntityRendererFast<KineticTileEntity> {
|
||||
|
||||
protected static Map<BlockState, BufferManipulator> cachedBuffers;
|
||||
public static Map<BlockState, BufferManipulator> cachedBuffers;
|
||||
public static boolean rainbowMode = false;
|
||||
|
||||
public static class BlockModelSpinner extends BufferManipulator {
|
||||
|
|
|
@ -9,12 +9,13 @@ import com.simibubi.create.foundation.block.IWithTileEntity;
|
|||
import com.simibubi.create.foundation.block.IWithoutBlockItem;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity.TransportedEntityInfo;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -31,121 +32,90 @@ import net.minecraft.util.IStringSerializable;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
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.IWorldReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
|
||||
public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockItem, IWithTileEntity<BeltTileEntity> {
|
||||
|
||||
public static final IProperty<Slope> SLOPE = EnumProperty.create("slope", Slope.class);
|
||||
public static final IProperty<Part> PART = EnumProperty.create("part", Part.class);
|
||||
|
||||
private static final VoxelShape FULL = makeCuboidShape(0, 0, 0, 16, 16, 16),
|
||||
FLAT_STRAIGHT_X = makeCuboidShape(1, 3, 0, 15, 13, 16),
|
||||
FLAT_STRAIGHT_Z = makeCuboidShape(0, 3, 1, 16, 13, 15),
|
||||
VERTICAL_STRAIGHT_X = makeCuboidShape(3, 0, 1, 13, 16, 15),
|
||||
VERTICAL_STRAIGHT_Z = makeCuboidShape(1, 0, 3, 15, 16, 13),
|
||||
|
||||
SLOPE_END_EAST = makeCuboidShape(0, 3, 1, 10, 13, 15),
|
||||
SLOPE_END_WEST = makeCuboidShape(6, 3, 1, 16, 13, 15),
|
||||
SLOPE_END_SOUTH = makeCuboidShape(1, 3, 0, 15, 13, 10),
|
||||
SLOPE_END_NORTH = makeCuboidShape(1, 3, 6, 15, 13, 16),
|
||||
|
||||
SLOPE_BUILDING_BLOCK_X = makeCuboidShape(5, 5, 1, 11, 11, 15),
|
||||
SLOPE_BUILDING_BLOCK_Z = makeCuboidShape(1, 5, 5, 15, 11, 11),
|
||||
|
||||
SLOPE_UPWARD_END_EAST = VoxelShapes.or(SLOPE_END_EAST, createHalfSlope(Direction.EAST, false)),
|
||||
SLOPE_UPWARD_END_WEST = VoxelShapes.or(SLOPE_END_WEST, createHalfSlope(Direction.WEST, false)),
|
||||
SLOPE_UPWARD_END_SOUTH = VoxelShapes.or(SLOPE_END_SOUTH, createHalfSlope(Direction.SOUTH, false)),
|
||||
SLOPE_UPWARD_END_NORTH = VoxelShapes.or(SLOPE_END_NORTH, createHalfSlope(Direction.NORTH, false)),
|
||||
|
||||
SLOPE_DOWNWARD_END_EAST = VoxelShapes.or(SLOPE_END_EAST, createHalfSlope(Direction.EAST, true)),
|
||||
SLOPE_DOWNWARD_END_WEST = VoxelShapes.or(SLOPE_END_WEST, createHalfSlope(Direction.WEST, true)),
|
||||
SLOPE_DOWNWARD_END_SOUTH = VoxelShapes.or(SLOPE_END_SOUTH, createHalfSlope(Direction.SOUTH, true)),
|
||||
SLOPE_DOWNWARD_END_NORTH = VoxelShapes.or(SLOPE_END_NORTH, createHalfSlope(Direction.NORTH, true)),
|
||||
|
||||
SLOPE_EAST = createSlope(Direction.EAST), SLOPE_WEST = createSlope(Direction.WEST),
|
||||
SLOPE_NORTH = createSlope(Direction.NORTH), SLOPE_SOUTH = createSlope(Direction.SOUTH);
|
||||
|
||||
public BeltBlock() {
|
||||
super(Properties.from(Blocks.BROWN_WOOL));
|
||||
setDefaultState(getDefaultState().with(SLOPE, Slope.HORIZONTAL).with(PART, Part.START));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) {
|
||||
if (face.getAxis() != getRotationAxis(state))
|
||||
return false;
|
||||
BeltTileEntity beltEntity = (BeltTileEntity) world.getTileEntity(pos);
|
||||
return beltEntity != null && beltEntity.hasPulley();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Axis getRotationAxis(BlockState state) {
|
||||
return state.get(HORIZONTAL_FACING).rotateY().getAxis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
|
||||
PlayerEntity player) {
|
||||
return new ItemStack(AllItems.BELT_CONNECTOR.item);
|
||||
return AllItems.BELT_CONNECTOR.asStack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLanded(IBlockReader worldIn, Entity entityIn) {
|
||||
super.onLanded(worldIn, entityIn);
|
||||
|
||||
if (entityIn instanceof PlayerEntity && entityIn.isSneaking())
|
||||
return;
|
||||
if (entityIn instanceof PlayerEntity && ((PlayerEntity) entityIn).moveVertical > 0)
|
||||
return;
|
||||
|
||||
BeltTileEntity belt = null;
|
||||
BlockPos entityPosition = entityIn.getPosition();
|
||||
BlockPos beltPos = null;
|
||||
|
||||
if (AllBlocks.BELT.typeOf(worldIn.getBlockState(entityPosition)))
|
||||
belt = (BeltTileEntity) worldIn.getTileEntity(entityPosition);
|
||||
beltPos = entityPosition;
|
||||
else if (AllBlocks.BELT.typeOf(worldIn.getBlockState(entityPosition.down())))
|
||||
belt = (BeltTileEntity) worldIn.getTileEntity(entityPosition.down());
|
||||
|
||||
if (belt == null || !belt.hasSource())
|
||||
beltPos = entityPosition.down();
|
||||
if (beltPos == null)
|
||||
return;
|
||||
if (!(worldIn instanceof World))
|
||||
return;
|
||||
|
||||
BeltTileEntity controller = (BeltTileEntity) worldIn.getTileEntity(belt.getController());
|
||||
|
||||
if (controller == null)
|
||||
return;
|
||||
if (controller.passengers == null)
|
||||
return;
|
||||
|
||||
if (controller.passengers.containsKey(entityIn))
|
||||
controller.passengers.get(entityIn).refresh(belt.getPos(), belt.getBlockState());
|
||||
else
|
||||
controller.passengers.put(entityIn, new TransportedEntityInfo(belt.getPos(), belt.getBlockState()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness(BlockState state, IWorldReader world, BlockPos pos, Entity entity) {
|
||||
return super.getSlipperiness(state, world, pos, entity);
|
||||
onEntityCollision(worldIn.getBlockState(beltPos), (World) worldIn, beltPos, entityIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(BlockState state, World worldIn, BlockPos pos, Entity entityIn) {
|
||||
if (entityIn instanceof PlayerEntity && entityIn.isSneaking())
|
||||
return;
|
||||
if (entityIn instanceof PlayerEntity && ((PlayerEntity) entityIn).moveVertical > 0)
|
||||
return;
|
||||
|
||||
BeltTileEntity belt = null;
|
||||
belt = (BeltTileEntity) worldIn.getTileEntity(pos);
|
||||
|
||||
if (belt == null || !belt.hasSource())
|
||||
if (entityIn instanceof PlayerEntity && entityIn.isSneaking())
|
||||
return;
|
||||
if (belt == null || belt.getSpeed() == 0)
|
||||
return;
|
||||
if (entityIn instanceof ItemEntity && entityIn.isAlive()) {
|
||||
if (worldIn.isRemote)
|
||||
return;
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
ItemEntity itemEntity = (ItemEntity) entityIn;
|
||||
ItemStack remainder = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
.orElseGet(() -> new ItemStackHandler(0)).insertItem(0, itemEntity.getItem().copy(), false);
|
||||
if (remainder.isEmpty())
|
||||
itemEntity.remove();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
BeltTileEntity controller = (BeltTileEntity) worldIn.getTileEntity(belt.getController());
|
||||
|
||||
if (controller == null)
|
||||
if (controller == null || controller.passengers == null)
|
||||
return;
|
||||
if (controller.passengers == null)
|
||||
return;
|
||||
|
||||
if (controller.passengers.containsKey(entityIn)) {
|
||||
TransportedEntityInfo transportedEntityInfo = controller.passengers.get(entityIn);
|
||||
if (transportedEntityInfo.ticksSinceLastCollision != 0 || pos.equals(entityIn.getPosition()))
|
||||
transportedEntityInfo.refresh(pos, state);
|
||||
TransportedEntityInfo info = controller.passengers.get(entityIn);
|
||||
if (info.ticksSinceLastCollision != 0 || pos.equals(entityIn.getPosition()))
|
||||
info.refresh(pos, state);
|
||||
} else
|
||||
controller.passengers.put(entityIn, new TransportedEntityInfo(pos, state));
|
||||
}
|
||||
|
@ -167,7 +137,12 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
return false;
|
||||
if (worldIn.isRemote)
|
||||
return true;
|
||||
withTileEntityDo(worldIn, pos, te -> te.applyColor(DyeColor.getColor(heldItem)));
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
DyeColor dyeColor = DyeColor.getColor(heldItem);
|
||||
if (dyeColor == null)
|
||||
return;
|
||||
te.applyColor(dyeColor);
|
||||
});
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
return true;
|
||||
|
@ -186,45 +161,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
|
||||
Direction facing = state.get(HORIZONTAL_FACING);
|
||||
Axis axis = facing.getAxis();
|
||||
Part part = state.get(PART);
|
||||
Slope slope = state.get(SLOPE);
|
||||
|
||||
if (slope == Slope.HORIZONTAL)
|
||||
return axis == Axis.Z ? FLAT_STRAIGHT_X : FLAT_STRAIGHT_Z;
|
||||
if (slope == Slope.VERTICAL)
|
||||
return axis == Axis.X ? VERTICAL_STRAIGHT_X : VERTICAL_STRAIGHT_Z;
|
||||
|
||||
if (part != Part.MIDDLE) {
|
||||
if (part == Part.START)
|
||||
slope = slope == Slope.UPWARD ? Slope.DOWNWARD : Slope.UPWARD;
|
||||
else
|
||||
facing = facing.getOpposite();
|
||||
|
||||
if (facing == Direction.NORTH)
|
||||
return slope == Slope.UPWARD ? SLOPE_UPWARD_END_NORTH : SLOPE_DOWNWARD_END_NORTH;
|
||||
if (facing == Direction.SOUTH)
|
||||
return slope == Slope.UPWARD ? SLOPE_UPWARD_END_SOUTH : SLOPE_DOWNWARD_END_SOUTH;
|
||||
if (facing == Direction.EAST)
|
||||
return slope == Slope.UPWARD ? SLOPE_UPWARD_END_EAST : SLOPE_DOWNWARD_END_EAST;
|
||||
if (facing == Direction.WEST)
|
||||
return slope == Slope.UPWARD ? SLOPE_UPWARD_END_WEST : SLOPE_DOWNWARD_END_WEST;
|
||||
}
|
||||
|
||||
if (slope == Slope.DOWNWARD)
|
||||
facing = facing.getOpposite();
|
||||
|
||||
if (facing == Direction.NORTH)
|
||||
return SLOPE_NORTH;
|
||||
if (facing == Direction.SOUTH)
|
||||
return SLOPE_SOUTH;
|
||||
if (facing == Direction.EAST)
|
||||
return SLOPE_EAST;
|
||||
if (facing == Direction.WEST)
|
||||
return SLOPE_WEST;
|
||||
|
||||
return FULL;
|
||||
return BeltShapes.getShape(state, worldIn, pos, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -308,19 +245,6 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) {
|
||||
if (face.getAxis() != getRotationAxis(state))
|
||||
return false;
|
||||
BeltTileEntity beltEntity = (BeltTileEntity) world.getTileEntity(pos);
|
||||
return beltEntity != null && beltEntity.hasPulley();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Axis getRotationAxis(BlockState state) {
|
||||
return state.get(HORIZONTAL_FACING).getAxis() == Axis.X ? Axis.Z : Axis.X;
|
||||
}
|
||||
|
||||
public enum Slope implements IStringSerializable {
|
||||
HORIZONTAL, UPWARD, DOWNWARD, VERTICAL;
|
||||
|
||||
|
@ -339,18 +263,6 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isUpperEnd(BlockState state, float speed) {
|
||||
Direction facing = state.get(HORIZONTAL_FACING);
|
||||
if (state.get(SLOPE) == Slope.UPWARD && state.get(PART) == Part.END) {
|
||||
return facing.getAxisDirection().getOffset() * Math.signum(speed) == (facing.getAxis() == Axis.X ? -1 : 1);
|
||||
}
|
||||
if (state.get(SLOPE) == Slope.DOWNWARD && state.get(PART) == Part.START) {
|
||||
return facing.getAxisDirection().getOffset() * Math.signum(speed) == (facing.getAxis() == Axis.Z ? -1 : 1);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<BlockPos> getBeltChain(World world, BlockPos controllerPos) {
|
||||
List<BlockPos> positions = new LinkedList<>();
|
||||
|
||||
|
@ -382,33 +294,4 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
return positions;
|
||||
}
|
||||
|
||||
protected static VoxelShape createSlope(Direction facing) {
|
||||
return VoxelShapes.or(createHalfSlope(facing.getOpposite(), false), createHalfSlope(facing, true));
|
||||
}
|
||||
|
||||
protected static VoxelShape createHalfSlope(Direction facing, boolean upward) {
|
||||
VoxelShape shape = VoxelShapes.empty();
|
||||
VoxelShape buildingBlock = facing.getAxis() == Axis.X ? SLOPE_BUILDING_BLOCK_X : SLOPE_BUILDING_BLOCK_Z;
|
||||
Vec3i directionVec = facing.getDirectionVec();
|
||||
|
||||
int x = directionVec.getX();
|
||||
int y = upward ? 1 : -1;
|
||||
int z = directionVec.getZ();
|
||||
|
||||
for (int segment = 0; segment < 6; segment++)
|
||||
shape = VoxelShapes.or(shape,
|
||||
buildingBlock.withOffset(x * segment / 16f, y * segment / 16f, z * segment / 16f));
|
||||
|
||||
if (!upward)
|
||||
return shape;
|
||||
|
||||
VoxelShape mask = makeCuboidShape(0, -8, 0, 16, 24, 16);
|
||||
for (int segment = 6; segment < 11; segment++)
|
||||
shape = VoxelShapes.or(shape,
|
||||
VoxelShapes.combine(mask,
|
||||
buildingBlock.withOffset(x * segment / 16f, y * segment / 16f, z * segment / 16f),
|
||||
IBooleanFunction.AND));
|
||||
return shape;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateConfig;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.ShaftBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
|
||||
|
@ -22,9 +23,9 @@ import net.minecraft.util.Direction.AxisDirection;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BeltItem extends Item {
|
||||
public class BeltConnectorItem extends Item {
|
||||
|
||||
public BeltItem(Properties properties) {
|
||||
public BeltConnectorItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
|
@ -95,11 +96,22 @@ public class BeltItem extends Item {
|
|||
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));
|
||||
world.setBlockState(pos, beltBlock.with(BeltBlock.SLOPE, slope).with(BeltBlock.PART, part)
|
||||
.with(BeltBlock.HORIZONTAL_FACING, facing), 3);
|
||||
connectBelt(world, pos, start);
|
||||
|
||||
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(pos);
|
||||
if (te != null) {
|
||||
te.setController(start);
|
||||
te.beltLength = beltsToCreate.size();
|
||||
te.index = index;
|
||||
te.hasPulley = pulley;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,12 +163,6 @@ public class BeltItem extends Item {
|
|||
return positions;
|
||||
}
|
||||
|
||||
private void connectBelt(World world, BlockPos pos, BlockPos target) {
|
||||
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(pos);
|
||||
if (te != null)
|
||||
te.setController(target);
|
||||
}
|
||||
|
||||
public static boolean canConnect(World world, BlockPos first, BlockPos second) {
|
||||
if (!world.isAreaLoaded(first, 1))
|
||||
return false;
|
||||
|
@ -190,11 +196,15 @@ public class BeltItem extends Item {
|
|||
int limit = 1000;
|
||||
for (BlockPos currentPos = first.add(step); !currentPos.equals(second)
|
||||
&& limit-- > 0; currentPos = currentPos.add(step)) {
|
||||
if (!world.getBlockState(currentPos).getMaterial().isReplaceable())
|
||||
BlockState blockState = world.getBlockState(currentPos);
|
||||
if (AllBlocks.SHAFT.typeOf(blockState) && blockState.get(ShaftBlock.AXIS) == axis)
|
||||
continue;
|
||||
if (!blockState.getMaterial().isReplaceable())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static boolean validateAxis(World world, BlockPos pos) {
|
|
@ -23,7 +23,7 @@ import net.minecraft.util.math.RayTraceResult;
|
|||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BeltItemHandler {
|
||||
public class BeltConnectorItemHandler {
|
||||
|
||||
private static Random r = new Random();
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class BeltItemHandler {
|
|||
if (!selected.withinDistance(first, CreateConfig.parameters.maxBeltLength.get()))
|
||||
return;
|
||||
|
||||
boolean canConnect = BeltItem.validateAxis(world, selected) && BeltItem.canConnect(world, first, selected);
|
||||
boolean canConnect = BeltConnectorItem.validateAxis(world, selected) && BeltConnectorItem.canConnect(world, first, selected);
|
||||
|
||||
Vec3d start = new Vec3d(first);
|
||||
Vec3d end = new Vec3d(selected);
|
|
@ -0,0 +1,352 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
public class BeltInventory {
|
||||
|
||||
final BeltTileEntity belt;
|
||||
final List<TransportedItemStack> items;
|
||||
boolean beltMovementPositive;
|
||||
final float SEGMENT_WINDOW = .75f;
|
||||
|
||||
public BeltInventory(BeltTileEntity te) {
|
||||
this.belt = te;
|
||||
items = new LinkedList<>();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
|
||||
// Reverse item collection if belt just reversed
|
||||
if (beltMovementPositive != movingPositive()) {
|
||||
beltMovementPositive = movingPositive();
|
||||
Collections.reverse(items);
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
|
||||
// Assuming the first entry is furthest on the belt
|
||||
TransportedItemStack stackInFront = null;
|
||||
TransportedItemStack current = null;
|
||||
Iterator<TransportedItemStack> iterator = items.iterator();
|
||||
float beltSpeed = belt.getBeltMovementSpeed();
|
||||
float spacing = 1;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
stackInFront = current;
|
||||
current = iterator.next();
|
||||
|
||||
if (current.stack.isEmpty()) {
|
||||
iterator.remove();
|
||||
current = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
float movement = beltSpeed;
|
||||
|
||||
// Don't move if other items are waiting in front
|
||||
float currentPos = current.beltPosition;
|
||||
if (stackInFront != null) {
|
||||
float diff = stackInFront.beltPosition - currentPos;
|
||||
if (Math.abs(diff) <= spacing)
|
||||
continue;
|
||||
movement = beltMovementPositive ? Math.min(movement, diff - spacing)
|
||||
: Math.max(movement, diff + spacing);
|
||||
}
|
||||
|
||||
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
|
||||
float limitedMovement = beltMovementPositive ? Math.min(movement, diffToEnd)
|
||||
: Math.max(movement, diffToEnd);
|
||||
|
||||
int segmentBefore = (int) currentPos;
|
||||
float min = segmentBefore + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = segmentBefore + .5f + (SEGMENT_WINDOW / 2);
|
||||
if (currentPos < min || currentPos > max)
|
||||
segmentBefore = -1;
|
||||
|
||||
current.beltPosition += limitedMovement;
|
||||
|
||||
int segmentAfter = (int) currentPos;
|
||||
min = segmentAfter + .5f - (SEGMENT_WINDOW / 2);
|
||||
max = segmentAfter + .5f + (SEGMENT_WINDOW / 2);
|
||||
if (currentPos < min || currentPos > max)
|
||||
segmentAfter = -1;
|
||||
|
||||
// Item changed segments
|
||||
World world = belt.getWorld();
|
||||
if (segmentBefore != segmentAfter) {
|
||||
for (int segment : new int[] { segmentBefore, segmentAfter }) {
|
||||
if (segment == -1)
|
||||
continue;
|
||||
if (!world.isRemote)
|
||||
world.updateComparatorOutputLevel(getPositionForOffset(segment),
|
||||
belt.getBlockState().getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
// End reached
|
||||
if (limitedMovement != movement) {
|
||||
if (world.isRemote)
|
||||
continue;
|
||||
|
||||
BlockPos nextPosition = getPositionForOffset(beltMovementPositive ? belt.beltLength : -1);
|
||||
BlockState state = world.getBlockState(nextPosition);
|
||||
Direction movementFacing = belt.getMovementFacing();
|
||||
|
||||
// next block is not a belt
|
||||
if (!AllBlocks.BELT.typeOf(state)) {
|
||||
if (!Block.hasSolidSide(state, world, nextPosition, movementFacing.getOpposite())) {
|
||||
eject(current);
|
||||
iterator.remove();
|
||||
current = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Next block is a belt
|
||||
TileEntity te = world.getTileEntity(nextPosition);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
continue;
|
||||
BeltTileEntity nextBelt = (BeltTileEntity) te;
|
||||
Direction nextMovementFacing = nextBelt.getMovementFacing();
|
||||
|
||||
// next belt goes the opposite way
|
||||
if (nextMovementFacing == movementFacing.getOpposite())
|
||||
continue;
|
||||
|
||||
// Inserting into other belt
|
||||
BlockPos controller = nextBelt.getController();
|
||||
if (!world.isBlockPresent(controller))
|
||||
continue;
|
||||
te = world.getTileEntity(controller);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
continue;
|
||||
BeltTileEntity nextBeltController = (BeltTileEntity) te;
|
||||
BeltInventory nextInventory = nextBeltController.getInventory();
|
||||
|
||||
if (!nextInventory.canInsertAt(nextBelt.index))
|
||||
continue;
|
||||
|
||||
current.beltPosition = nextBelt.index + .5f;
|
||||
current.insertedAt = nextBelt.index;
|
||||
nextInventory.insert(current);
|
||||
iterator.remove();
|
||||
current = null;
|
||||
belt.sendData();
|
||||
nextBeltController.sendData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TransportedItemStack implements Comparable<TransportedItemStack> {
|
||||
public ItemStack stack;
|
||||
public float beltPosition;
|
||||
public float sideOffset;
|
||||
public int insertedAt;
|
||||
|
||||
public TransportedItemStack(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TransportedItemStack o) {
|
||||
return beltPosition < o.beltPosition ? 1 : beltPosition > o.beltPosition ? -1 : 0;
|
||||
}
|
||||
|
||||
public CompoundNBT serializeNBT() {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.put("Item", stack.serializeNBT());
|
||||
nbt.putFloat("Pos", beltPosition);
|
||||
nbt.putFloat("Offset", sideOffset);
|
||||
nbt.putInt("InSegment", insertedAt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static TransportedItemStack read(CompoundNBT nbt) {
|
||||
TransportedItemStack stack = new TransportedItemStack(ItemStack.read(nbt.getCompound("Item")));
|
||||
stack.beltPosition = nbt.getFloat("Pos");
|
||||
stack.sideOffset = nbt.getFloat("Offset");
|
||||
stack.insertedAt = nbt.getInt("InSegment");
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean canInsertAt(int segment) {
|
||||
float min = segment + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = segment + .5f + (SEGMENT_WINDOW / 2);
|
||||
|
||||
for (TransportedItemStack stack : items) {
|
||||
float currentPos = stack.beltPosition;
|
||||
|
||||
// Searched past relevant stacks
|
||||
if (beltMovementPositive ? currentPos < segment : currentPos - 1 > segment)
|
||||
break;
|
||||
|
||||
// Item inside extraction window
|
||||
if (currentPos > min && currentPos < max)
|
||||
return false;
|
||||
|
||||
// Items on the belt get prioritized if the previous item was inserted on the
|
||||
// same segment
|
||||
if (stack.insertedAt == segment && currentPos <= segment + 1)
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void insert(TransportedItemStack newStack) {
|
||||
int index = 0;
|
||||
if (items.isEmpty())
|
||||
items.add(newStack);
|
||||
for (TransportedItemStack stack : items) {
|
||||
if (stack.compareTo(newStack) > 0 == beltMovementPositive)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
items.add(index, newStack);
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
|
||||
protected TransportedItemStack getStackAtOffset(int offset) {
|
||||
float min = offset + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = offset + .5f + (SEGMENT_WINDOW / 2);
|
||||
for (TransportedItemStack stack : items) {
|
||||
if (stack.beltPosition > max)
|
||||
break;
|
||||
if (stack.beltPosition > min)
|
||||
return stack;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void read(CompoundNBT nbt) {
|
||||
items.clear();
|
||||
nbt.getList("Items", NBT.TAG_COMPOUND)
|
||||
.forEach(inbt -> items.add(TransportedItemStack.read((CompoundNBT) inbt)));
|
||||
beltMovementPositive = nbt.getBoolean("PositiveOrder");
|
||||
}
|
||||
|
||||
public CompoundNBT write() {
|
||||
CompoundNBT nbt = new CompoundNBT();
|
||||
ListNBT itemsNBT = new ListNBT();
|
||||
items.forEach(stack -> itemsNBT.add(stack.serializeNBT()));
|
||||
nbt.put("Items", itemsNBT);
|
||||
nbt.putBoolean("PositiveOrder", beltMovementPositive);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
private void eject(TransportedItemStack stack) {
|
||||
ItemStack ejected = stack.stack;
|
||||
Vec3d outPos = getVectorForOffset(stack.beltPosition);
|
||||
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y, outPos.z, ejected);
|
||||
entity.setMotion(new Vec3d(belt.getBeltChainDirection()).scale(Math.abs(belt.getBeltMovementSpeed())));
|
||||
entity.velocityChanged = true;
|
||||
}
|
||||
|
||||
private Vec3d getVectorForOffset(float offset) {
|
||||
Vec3d vec = VecHelper.getCenterOf(belt.getPos());
|
||||
vec.add(new Vec3d(belt.getBeltChainDirection()).scale(offset));
|
||||
return vec;
|
||||
}
|
||||
|
||||
private BlockPos getPositionForOffset(int offset) {
|
||||
BlockPos pos = belt.getPos();
|
||||
Vec3i vec = belt.getBeltChainDirection();
|
||||
return pos.add(offset * vec.getX(), offset * vec.getY(), offset * vec.getZ());
|
||||
}
|
||||
|
||||
private boolean movingPositive() {
|
||||
return belt.getBeltMovementSpeed() > 0;
|
||||
}
|
||||
|
||||
public class ItemHandlerSegment implements IItemHandler {
|
||||
int offset;
|
||||
|
||||
public ItemHandlerSegment(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
TransportedItemStack stackAtOffset = getStackAtOffset(offset);
|
||||
if (stackAtOffset == null)
|
||||
return ItemStack.EMPTY;
|
||||
return stackAtOffset.stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
if (canInsertAt(offset)) {
|
||||
if (!simulate) {
|
||||
TransportedItemStack newStack = new TransportedItemStack(stack);
|
||||
newStack.insertedAt = offset;
|
||||
newStack.beltPosition = offset + .5f;
|
||||
insert(newStack);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
TransportedItemStack transported = getStackAtOffset(offset);
|
||||
if (transported == null)
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
amount = Math.min(amount, transported.stack.getCount());
|
||||
ItemStack extracted = simulate ? transported.stack.copy().split(amount) : transported.stack.split(amount);
|
||||
if (!simulate) {
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return Math.min(getStackInSlot(slot).getMaxStackSize(), 64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, ItemStack stack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IItemHandler createHandlerForSegment(int segment) {
|
||||
return new ItemHandlerSegment(segment);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.BufferManipulator;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
class BeltModelAnimator extends BufferManipulator {
|
||||
protected static TextureAtlasSprite beltTextures;
|
||||
protected static TextureAtlasSprite originalTexture;
|
||||
|
||||
public BeltModelAnimator(ByteBuffer template) {
|
||||
super(template);
|
||||
if (beltTextures == null)
|
||||
initSprites();
|
||||
}
|
||||
|
||||
private void initSprites() {
|
||||
AtlasTexture textureMap = Minecraft.getInstance().getTextureMap();
|
||||
originalTexture = textureMap.getSprite(new ResourceLocation(Create.ID, "block/belt"));
|
||||
beltTextures = textureMap.getSprite(new ResourceLocation(Create.ID, "block/belt_animated"));
|
||||
}
|
||||
|
||||
public ByteBuffer getTransformed(BeltTileEntity te, float x, float y, float z, int color) {
|
||||
original.rewind();
|
||||
mutable.rewind();
|
||||
|
||||
float textureOffsetX = 0;
|
||||
float textureOffsetY = 0;
|
||||
|
||||
if (te.getSpeed() != 0) {
|
||||
float time = AnimationTickHolder.getRenderTick();
|
||||
Direction direction = te.getBlockState().get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
if (direction == Direction.EAST || direction == Direction.NORTH)
|
||||
time = -time;
|
||||
int textureIndex = (int) ((te.getSpeed() * time / 8) % 16);
|
||||
if (textureIndex < 0)
|
||||
textureIndex += 16;
|
||||
|
||||
textureOffsetX = beltTextures.getInterpolatedU((textureIndex % 4) * 4) - originalTexture.getMinU();
|
||||
textureOffsetY = beltTextures.getInterpolatedV((textureIndex / 4) * 4) - originalTexture.getMinV();
|
||||
}
|
||||
|
||||
final BlockState blockState = te.getBlockState();
|
||||
int packedLightCoords = blockState.getPackedLightmapCoords(te.getWorld(), te.getPos());
|
||||
float texOffX = textureOffsetX;
|
||||
float texOffY = textureOffsetY;
|
||||
|
||||
boolean defaultColor = color == -1;
|
||||
int b = defaultColor ? 128 : color & 0xFF;
|
||||
int g = defaultColor ? 128 : (color >> 8) & 0xFF;
|
||||
int r = defaultColor ? 128 : (color >> 16) & 0xFF;
|
||||
|
||||
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
|
||||
putPos(mutable, vertex, getX(original, vertex) + x, getY(original, vertex) + y,
|
||||
getZ(original, vertex) + z);
|
||||
putLight(mutable, vertex, packedLightCoords);
|
||||
|
||||
int bufferPosition = getBufferPosition(vertex);
|
||||
mutable.putFloat(bufferPosition + 16, original.getFloat(bufferPosition + 16) + texOffX);
|
||||
mutable.putFloat(bufferPosition + 20, original.getFloat(bufferPosition + 20) + texOffY);
|
||||
|
||||
byte lumByte = getR(original, vertex);
|
||||
float lum = (lumByte < 0 ? 255 + lumByte : lumByte) / 256f;
|
||||
|
||||
int r2 = (int) (r * lum);
|
||||
int g2 = (int) (g * lum);
|
||||
int b2 = (int) (b * lum);
|
||||
putColor(mutable, vertex, (byte) r2, (byte) g2, (byte) b2, (byte) 255);
|
||||
}
|
||||
|
||||
return mutable;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import static net.minecraft.entity.MoverType.SELF;
|
||||
import static net.minecraft.util.Direction.AxisDirection.NEGATIVE;
|
||||
import static net.minecraft.util.Direction.AxisDirection.POSITIVE;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BeltMovementHandler {
|
||||
|
||||
public static class TransportedEntityInfo {
|
||||
int ticksSinceLastCollision;
|
||||
BlockPos lastCollidedPos;
|
||||
BlockState lastCollidedState;
|
||||
|
||||
public TransportedEntityInfo(BlockPos collision, BlockState belt) {
|
||||
refresh(collision, belt);
|
||||
}
|
||||
|
||||
public void refresh(BlockPos collision, BlockState belt) {
|
||||
ticksSinceLastCollision = 0;
|
||||
lastCollidedPos = new BlockPos(collision).toImmutable();
|
||||
lastCollidedState = belt;
|
||||
}
|
||||
|
||||
public TransportedEntityInfo tick() {
|
||||
ticksSinceLastCollision++;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canBeTransported(Entity entity) {
|
||||
if (!entity.isAlive())
|
||||
return false;
|
||||
if (entity instanceof PlayerEntity && ((PlayerEntity) entity).isSneaking())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void transportEntity(BeltTileEntity beltTe, Entity entityIn, TransportedEntityInfo info) {
|
||||
BlockPos pos = info.lastCollidedPos;
|
||||
World world = beltTe.getWorld();
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
TileEntity tileEntityBelowPassenger = world.getTileEntity(entityIn.getPosition());
|
||||
BlockState blockState = info.lastCollidedState;
|
||||
Direction movementFacing = Direction.getFacingFromAxisDirection(
|
||||
blockState.get(BlockStateProperties.HORIZONTAL_FACING).getAxis(),
|
||||
beltTe.getSpeed() < 0 ? POSITIVE : NEGATIVE);
|
||||
|
||||
boolean collidedWithBelt = te instanceof BeltTileEntity;
|
||||
boolean betweenBelts = tileEntityBelowPassenger instanceof BeltTileEntity && tileEntityBelowPassenger != te;
|
||||
|
||||
// Don't fight other Belts
|
||||
if (!collidedWithBelt || betweenBelts) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Too slow
|
||||
boolean notHorizontal = beltTe.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL;
|
||||
if (Math.abs(beltTe.getSpeed()) < (notHorizontal ? 32 : 1))
|
||||
return;
|
||||
|
||||
// Not on top
|
||||
if (entityIn.posY - .25f < pos.getY())
|
||||
return;
|
||||
|
||||
// Lock entities in place
|
||||
boolean isPlayer = entityIn instanceof PlayerEntity;
|
||||
if (entityIn instanceof LivingEntity && !isPlayer) {
|
||||
((LivingEntity) entityIn).addPotionEffect(new EffectInstance(Effects.SLOWNESS, 1, 9, false, false));
|
||||
}
|
||||
|
||||
BeltTileEntity belt = (BeltTileEntity) te;
|
||||
|
||||
// Attachment pauses movement
|
||||
for (BeltAttachmentState state : belt.attachmentTracker.attachments) {
|
||||
if (state.attachment.handleEntity(belt, entityIn, state)) {
|
||||
info.ticksSinceLastCollision--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Direction beltFacing = blockState.get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
final Slope slope = blockState.get(BeltBlock.SLOPE);
|
||||
final Axis axis = beltFacing.getAxis();
|
||||
float movementSpeed = beltTe.getBeltMovementSpeed();
|
||||
final Direction movementDirection = Direction.getFacingFromAxis(axis == Axis.X ? NEGATIVE : POSITIVE, axis);
|
||||
|
||||
Vec3i centeringDirection = Direction.getFacingFromAxis(POSITIVE, beltFacing.rotateY().getAxis())
|
||||
.getDirectionVec();
|
||||
Vec3d movement = new Vec3d(movementDirection.getDirectionVec()).scale(movementSpeed);
|
||||
|
||||
double diffCenter = axis == Axis.Z ? (pos.getX() + .5f - entityIn.posX) : (pos.getZ() + .5f - entityIn.posZ);
|
||||
if (Math.abs(diffCenter) > 48 / 64f)
|
||||
return;
|
||||
|
||||
Part part = blockState.get(BeltBlock.PART);
|
||||
float top = 13 / 16f;
|
||||
boolean onSlope = notHorizontal && (part == Part.MIDDLE
|
||||
|| part == (slope == Slope.UPWARD ? Part.END : Part.START) && entityIn.posY - pos.getY() < top
|
||||
|| part == (slope == Slope.UPWARD ? Part.START : Part.END) && entityIn.posY - pos.getY() > top);
|
||||
|
||||
boolean movingDown = onSlope && slope == (movementFacing == beltFacing ? Slope.DOWNWARD : Slope.UPWARD);
|
||||
boolean movingUp = onSlope && slope == (movementFacing == beltFacing ? Slope.UPWARD : Slope.DOWNWARD);
|
||||
|
||||
if (beltFacing.getAxis() == Axis.Z) {
|
||||
boolean b = movingDown;
|
||||
movingDown = movingUp;
|
||||
movingUp = b;
|
||||
}
|
||||
|
||||
if (movingUp)
|
||||
movement = movement.add(0, Math.abs(axis.getCoordinate(movement.x, movement.y, movement.z)), 0);
|
||||
if (movingDown)
|
||||
movement = movement.add(0, -Math.abs(axis.getCoordinate(movement.x, movement.y, movement.z)), 0);
|
||||
|
||||
Vec3d centering = new Vec3d(centeringDirection).scale(diffCenter * Math.min(Math.abs(movementSpeed), .1f) * 4);
|
||||
movement = movement.add(centering);
|
||||
|
||||
float step = entityIn.stepHeight;
|
||||
if (!isPlayer)
|
||||
entityIn.stepHeight = 1;
|
||||
|
||||
// Entity Collisions
|
||||
if (Math.abs(movementSpeed) < .5f) {
|
||||
Vec3d checkDistance = movement.scale(2f).add(movement.normalize());
|
||||
AxisAlignedBB bb = entityIn.getBoundingBox();
|
||||
AxisAlignedBB checkBB = new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
|
||||
if (!world
|
||||
.getEntitiesWithinAABBExcludingEntity(entityIn, checkBB.offset(checkDistance)
|
||||
.grow(-Math.abs(checkDistance.x), -Math.abs(checkDistance.y), -Math.abs(checkDistance.z)))
|
||||
.isEmpty()) {
|
||||
entityIn.setMotion(0, 0, 0);
|
||||
info.ticksSinceLastCollision--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (movingUp) {
|
||||
float minVelocity = .13f;
|
||||
float yMovement = (float) -(Math.max(Math.abs(movement.y), minVelocity));
|
||||
entityIn.move(SELF, new Vec3d(0, yMovement, 0));
|
||||
entityIn.move(SELF, movement.mul(1, 0, 1));
|
||||
} else if (movingDown) {
|
||||
entityIn.move(SELF, movement.mul(1, 0, 1));
|
||||
entityIn.move(SELF, movement.mul(0, 1, 0));
|
||||
} else {
|
||||
entityIn.move(SELF, movement);
|
||||
}
|
||||
|
||||
if (!isPlayer)
|
||||
entityIn.stepHeight = step;
|
||||
|
||||
boolean movedPastEndingSlope = onSlope && (AllBlocks.BELT.typeOf(world.getBlockState(entityIn.getPosition()))
|
||||
|| AllBlocks.BELT.typeOf(world.getBlockState(entityIn.getPosition().down())));
|
||||
|
||||
if (movedPastEndingSlope && !movingDown && Math.abs(movementSpeed) > 0)
|
||||
entityIn.setPosition(entityIn.posX, entityIn.posY + movement.y, entityIn.posZ);
|
||||
if (movedPastEndingSlope) {
|
||||
entityIn.setMotion(movement);
|
||||
entityIn.velocityChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import static net.minecraft.block.Block.makeCuboidShape;
|
||||
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
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;
|
||||
|
||||
public class BeltShapes {
|
||||
|
||||
private static final VoxelShape FULL = makeCuboidShape(0, 0, 0, 16, 16, 16),
|
||||
FLAT_STRAIGHT_X = makeCuboidShape(1, 3, 0, 15, 13, 16),
|
||||
FLAT_STRAIGHT_Z = makeCuboidShape(0, 3, 1, 16, 13, 15),
|
||||
VERTICAL_STRAIGHT_X = makeCuboidShape(3, 0, 1, 13, 16, 15),
|
||||
VERTICAL_STRAIGHT_Z = makeCuboidShape(1, 0, 3, 15, 16, 13),
|
||||
|
||||
SLOPE_END_EAST = makeCuboidShape(0, 3, 1, 10, 13, 15),
|
||||
SLOPE_END_WEST = makeCuboidShape(6, 3, 1, 16, 13, 15),
|
||||
SLOPE_END_SOUTH = makeCuboidShape(1, 3, 0, 15, 13, 10),
|
||||
SLOPE_END_NORTH = makeCuboidShape(1, 3, 6, 15, 13, 16),
|
||||
|
||||
SLOPE_BUILDING_BLOCK_X = makeCuboidShape(5, 5, 1, 11, 11, 15),
|
||||
SLOPE_BUILDING_BLOCK_Z = makeCuboidShape(1, 5, 5, 15, 11, 11),
|
||||
|
||||
SLOPE_UPWARD_END_EAST = VoxelShapes.or(SLOPE_END_EAST, createHalfSlope(Direction.EAST, false)),
|
||||
SLOPE_UPWARD_END_WEST = VoxelShapes.or(SLOPE_END_WEST, createHalfSlope(Direction.WEST, false)),
|
||||
SLOPE_UPWARD_END_SOUTH = VoxelShapes.or(SLOPE_END_SOUTH, createHalfSlope(Direction.SOUTH, false)),
|
||||
SLOPE_UPWARD_END_NORTH = VoxelShapes.or(SLOPE_END_NORTH, createHalfSlope(Direction.NORTH, false)),
|
||||
|
||||
SLOPE_DOWNWARD_END_EAST = VoxelShapes.or(SLOPE_END_EAST, createHalfSlope(Direction.EAST, true)),
|
||||
SLOPE_DOWNWARD_END_WEST = VoxelShapes.or(SLOPE_END_WEST, createHalfSlope(Direction.WEST, true)),
|
||||
SLOPE_DOWNWARD_END_SOUTH = VoxelShapes.or(SLOPE_END_SOUTH, createHalfSlope(Direction.SOUTH, true)),
|
||||
SLOPE_DOWNWARD_END_NORTH = VoxelShapes.or(SLOPE_END_NORTH, createHalfSlope(Direction.NORTH, true)),
|
||||
|
||||
SLOPE_EAST = createSlope(Direction.EAST), SLOPE_WEST = createSlope(Direction.WEST),
|
||||
SLOPE_NORTH = createSlope(Direction.NORTH), SLOPE_SOUTH = createSlope(Direction.SOUTH);
|
||||
|
||||
public static VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
|
||||
Direction facing = state.get(BeltBlock.HORIZONTAL_FACING);
|
||||
Axis axis = facing.getAxis();
|
||||
Part part = state.get(BeltBlock.PART);
|
||||
Slope slope = state.get(BeltBlock.SLOPE);
|
||||
|
||||
if (slope == Slope.HORIZONTAL)
|
||||
return axis == Axis.Z ? FLAT_STRAIGHT_X : FLAT_STRAIGHT_Z;
|
||||
if (slope == Slope.VERTICAL)
|
||||
return axis == Axis.X ? VERTICAL_STRAIGHT_X : VERTICAL_STRAIGHT_Z;
|
||||
|
||||
if (part != Part.MIDDLE) {
|
||||
boolean upward = slope == Slope.UPWARD;
|
||||
if (part == Part.START)
|
||||
slope = upward ? Slope.DOWNWARD : Slope.UPWARD;
|
||||
else
|
||||
facing = facing.getOpposite();
|
||||
|
||||
if (facing == Direction.NORTH)
|
||||
return upward ? SLOPE_UPWARD_END_NORTH : SLOPE_DOWNWARD_END_NORTH;
|
||||
if (facing == Direction.SOUTH)
|
||||
return upward ? SLOPE_UPWARD_END_SOUTH : SLOPE_DOWNWARD_END_SOUTH;
|
||||
if (facing == Direction.EAST)
|
||||
return upward ? SLOPE_UPWARD_END_EAST : SLOPE_DOWNWARD_END_EAST;
|
||||
if (facing == Direction.WEST)
|
||||
return upward ? SLOPE_UPWARD_END_WEST : SLOPE_DOWNWARD_END_WEST;
|
||||
}
|
||||
|
||||
if (slope == Slope.DOWNWARD)
|
||||
facing = facing.getOpposite();
|
||||
|
||||
if (facing == Direction.NORTH)
|
||||
return SLOPE_NORTH;
|
||||
if (facing == Direction.SOUTH)
|
||||
return SLOPE_SOUTH;
|
||||
if (facing == Direction.EAST)
|
||||
return SLOPE_EAST;
|
||||
if (facing == Direction.WEST)
|
||||
return SLOPE_WEST;
|
||||
|
||||
return FULL;
|
||||
}
|
||||
|
||||
protected static VoxelShape createSlope(Direction facing) {
|
||||
return VoxelShapes.or(createHalfSlope(facing.getOpposite(), false), createHalfSlope(facing, true));
|
||||
}
|
||||
|
||||
protected static VoxelShape createHalfSlope(Direction facing, boolean upward) {
|
||||
VoxelShape shape = VoxelShapes.empty();
|
||||
VoxelShape buildingBlock = facing.getAxis() == Axis.X ? SLOPE_BUILDING_BLOCK_X : SLOPE_BUILDING_BLOCK_Z;
|
||||
Vec3i directionVec = facing.getDirectionVec();
|
||||
|
||||
int x = directionVec.getX();
|
||||
int y = upward ? 1 : -1;
|
||||
int z = directionVec.getZ();
|
||||
|
||||
for (int segment = 0; segment < 6; segment++)
|
||||
shape = VoxelShapes.or(shape,
|
||||
buildingBlock.withOffset(x * segment / 16f, y * segment / 16f, z * segment / 16f));
|
||||
|
||||
if (!upward)
|
||||
return shape;
|
||||
|
||||
VoxelShape mask = makeCuboidShape(0, -8, 0, 16, 24, 16);
|
||||
for (int segment = 6; segment < 11; segment++)
|
||||
shape = VoxelShapes.or(shape,
|
||||
VoxelShapes.combine(mask,
|
||||
buildingBlock.withOffset(x * segment / 16f, y * segment / 16f, z * segment / 16f),
|
||||
IBooleanFunction.AND));
|
||||
return shape;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,13 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import static com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part.END;
|
||||
import static com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part.MIDDLE;
|
||||
import static com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope.DOWNWARD;
|
||||
import static com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope.HORIZONTAL;
|
||||
import static com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope.UPWARD;
|
||||
import static net.minecraft.util.Direction.AxisDirection.NEGATIVE;
|
||||
import static net.minecraft.util.Direction.AxisDirection.POSITIVE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -9,113 +17,167 @@ import com.simibubi.create.AllBlocks;
|
|||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.Tracker;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
public class BeltTileEntity extends KineticTileEntity {
|
||||
|
||||
protected BlockPos controller;
|
||||
public Map<Entity, TransportedEntityInfo> passengers;
|
||||
public AllBeltAttachments.Tracker attachmentTracker;
|
||||
private CompoundNBT trackerUpdateTag;
|
||||
public int color;
|
||||
public int beltLength;
|
||||
public int index;
|
||||
public boolean hasPulley;
|
||||
|
||||
protected static class TransportedEntityInfo {
|
||||
int ticksSinceLastCollision;
|
||||
BlockPos lastCollidedPos;
|
||||
BlockState lastCollidedState;
|
||||
protected BlockPos controller;
|
||||
protected BeltInventory inventory;
|
||||
protected LazyOptional<IItemHandler> itemHandler;
|
||||
|
||||
public TransportedEntityInfo(BlockPos collision, BlockState belt) {
|
||||
refresh(collision, belt);
|
||||
}
|
||||
|
||||
public void refresh(BlockPos collision, BlockState belt) {
|
||||
ticksSinceLastCollision = 0;
|
||||
lastCollidedPos = new BlockPos(collision).toImmutable();
|
||||
lastCollidedState = belt;
|
||||
}
|
||||
|
||||
public TransportedEntityInfo tick() {
|
||||
ticksSinceLastCollision++;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
private CompoundNBT trackerUpdateTag;
|
||||
|
||||
public BeltTileEntity() {
|
||||
super(AllTileEntities.BELT.type);
|
||||
controller = BlockPos.ZERO;
|
||||
attachmentTracker = new Tracker(this);
|
||||
itemHandler = LazyOptional.empty();
|
||||
color = -1;
|
||||
beltLength = -1;
|
||||
index = -1;
|
||||
}
|
||||
|
||||
protected boolean isLastBelt() {
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
// Initialize Belt Attachments
|
||||
if (world != null && trackerUpdateTag != null) {
|
||||
attachmentTracker.readAndSearch(trackerUpdateTag, this);
|
||||
trackerUpdateTag = null;
|
||||
}
|
||||
if (getSpeed() == 0)
|
||||
return false;
|
||||
return;
|
||||
|
||||
Direction direction = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
if (getBlockState().get(BeltBlock.SLOPE) == Slope.VERTICAL)
|
||||
return false;
|
||||
initializeItemHandler();
|
||||
|
||||
Part part = getBlockState().get(BeltBlock.PART);
|
||||
if (part == Part.MIDDLE)
|
||||
return false;
|
||||
// Move Items
|
||||
if (!isController())
|
||||
return;
|
||||
getInventory().tick();
|
||||
|
||||
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1))
|
||||
^ direction.getAxis() == Axis.X;
|
||||
return part == Part.START ^ movingPositively;
|
||||
// Move Entities
|
||||
if (passengers == null)
|
||||
passengers = new HashMap<>();
|
||||
|
||||
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);
|
||||
if (!canBeTransported || leftTheBelt) {
|
||||
toRemove.add(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
info.tick();
|
||||
BeltMovementHandler.transportEntity(this, entity, info);
|
||||
});
|
||||
toRemove.forEach(passengers::remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getRenderBoundingBox() {
|
||||
if (!isController())
|
||||
return super.getRenderBoundingBox();
|
||||
return super.getRenderBoundingBox().grow(beltLength);
|
||||
}
|
||||
|
||||
protected void initializeItemHandler() {
|
||||
if (world.isRemote || itemHandler.isPresent())
|
||||
return;
|
||||
if (!world.isBlockPresent(controller))
|
||||
return;
|
||||
TileEntity te = world.getTileEntity(controller);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return;
|
||||
IItemHandler handler = ((BeltTileEntity) te).getInventory().createHandlerForSegment(index);
|
||||
itemHandler = LazyOptional.of(() -> handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFastRenderer() {
|
||||
return !isController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
|
||||
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
return itemHandler.cast();
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
itemHandler.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
attachmentTracker.write(compound);
|
||||
compound.put("Controller", NBTUtil.writeBlockPos(controller));
|
||||
compound.putInt("Color", color);
|
||||
attachmentTracker.write(compound);
|
||||
compound.putInt("Length", beltLength);
|
||||
compound.putInt("Index", index);
|
||||
compound.putBoolean("Pulley", hasPulley);
|
||||
|
||||
if (isController())
|
||||
compound.put("Inventory", getInventory().write());
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT compound) {
|
||||
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
|
||||
trackerUpdateTag = compound;
|
||||
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
|
||||
color = compound.getInt("Color");
|
||||
beltLength = compound.getInt("Length");
|
||||
index = compound.getInt("Index");
|
||||
hasPulley = compound.getBoolean("Pulley");
|
||||
|
||||
if (isController())
|
||||
getInventory().read(compound.getCompound("Inventory"));
|
||||
super.read(compound);
|
||||
}
|
||||
|
||||
public void applyColor(DyeColor colorIn) {
|
||||
int colorValue = colorIn.getMapColor().colorValue;
|
||||
for (BlockPos blockPos : BeltBlock.getBeltChain(world, getController())) {
|
||||
BeltTileEntity tileEntity = (BeltTileEntity) world.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
if (tileEntity.color == -1) {
|
||||
tileEntity.color = colorValue;
|
||||
} else {
|
||||
tileEntity.color = ColorHelper.mixColors(tileEntity.color, colorValue, .5f);
|
||||
}
|
||||
tileEntity.sendData();
|
||||
}
|
||||
BeltTileEntity belt = (BeltTileEntity) world.getTileEntity(blockPos);
|
||||
if (belt == null)
|
||||
continue;
|
||||
belt.color = belt.color == -1 ? colorValue : ColorHelper.mixColors(belt.color, colorValue, .5f);
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,178 +193,81 @@ public class BeltTileEntity extends KineticTileEntity {
|
|||
return controller.equals(pos);
|
||||
}
|
||||
|
||||
public float getBeltMovementSpeed() {
|
||||
return getSpeed() / 1600f;
|
||||
}
|
||||
|
||||
public boolean hasPulley() {
|
||||
if (!AllBlocks.BELT.typeOf(getBlockState()))
|
||||
return false;
|
||||
return getBlockState().get(BeltBlock.PART) == Part.END || getBlockState().get(BeltBlock.PART) == Part.START;
|
||||
Part part = getBlockState().get(BeltBlock.PART);
|
||||
return part == END || part == Part.START || hasPulley;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (world != null && trackerUpdateTag != null) {
|
||||
attachmentTracker.readAndSearch(trackerUpdateTag, this);
|
||||
trackerUpdateTag = null;
|
||||
}
|
||||
if (!isController())
|
||||
return;
|
||||
if (passengers == null)
|
||||
passengers = new HashMap<>();
|
||||
|
||||
passengers.forEach((entity, info) -> {
|
||||
transportEntity(entity, info);
|
||||
});
|
||||
|
||||
List<Entity> toRemove = new ArrayList<>();
|
||||
passengers.forEach((entity, info) -> {
|
||||
if (!canTransport(entity))
|
||||
toRemove.add(entity);
|
||||
if (info.ticksSinceLastCollision > ((getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL) ? 3 : 1)) {
|
||||
toRemove.add(entity);
|
||||
}
|
||||
info.tick();
|
||||
});
|
||||
toRemove.forEach(e -> {
|
||||
if (e instanceof ItemEntity)
|
||||
((ItemEntity) e).setAgeToCreativeDespawnTime();
|
||||
passengers.remove(e);
|
||||
});
|
||||
|
||||
protected boolean isLastBelt() {
|
||||
if (getSpeed() == 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
Direction direction = getBeltFacing();
|
||||
if (getBlockState().get(BeltBlock.SLOPE) == Slope.VERTICAL)
|
||||
return false;
|
||||
|
||||
Part part = getBlockState().get(BeltBlock.PART);
|
||||
if (part == MIDDLE)
|
||||
return false;
|
||||
|
||||
boolean movingPositively = (getSpeed() > 0 == (direction.getAxisDirection().getOffset() == 1))
|
||||
^ direction.getAxis() == Axis.X;
|
||||
return part == Part.START ^ movingPositively;
|
||||
}
|
||||
|
||||
public void transportEntity(Entity entityIn, TransportedEntityInfo info) {
|
||||
BlockPos pos = info.lastCollidedPos;
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
TileEntity tileEntityBelowPassenger = world.getTileEntity(entityIn.getPosition());
|
||||
BlockState blockState = info.lastCollidedState;
|
||||
Direction movementFacing = Direction.getFacingFromAxisDirection(
|
||||
blockState.get(BlockStateProperties.HORIZONTAL_FACING).getAxis(),
|
||||
getSpeed() < 0 ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE);
|
||||
public Vec3i getMovementDirection(boolean firstHalf) {
|
||||
return this.getMovementDirection(firstHalf, false);
|
||||
}
|
||||
|
||||
boolean collidedWithBelt = te instanceof BeltTileEntity;
|
||||
boolean betweenBelts = tileEntityBelowPassenger instanceof BeltTileEntity && tileEntityBelowPassenger != te;
|
||||
public Vec3i getBeltChainDirection() {
|
||||
return this.getMovementDirection(true, true);
|
||||
}
|
||||
|
||||
// Don't fight other Belts
|
||||
if (!collidedWithBelt || betweenBelts) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Too slow
|
||||
boolean notHorizontal = getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL;
|
||||
if (Math.abs(getSpeed()) < (notHorizontal ? 32 : 1))
|
||||
return;
|
||||
|
||||
// Not on top
|
||||
if (entityIn.posY - .25f < pos.getY())
|
||||
return;
|
||||
|
||||
// Lock entities in place
|
||||
if (entityIn instanceof LivingEntity && !(entityIn instanceof PlayerEntity)) {
|
||||
((LivingEntity) entityIn).addPotionEffect(new EffectInstance(Effects.SLOWNESS, 1, 9, false, false));
|
||||
}
|
||||
|
||||
BeltTileEntity belt = (BeltTileEntity) te;
|
||||
|
||||
// Attachment pauses movement
|
||||
for (BeltAttachmentState state : belt.attachmentTracker.attachments) {
|
||||
if (state.attachment.handleEntity(belt, entityIn, state)) {
|
||||
info.ticksSinceLastCollision--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
protected Vec3i getMovementDirection(boolean firstHalf, boolean ignoreHalves) {
|
||||
if (getSpeed() == 0)
|
||||
return BlockPos.ZERO;
|
||||
|
||||
final BlockState blockState = getBlockState();
|
||||
final Direction beltFacing = blockState.get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
final Slope slope = blockState.get(BeltBlock.SLOPE);
|
||||
final Part part = blockState.get(BeltBlock.PART);
|
||||
final Axis axis = beltFacing.getAxis();
|
||||
float movementSpeed = ((KineticTileEntity) te).getSpeed() / 1600f;
|
||||
final Direction movementDirection = Direction
|
||||
.getFacingFromAxis(axis == Axis.X ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE, axis);
|
||||
|
||||
Vec3i centeringDirection = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis == Axis.X ? Axis.Z : Axis.X)
|
||||
.getDirectionVec();
|
||||
Vec3d movement = new Vec3d(movementDirection.getDirectionVec()).scale(movementSpeed);
|
||||
Direction movementFacing = Direction.getFacingFromAxis(axis == Axis.X ? NEGATIVE : POSITIVE, axis);
|
||||
boolean notHorizontal = blockState.get(BeltBlock.SLOPE) != HORIZONTAL;
|
||||
if (getSpeed() < 0)
|
||||
movementFacing = movementFacing.getOpposite();
|
||||
Vec3i movement = movementFacing.getDirectionVec();
|
||||
|
||||
double diffCenter = axis == Axis.Z ? (pos.getX() + .5f - entityIn.posX) : (pos.getZ() + .5f - entityIn.posZ);
|
||||
float maxDiffCenter = (entityIn instanceof ItemEntity) ? 32 / 64f : 48 / 64f;
|
||||
if (Math.abs(diffCenter) > maxDiffCenter)
|
||||
return;
|
||||
boolean slopeBeforeHalf = (part == END) == (beltFacing.getAxisDirection() == POSITIVE);
|
||||
boolean onSlope = notHorizontal && (part == MIDDLE || slopeBeforeHalf == firstHalf || ignoreHalves);
|
||||
boolean movingUp = onSlope && slope == (movementFacing == beltFacing ? UPWARD : DOWNWARD);
|
||||
|
||||
Part part = blockState.get(BeltBlock.PART);
|
||||
float top = 13 / 16f;
|
||||
boolean onSlope = notHorizontal && (part == Part.MIDDLE
|
||||
|| part == (slope == Slope.UPWARD ? Part.END : Part.START) && entityIn.posY - pos.getY() < top
|
||||
|| part == (slope == Slope.UPWARD ? Part.START : Part.END) && entityIn.posY - pos.getY() > top);
|
||||
if (!onSlope)
|
||||
return movement;
|
||||
|
||||
boolean movingDown = onSlope && slope == (movementFacing == beltFacing ? Slope.DOWNWARD : Slope.UPWARD);
|
||||
boolean movingUp = onSlope && slope == (movementFacing == beltFacing ? Slope.UPWARD : Slope.DOWNWARD);
|
||||
|
||||
if (beltFacing.getAxis() == Axis.Z) {
|
||||
boolean b = movingDown;
|
||||
movingDown = movingUp;
|
||||
movingUp = b;
|
||||
}
|
||||
|
||||
if (movingUp)
|
||||
movement = movement.add(0, Math.abs(axis.getCoordinate(movement.x, movement.y, movement.z)), 0);
|
||||
if (movingDown)
|
||||
movement = movement.add(0, -Math.abs(axis.getCoordinate(movement.x, movement.y, movement.z)), 0);
|
||||
|
||||
Vec3d centering = new Vec3d(centeringDirection).scale(diffCenter * Math.min(Math.abs(movementSpeed), .1f) * 4);
|
||||
movement = movement.add(centering);
|
||||
|
||||
float step = entityIn.stepHeight;
|
||||
if (!(entityIn instanceof PlayerEntity))
|
||||
entityIn.stepHeight = 1;
|
||||
|
||||
// Entity Collisions
|
||||
if (Math.abs(movementSpeed) < .5f) {
|
||||
Vec3d checkDistance = movement.scale(2f).add(movement.normalize());
|
||||
AxisAlignedBB bb = entityIn.getBoundingBox();
|
||||
AxisAlignedBB checkBB = new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
|
||||
if (!world
|
||||
.getEntitiesWithinAABBExcludingEntity(entityIn, checkBB.offset(checkDistance)
|
||||
.grow(-Math.abs(checkDistance.x), -Math.abs(checkDistance.y), -Math.abs(checkDistance.z)))
|
||||
.isEmpty()) {
|
||||
entityIn.setMotion(0, 0, 0);
|
||||
info.ticksSinceLastCollision--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (movingUp) {
|
||||
float minVelocity = entityIn instanceof ItemEntity ? .09f : .13f;
|
||||
float yMovement = (float) -(Math.max(Math.abs(movement.y), minVelocity));
|
||||
entityIn.move(MoverType.SELF, new Vec3d(0, yMovement, 0));
|
||||
entityIn.move(MoverType.SELF, movement.mul(1, 0, 1));
|
||||
} else if (movingDown) {
|
||||
entityIn.move(MoverType.SELF, movement.mul(1, 0, 1));
|
||||
entityIn.move(MoverType.SELF, movement.mul(0, 1, 0));
|
||||
} else {
|
||||
entityIn.move(MoverType.SELF, movement);
|
||||
}
|
||||
|
||||
if (!(entityIn instanceof PlayerEntity))
|
||||
entityIn.stepHeight = step;
|
||||
|
||||
boolean movedPastEndingSlope = onSlope && (AllBlocks.BELT.typeOf(world.getBlockState(entityIn.getPosition()))
|
||||
|| AllBlocks.BELT.typeOf(world.getBlockState(entityIn.getPosition().down())));
|
||||
|
||||
if (movedPastEndingSlope && !movingDown && Math.abs(movementSpeed) > 0)
|
||||
entityIn.setPosition(entityIn.posX, entityIn.posY + movement.y, entityIn.posZ);
|
||||
if (movedPastEndingSlope)
|
||||
entityIn.setMotion(movement);
|
||||
return new Vec3i(movement.getX(), movingUp ? 1 : -1, movement.getZ());
|
||||
}
|
||||
|
||||
public boolean canTransport(Entity entity) {
|
||||
if (!entity.isAlive())
|
||||
return false;
|
||||
if (entity instanceof PlayerEntity && ((PlayerEntity) entity).isSneaking())
|
||||
return false;
|
||||
protected Direction getMovementFacing() {
|
||||
return Direction.getFacingFromAxisDirection(getBeltFacing().getAxis(),
|
||||
getBeltMovementSpeed() < 0 ? POSITIVE : NEGATIVE);
|
||||
}
|
||||
|
||||
return true;
|
||||
protected Direction getBeltFacing() {
|
||||
return getBlockState().get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
}
|
||||
|
||||
public BeltInventory getInventory() {
|
||||
if (inventory == null)
|
||||
inventory = new BeltInventory(this);
|
||||
return inventory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,114 +1,81 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.BufferManipulator;
|
||||
import com.simibubi.create.foundation.utility.TessellatorHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer.BlockModelSpinner;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
public class BeltTileEntityRenderer extends KineticTileEntityRenderer {
|
||||
@SuppressWarnings("deprecation")
|
||||
public class BeltTileEntityRenderer extends TileEntityRenderer<BeltTileEntity> {
|
||||
|
||||
protected static class BeltModelAnimator extends BufferManipulator {
|
||||
protected static TextureAtlasSprite beltTextures;
|
||||
protected static TextureAtlasSprite originalTexture;
|
||||
@Override
|
||||
public void render(BeltTileEntity te, double x, double y, double z, float partialTicks, int destroyStage) {
|
||||
super.render(te, x, y, z, partialTicks, destroyStage);
|
||||
if (te.isController()) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translated(x + .5, y + 13 / 16f + .25, z + .5);
|
||||
|
||||
public BeltModelAnimator(ByteBuffer template) {
|
||||
super(template);
|
||||
if (beltTextures == null)
|
||||
initSprites();
|
||||
}
|
||||
|
||||
private void initSprites() {
|
||||
AtlasTexture textureMap = Minecraft.getInstance().getTextureMap();
|
||||
originalTexture = textureMap.getSprite(new ResourceLocation(Create.ID, "block/belt"));
|
||||
beltTextures = textureMap.getSprite(new ResourceLocation(Create.ID, "block/belt_animated"));
|
||||
}
|
||||
|
||||
public ByteBuffer getTransformed(BeltTileEntity te, float x, float y, float z, int color) {
|
||||
original.rewind();
|
||||
mutable.rewind();
|
||||
|
||||
float textureOffsetX = 0;
|
||||
float textureOffsetY = 0;
|
||||
|
||||
if (te.getSpeed() != 0) {
|
||||
float time = AnimationTickHolder.getRenderTick();
|
||||
Direction direction = te.getBlockState().get(BlockStateProperties.HORIZONTAL_FACING);
|
||||
if (direction == Direction.EAST || direction == Direction.NORTH)
|
||||
time = -time;
|
||||
int textureIndex = (int) ((te.getSpeed() * time / 8) % 16);
|
||||
if (textureIndex < 0)
|
||||
textureIndex += 16;
|
||||
|
||||
textureOffsetX = beltTextures.getInterpolatedU((textureIndex % 4) * 4) - originalTexture.getMinU();
|
||||
textureOffsetY = beltTextures.getInterpolatedV((textureIndex / 4) * 4) - originalTexture.getMinV();
|
||||
for (TransportedItemStack transported : te.getInventory().items) {
|
||||
GlStateManager.pushMatrix();
|
||||
Vec3i direction = te.getBeltChainDirection();
|
||||
float offset = transported.beltPosition;
|
||||
Vec3d offsetVec = new Vec3d(direction).scale(offset);
|
||||
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(transported.stack, TransformType.FIXED);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
final BlockState blockState = te.getBlockState();
|
||||
int packedLightCoords = blockState.getPackedLightmapCoords(te.getWorld(), te.getPos());
|
||||
float texOffX = textureOffsetX;
|
||||
float texOffY = textureOffsetY;
|
||||
|
||||
boolean defaultColor = color == -1;
|
||||
int b = defaultColor ? 128 : color & 0xFF;
|
||||
int g = defaultColor ? 128 : (color >> 8) & 0xFF;
|
||||
int r = defaultColor ? 128 : (color >> 16) & 0xFF;
|
||||
|
||||
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
|
||||
putPos(mutable, vertex, getX(original, vertex) + x, getY(original, vertex) + y,
|
||||
getZ(original, vertex) + z);
|
||||
putLight(mutable, vertex, packedLightCoords);
|
||||
|
||||
int bufferPosition = getBufferPosition(vertex);
|
||||
mutable.putFloat(bufferPosition + 16, original.getFloat(bufferPosition + 16) + texOffX);
|
||||
mutable.putFloat(bufferPosition + 20, original.getFloat(bufferPosition + 20) + texOffY);
|
||||
|
||||
byte lumByte = getR(original, vertex);
|
||||
float lum = (lumByte < 0 ? 255 + lumByte : lumByte) / 256f;
|
||||
|
||||
int r2 = (int) (r * lum);
|
||||
int g2 = (int) (g * lum);
|
||||
int b2 = (int) (b * lum);
|
||||
putColor(mutable, vertex, (byte) r2, (byte) g2, (byte) b2, (byte) 255);
|
||||
}
|
||||
|
||||
return mutable;
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
TessellatorHelper.prepareFastRender();
|
||||
TessellatorHelper.begin(DefaultVertexFormats.BLOCK);
|
||||
renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, Tessellator.getInstance().getBuffer());
|
||||
TessellatorHelper.draw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
|
||||
public void renderTileEntityFast(BeltTileEntity te, double x, double y, double z, float partialTicks,
|
||||
int destroyStage, BufferBuilder buffer) {
|
||||
BeltTileEntity beltEntity = (BeltTileEntity) te;
|
||||
|
||||
if (beltEntity.hasPulley())
|
||||
super.renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, buffer);
|
||||
if (te.hasPulley()) {
|
||||
final BlockState state = getRenderedBlockState(te);
|
||||
KineticTileEntityRenderer.cacheIfMissing(state, getWorld(), BlockModelSpinner::new);
|
||||
final BlockPos pos = te.getPos();
|
||||
Axis axis = ((IRotate) te.getBlockState().getBlock()).getRotationAxis(te.getBlockState());
|
||||
float angle = KineticTileEntityRenderer.getAngleForTe(te, pos, axis);
|
||||
KineticTileEntityRenderer.renderFromCache(buffer, state, getWorld(), (float) x, (float) y, (float) z, pos,
|
||||
axis, angle);
|
||||
}
|
||||
|
||||
cacheIfMissing(beltEntity.getBlockState(), getWorld(), BeltModelAnimator::new);
|
||||
renderBeltFromCache(beltEntity, (float) x, (float) y, (float) z, buffer);
|
||||
KineticTileEntityRenderer.cacheIfMissing(te.getBlockState(), getWorld(), BeltModelAnimator::new);
|
||||
renderBeltFromCache(te, (float) x, (float) y, (float) z, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState getRenderedBlockState(KineticTileEntity te) {
|
||||
return AllBlocks.BELT_PULLEY.get().getDefaultState().with(BlockStateProperties.AXIS,
|
||||
((IRotate) AllBlocks.BELT.get()).getRotationAxis(te.getBlockState()));
|
||||
}
|
||||
|
||||
public void renderBeltFromCache(BeltTileEntity te, float x, float y, float z, BufferBuilder buffer) {
|
||||
buffer.putBulkData(
|
||||
((BeltModelAnimator) cachedBuffers.get(te.getBlockState())).getTransformed(te, x, y, z, te.color));
|
||||
buffer.putBulkData(((BeltModelAnimator) KineticTileEntityRenderer.cachedBuffers.get(te.getBlockState()))
|
||||
.getTransformed(te, x, y, z, te.color));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.simibubi.create.foundation.utility.BufferManipulator;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
|
||||
public class FastItemRenderer extends BufferManipulator {
|
||||
|
||||
public FastItemRenderer(ByteBuffer original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
public ByteBuffer getTranslatedAndRotated(World world, float x, float y, float z, float yaw, float pitch) {
|
||||
original.rewind();
|
||||
mutable.rewind();
|
||||
|
||||
float cosYaw = MathHelper.cos(yaw);
|
||||
float sinYaw = MathHelper.sin(yaw);
|
||||
float cosPitch = MathHelper.cos(pitch);
|
||||
float sinPitch = MathHelper.sin(pitch);
|
||||
|
||||
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
|
||||
float xL = getX(original, vertex); // - (float) rotationOffset.x;
|
||||
float yL = getY(original, vertex); // - (float) rotationOffset.y;
|
||||
float zL = getZ(original, vertex); // - (float) rotationOffset.z;
|
||||
|
||||
float xL2 = rotateX(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
float yL2 = rotateY(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
float zL2 = rotateZ(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
//
|
||||
xL = rotateX(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
yL = rotateY(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
zL = rotateZ(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
|
||||
float xPos = xL + x; // + (float) (offset.x + rotationOffset.x);
|
||||
float yPos = yL + y; // + (float) (offset.y + rotationOffset.y);
|
||||
float zPos = zL + z; // + (float) (offset.z + rotationOffset.z);
|
||||
putPos(mutable, vertex, xPos, yPos, zPos);
|
||||
BlockPos pos = new BlockPos(xPos + .5f, yPos + .5f, zPos + .5f);
|
||||
putLight(mutable, vertex, world.getCombinedLight(pos, 15));
|
||||
}
|
||||
|
||||
return mutable;
|
||||
}
|
||||
|
||||
protected static Cache<Item, FastItemRenderer> cachedItems;
|
||||
|
||||
public static void renderItem(BufferBuilder buffer, World world, ItemStack stack, float x, float y, float z,
|
||||
float yaw, float pitch) {
|
||||
if (stack.isEmpty())
|
||||
return;
|
||||
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
IBakedModel model = itemRenderer.getModelWithOverrides(stack);
|
||||
|
||||
if (model.isBuiltInRenderer()) {
|
||||
renderItemIntoBuffer(stack, itemRenderer, model, 0, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
cacheIfMissing(stack);
|
||||
FastItemRenderer renderer = cachedItems.getIfPresent(stack.getItem());
|
||||
if (renderer == null)
|
||||
return;
|
||||
buffer.putBulkData(renderer.getTranslatedAndRotated(world, x, y +1, z, yaw, pitch));
|
||||
}
|
||||
|
||||
protected static void cacheIfMissing(ItemStack stack) {
|
||||
if (cachedItems == null)
|
||||
cachedItems = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.SECONDS).build();
|
||||
if (cachedItems.getIfPresent(stack.getItem()) != null)
|
||||
return;
|
||||
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
IBakedModel model = itemRenderer.getModelWithOverrides(stack);
|
||||
|
||||
int color = 0;
|
||||
BufferBuilder bufferbuilder = new BufferBuilder(0);
|
||||
bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
renderItemIntoBuffer(stack, itemRenderer, model, color, bufferbuilder);
|
||||
bufferbuilder.finishDrawing();
|
||||
cachedItems.put(stack.getItem(), new FastItemRenderer(bufferbuilder.getByteBuffer()));
|
||||
}
|
||||
|
||||
protected static void renderItemIntoBuffer(ItemStack stack, ItemRenderer itemRenderer, IBakedModel model, int color,
|
||||
BufferBuilder bufferbuilder) {
|
||||
Random random = new Random(42L);
|
||||
for (Direction direction : Direction.values())
|
||||
itemRenderer.renderQuads(bufferbuilder, model.getQuads(null, direction, random, EmptyModelData.INSTANCE),
|
||||
color, stack);
|
||||
itemRenderer.renderQuads(bufferbuilder, model.getQuads(null, null, random, EmptyModelData.INSTANCE), color,
|
||||
stack);
|
||||
}
|
||||
|
||||
public static void invalidateCache() {
|
||||
if (cachedItems != null)
|
||||
cachedItems.invalidateAll();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "create:belt_support"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue