Clockwork Bearing and Rope Pulley

- Stationary Contraption Entities no longer sync positions like normal entities
- Flimsy attempts at making linear contraption movement smoother, especially at differing tick speeds between server and client
- Added slot covers for the Mechanical Crafter
- Added the Clockwork Bearing
- Added the Rope Pulley
- Server speed no longer tries to sync when game is paused
- Fixed crash when moving block breakers are loaded in while stalled
- Fixed Cuckoo Clock's angle interpolation when tps is low
This commit is contained in:
simibubi 2020-02-15 18:54:23 +01:00
parent 6537214403
commit b1a0f25f4b
69 changed files with 2315 additions and 268 deletions

View file

@ -40,7 +40,7 @@ public enum AllBlockPartials {
GAUGE_INDICATOR("gauge/indicator"),
GAUGE_HEAD_SPEED("gauge/speed"),
GAUGE_HEAD_STRESS("gauge/stress"),
MECHANICAL_BEARING_TOP,
MECHANICAL_BEARING_TOP("bearing/top"),
DRILL,
HARVESTER_BLADE,
DEPLOYER_POLE("deployer/pole"),
@ -64,6 +64,9 @@ public enum AllBlockPartials {
CUCKOO_RIGHT_DOOR("cuckoo_clock/right_door"),
CUCKOO_PIG("cuckoo_clock/pig"),
CUCKOO_CREEPER("cuckoo_clock/creeper"),
ROPE_COIL("pulley/rope_coil"),
ROPE_HALF("pulley/rope_half"),
ROPE_HALF_MAGNET("pulley/rope_half_magnet"),
;

View file

@ -12,6 +12,7 @@ import com.simibubi.create.modules.contraptions.components.actors.DrillBlock;
import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock;
import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock;
import com.simibubi.create.modules.contraptions.components.clock.CuckooClockBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.LinearChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.RadialChassisBlock;
@ -20,6 +21,7 @@ import com.simibubi.create.modules.contraptions.components.contraptions.mounted.
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonHeadBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonPoleBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock;
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterBlock;
import com.simibubi.create.modules.contraptions.components.crank.HandCrankBlock;
import com.simibubi.create.modules.contraptions.components.crusher.CrushingWheelBlock;
@ -138,6 +140,12 @@ public enum AllBlocks {
MECHANICAL_PISTON_HEAD(new MechanicalPistonHeadBlock()),
PISTON_POLE(new PistonPoleBlock()),
MECHANICAL_BEARING(new MechanicalBearingBlock()),
CLOCKWORK_BEARING(new ClockworkBearingBlock()),
ROPE_PULLEY(new PulleyBlock()),
ROPE(new PulleyBlock.RopeBlock()),
PULLEY_MAGNET(new PulleyBlock.MagnetBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()),
TRANSLATION_CHASSIS(new LinearChassisBlock()),
TRANSLATION_CHASSIS_SECONDARY(new LinearChassisBlock()),
ROTATION_CHASSIS(new RadialChassisBlock()),
@ -146,8 +154,6 @@ public enum AllBlocks {
HARVESTER(new HarvesterBlock()),
DEPLOYER(new DeployerBlock()),
PORTABLE_STORAGE_INTERFACE(new PortableStorageInterfaceBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()),
ANALOG_LEVER(new AnalogLeverBlock()),
ANDESITE_CASING(new CasingBlock("andesite_casing")),

View file

@ -2,6 +2,7 @@ package com.simibubi.create;
import java.util.function.Function;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntityRenderer;
@ -18,7 +19,8 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry;
public enum AllEntities {
CONTRAPTION(ContraptionEntity::new, 30, 3, ContraptionEntity::build),
CONTRAPTION(ContraptionEntity::new, 30, 3, true, ContraptionEntity::build),
STATIONARY_CONTRAPTION(ContraptionEntity::new, 30, 40, false, ContraptionEntity::build),
;
@ -27,24 +29,26 @@ public enum AllEntities {
private int updateFrequency;
private Function<EntityType.Builder<? extends Entity>, EntityType.Builder<? extends Entity>> propertyBuilder;
private EntityClassification group;
private boolean sendVelocity;
public EntityType<? extends Entity> type;
private AllEntities(IFactory<?> factory, int range, int updateFrequency,
private AllEntities(IFactory<?> factory, int range, int updateFrequency, boolean sendVelocity,
Function<EntityType.Builder<? extends Entity>, EntityType.Builder<? extends Entity>> propertyBuilder) {
this.factory = factory;
this.range = range;
this.updateFrequency = updateFrequency;
this.sendVelocity = sendVelocity;
this.propertyBuilder = propertyBuilder;
}
public static void register(final RegistryEvent.Register<EntityType<?>> event) {
for (AllEntities entity : values()) {
String id = entity.name().toLowerCase();
String id = Lang.asId(entity.name());
ResourceLocation resourceLocation = new ResourceLocation(Create.ID, id);
Builder<? extends Entity> builder = EntityType.Builder.create(entity.factory, entity.group)
.setTrackingRange(entity.range).setUpdateInterval(entity.updateFrequency)
.setShouldReceiveVelocityUpdates(true);
.setShouldReceiveVelocityUpdates(entity.sendVelocity);
if (entity.propertyBuilder != null)
builder = entity.propertyBuilder.apply(builder);
entity.type = builder.build(id).setRegistryName(resourceLocation);

View file

@ -84,6 +84,7 @@ public enum AllItems {
PROPELLER,
WHISK,
BRASS_HAND,
SLOT_COVER,
WRENCH(WrenchItem::new),
GOGGLES(GogglesItem::new),

View file

@ -28,7 +28,7 @@ public enum AllParticles {
private ParticleEntry<?> entry;
private <D extends IParticleData> AllParticles(Supplier<? extends ICustomParticle<D>> typeFactory) {
String asId = Lang.asId(this.name().toLowerCase());
String asId = Lang.asId(this.name());
entry = new ParticleEntry<D>(new ResourceLocation(Create.ID, asId), typeFactory);
}

View file

@ -11,11 +11,14 @@ import com.simibubi.create.modules.contraptions.components.actors.HarvesterTileE
import com.simibubi.create.modules.contraptions.components.actors.HarvesterTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.clock.CuckooClockRenderer;
import com.simibubi.create.modules.contraptions.components.clock.CuckooClockTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.BearingTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyTileEntity;
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntity;
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.crank.HandCrankTileEntity;
@ -114,6 +117,8 @@ public enum AllTileEntities {
BELT_TUNNEL(BeltTunnelTileEntity::new, AllBlocks.BELT_TUNNEL),
MECHANICAL_PISTON(MechanicalPistonTileEntity::new, AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON),
MECHANICAL_BEARING(MechanicalBearingTileEntity::new, AllBlocks.MECHANICAL_BEARING),
CLOCKWORK_BEARING(ClockworkBearingTileEntity::new, AllBlocks.CLOCKWORK_BEARING),
ROPE_PULLEY(PulleyTileEntity::new, AllBlocks.ROPE_PULLEY),
CHASSIS(ChassisTileEntity::new, AllBlocks.ROTATION_CHASSIS, AllBlocks.TRANSLATION_CHASSIS,
AllBlocks.TRANSLATION_CHASSIS_SECONDARY),
DRILL(DrillTileEntity::new, AllBlocks.DRILL),
@ -200,7 +205,9 @@ public enum AllTileEntities {
bind(AnalogLeverTileEntity.class, new AnalogLeverTileEntityRenderer());
bind(MechanicalPistonTileEntity.class, new MechanicalPistonTileEntityRenderer());
bind(MechanicalBearingTileEntity.class, new MechanicalBearingTileEntityRenderer());
bind(MechanicalBearingTileEntity.class, new BearingTileEntityRenderer());
bind(ClockworkBearingTileEntity.class, new BearingTileEntityRenderer());
bind(PulleyTileEntity.class, new PulleyRenderer());
bind(HarvesterTileEntity.class, new HarvesterTileEntityRenderer());
bind(CrushingWheelTileEntity.class, new KineticTileEntityRenderer());

View file

@ -22,6 +22,7 @@ public class CKinetics extends ConfigBase {
public ConfigInt maxChassisForRotation = i(16, 1, "maxChassisForRotation", Comments.maxChassisForRotation);
public ConfigInt maxChassisRange = i(16, 1, "maxChassisRange", Comments.maxChassisRange);
public ConfigInt maxPistonPoles = i(64, 1, "maxPistonPoles", Comments.maxPistonPoles);
public ConfigInt maxRopeLength = i(128, 1, "maxRopeLength", Comments.maxRopeLength);
public ConfigGroup state = group(0, "stats", Comments.stats);
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
@ -54,6 +55,7 @@ public class CKinetics extends ConfigBase {
static String maxChassisForRotation = "Maximum amount of chassis blocks movable by a Mechanical Bearing.";
static String maxChassisRange = "Maximum value of a chassis attachment range.";
static String maxPistonPoles = "Maximum amount of extension poles behind a Mechanical Piston.";
static String maxRopeLength = "Max length of rope available off a Rope Pulley.";
static String stats = "Configure speed/capacity levels for requirements and indicators.";
static String rpm = "[in Revolutions per Minute]";
static String su = "[in Stress Units]";

View file

@ -37,12 +37,14 @@ public class StressConfigDefaults {
case ENCASED_FAN:
case MECHANICAL_MIXER:
case MECHANICAL_BEARING:
case MECHANICAL_CRAFTER:
return 8;
case TURNTABLE:
case MECHANICAL_PISTON:
case MECHANICAL_BEARING:
case CLOCKWORK_BEARING:
case ROPE_PULLEY:
case STICKY_MECHANICAL_PISTON:
return 4;

View file

@ -36,7 +36,11 @@ public class AllShapes {
makeCuboidShape(0, 0, 9, 16, 16, 14)), Direction.SOUTH),
PORTABLE_STORAGE_INTERFACE = VoxelShaper.forDirectional(VoxelShapes.or(
makeCuboidShape(0, 0, 0, 16, 12, 16),
makeCuboidShape(3, 12, 3, 13, 16, 13)), Direction.UP)
makeCuboidShape(3, 12, 3, 13, 16, 13)), Direction.UP),
PULLEY = VoxelShaper.forHorizontalAxis(VoxelShapes.or(
makeCuboidShape(0, 0, 0, 16, 16, 2),
makeCuboidShape(1, 1, 2, 15, 15, 14),
makeCuboidShape(0, 0, 14, 16, 16, 16)), Direction.SOUTH)
;
@ -114,8 +118,11 @@ public class AllShapes {
BELT_COLLISION_MASK = makeCuboidShape(0, 0, 0, 16, 19, 16),
SCHEMATICANNON_SHAPE = VoxelShapes.or(
makeCuboidShape(1, 0, 1, 15, 8, 15),
makeCuboidShape(0.5, 8, 0.5, 15.5, 11, 15.5))
makeCuboidShape(0.5, 8, 0.5, 15.5, 11, 15.5)),
PULLEY_MAGNET = VoxelShapes.or(
makeCuboidShape(3, 0, 3, 13, 2, 13),
FOUR_VOXEL_POLE.get(Direction.UP))
;

View file

@ -19,5 +19,19 @@ public class AngleHelper {
public static float rad(float angle) {
return (float) (angle / 180 * Math.PI);
}
public static float deg(float angle) {
return (float) (angle * 180 / Math.PI);
}
public static float angleLerp(float pct, float current, float target) {
return current + getShortestAngleDiff(current, target) * pct;
}
public static float getShortestAngleDiff(double current, double target) {
current = current % 360;
target = target % 360;
return (float) (((((target - current) % 360) + 540) % 360) - 180);
}
}

View file

@ -7,7 +7,10 @@ import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -38,10 +41,14 @@ public class ServerSpeedProvider {
return AllConfigs.SERVER.tickrateSyncTimer.get();
}
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void onClientTick(TickEvent.ClientTickEvent event) {
if (event.phase == Phase.START)
return;
if (Minecraft.getInstance().isSingleplayer() && Minecraft.getInstance().isGamePaused())
return;
modifier.tick();
clientTimer++;
}

View file

@ -0,0 +1,107 @@
package com.simibubi.create.modules.contraptions.base;
import com.simibubi.create.modules.contraptions.RotationPropagator;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.IProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public abstract class HorizontalAxisKineticBlock extends KineticBlock {
public static final IProperty<Axis> HORIZONTAL_AXIS = BlockStateProperties.HORIZONTAL_AXIS;
public HorizontalAxisKineticBlock(Properties properties) {
super(properties);
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(HORIZONTAL_AXIS);
super.fillStateContainer(builder);
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
Axis preferredAxis = getPreferredHorizontalAxis(context);
if (preferredAxis != null)
return this.getDefaultState().with(HORIZONTAL_AXIS, preferredAxis);
return this.getDefaultState().with(HORIZONTAL_AXIS, context.getPlacementHorizontalFacing().rotateY().getAxis());
}
public Axis getPreferredHorizontalAxis(BlockItemUseContext context) {
Direction prefferedSide = null;
for (Direction side : Direction.values()) {
if (side.getAxis().isVertical())
continue;
BlockState blockState = context.getWorld().getBlockState(context.getPos().offset(side));
if (blockState.getBlock() instanceof IRotate) {
if (((IRotate) blockState.getBlock()).hasShaftTowards(context.getWorld(), context.getPos().offset(side),
blockState, side.getOpposite()))
if (prefferedSide != null && prefferedSide.getAxis() != side.getAxis()) {
prefferedSide = null;
break;
} else {
prefferedSide = side;
}
}
}
return prefferedSide == null ? null : prefferedSide.getAxis();
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(HORIZONTAL_AXIS);
}
@Override
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) {
return face.getAxis() == state.get(HORIZONTAL_AXIS);
}
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
Direction facing = context.getFace();
if (facing.getAxis().isVertical())
return ActionResultType.PASS;
World world = context.getWorld();
if (facing.getAxis() == state.get(HORIZONTAL_AXIS))
return ActionResultType.PASS;
if (!world.isRemote) {
BlockPos pos = context.getPos();
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
if (tileEntity.hasNetwork())
tileEntity.getNetwork().remove(tileEntity);
RotationPropagator.handleRemoved(world, pos, tileEntity);
tileEntity.removeSource();
world.setBlockState(pos, state.cycle(HORIZONTAL_AXIS), 3);
tileEntity.attachKinetics();
}
return ActionResultType.SUCCESS;
}
@Override
public BlockState rotate(BlockState state, Rotation rot) {
Axis axis = state.get(HORIZONTAL_AXIS);
return state.with(HORIZONTAL_AXIS,
rot.rotate(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis)).getAxis());
}
@Override
public BlockState mirror(BlockState state, Mirror mirrorIn) {
return state;
}
}

View file

@ -16,6 +16,8 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
@Override
public void startMoving(MovementContext context) {
if (context.world.isRemote)
return;
context.data.putInt("BreakerId", -BlockBreakingKineticTileEntity.NEXT_BREAKER_ID.incrementAndGet());
}
@ -40,6 +42,8 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
@Override
public void stopMoving(MovementContext context) {
CompoundNBT data = context.data;
if (context.world.isRemote)
return;
if (!data.contains("BreakingPos"))
return;
@ -58,6 +62,8 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
@Override
public void tick(MovementContext context) {
CompoundNBT data = context.data;
if (context.world.isRemote)
return;
if (!data.contains("BreakingPos"))
return;
if (context.relativeMotion.equals(Vec3d.ZERO)) {

View file

@ -1,5 +1,9 @@
package com.simibubi.create.modules.contraptions.components.clock;
import static com.simibubi.create.foundation.utility.AngleHelper.deg;
import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngleDiff;
import static com.simibubi.create.foundation.utility.AngleHelper.rad;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import com.simibubi.create.foundation.gui.widgets.InterpolatedValue;
@ -20,7 +24,7 @@ import net.minecraft.world.Explosion;
public class CuckooClockTileEntity extends KineticTileEntity {
public static DamageSource CUCKOO_SURPRISE = new DamageSource("create.cuckoo_clock_explosion").setExplosion();
public InterpolatedChasingValue hourHand = new InterpolatedChasingValue().withSpeed(.2f);
public InterpolatedChasingValue minuteHand = new InterpolatedChasingValue().withSpeed(.2f);
public InterpolatedValue animationProgress = new InterpolatedValue();
@ -69,22 +73,23 @@ public class CuckooClockTileEntity extends KineticTileEntity {
if (!world.isRemote) {
if (animationType == null) {
if (hours == 12 && minutes < 5)
if (hours == 12 && minutes < 5)
startAnimation(Animation.PIG);
if (hours == 18 && minutes < 36 && minutes > 31)
if (hours == 18 && minutes < 36 && minutes > 31)
startAnimation(Animation.CREEPER);
} else {
float value = animationProgress.value;
animationProgress.set(value + 1);
if (value > 100)
animationType = null;
if (animationType == Animation.SURPRISE && animationProgress.value == 50) {
Vec3d center = VecHelper.getCenterOf(pos);
world.destroyBlock(pos, false);
world.createExplosion(null, CUCKOO_SURPRISE, center.x, center.y, center.z, 3, false, Explosion.Mode.BREAK);
world.createExplosion(null, CUCKOO_SURPRISE, center.x, center.y, center.z, 3, false,
Explosion.Mode.BREAK);
}
}
}
@ -150,21 +155,11 @@ public class CuckooClockTileEntity extends KineticTileEntity {
}
public void moveHands(int hours, int minutes) {
float hourTarget = (float) (2 * Math.PI / 12 * (hours % 12));
float minuteTarget = (float) (2 * Math.PI / 60 * minutes);
float hourTarget = (float) (360 / 12 * (hours % 12));
float minuteTarget = (float) (360 / 60 * minutes);
hourHand.target(hourTarget);
minuteHand.target(minuteTarget);
if (minuteTarget - minuteHand.value < 0) {
minuteHand.value = (float) (minuteHand.value - Math.PI * 2);
minuteHand.lastValue = minuteHand.value;
}
if (hourTarget - hourHand.value < 0) {
hourHand.value = (float) (hourHand.value - Math.PI * 2);
hourHand.lastValue = hourHand.value;
}
hourHand.target(hourHand.value + rad(getShortestAngleDiff(deg(hourHand.value), hourTarget)));
minuteHand.target(minuteHand.value + rad(getShortestAngleDiff(deg(minuteHand.value), minuteTarget)));
hourHand.tick();
minuteHand.tick();

View file

@ -14,6 +14,7 @@ import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.MutablePair;
@ -22,13 +23,10 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.BearingContraption;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.LinearChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.RadialChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.mounted.MountedContraption;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonContraption;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import net.minecraft.block.Block;
@ -57,6 +55,8 @@ import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class Contraption {
protected static Map<String, Supplier<? extends Contraption>> deserializers = new HashMap<>();
public Map<BlockPos, BlockInfo> blocks;
public Map<BlockPos, MountedStorage> storage;
public List<MutablePair<BlockInfo, MovementContext>> actors;
@ -69,6 +69,10 @@ public class Contraption {
protected Direction cachedColliderDirection;
protected BlockPos anchor;
protected static void register(String name, Supplier<? extends Contraption> factory) {
deserializers.put(name, factory);
}
public Contraption() {
blocks = new HashMap<>();
storage = new HashMap<>();
@ -168,7 +172,7 @@ public class Contraption {
return true;
}
private boolean moveBlock(World world, BlockPos pos, Direction direction, List<BlockPos> frontier,
protected boolean moveBlock(World world, BlockPos pos, Direction direction, List<BlockPos> frontier,
Set<BlockPos> visited) {
visited.add(pos);
frontier.remove(pos);
@ -478,12 +482,8 @@ public class Contraption {
public static Contraption fromNBT(World world, CompoundNBT nbt) {
String type = nbt.getString("Type");
Contraption contraption = new Contraption();
if (type.equals("Piston"))
contraption = new PistonContraption();
if (type.equals("Mounted"))
contraption = new MountedContraption();
if (type.equals("Bearing"))
contraption = new BearingContraption();
if (deserializers.containsKey(type))
contraption = deserializers.get(type).get();
contraption.readNBT(world, nbt);
return contraption;
}
@ -525,14 +525,7 @@ public class Contraption {
public CompoundNBT writeNBT() {
CompoundNBT nbt = new CompoundNBT();
if (this instanceof PistonContraption)
nbt.putString("Type", "Piston");
if (this instanceof MountedContraption)
nbt.putString("Type", "Mounted");
if (this instanceof BearingContraption)
nbt.putString("Type", "Bearing");
nbt.putString("Type", getType());
ListNBT blocksNBT = new ListNBT();
for (BlockInfo block : this.blocks.values()) {
CompoundNBT c = new CompoundNBT();
@ -676,4 +669,8 @@ public class Contraption {
return ((IPortableBlock) block).getMovementBehaviour();
}
protected String getType() {
return "Contraption";
}
}

View file

@ -1,5 +1,8 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp;
import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngleDiff;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllEntities;
@ -38,6 +41,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected BlockPos controllerPos;
protected IControlContraption controllerTE;
protected Vec3d motionBeforeStall;
protected boolean stationary;
private static final DataParameter<Boolean> STALLED =
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
@ -57,21 +61,27 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public ContraptionEntity(EntityType<?> entityTypeIn, World worldIn) {
super(entityTypeIn, worldIn);
motionBeforeStall = Vec3d.ZERO;
stationary = entityTypeIn == AllEntities.STATIONARY_CONTRAPTION.type;
}
protected ContraptionEntity(World world) {
this(AllEntities.CONTRAPTION.type, world);
}
public ContraptionEntity(World world, Contraption contraption, float initialAngle) {
this(world);
this.contraption = contraption;
this.initialAngle = initialAngle;
this.prevYaw = initialAngle;
this.yaw = initialAngle;
this.targetYaw = initialAngle;
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) {
ContraptionEntity entity = new ContraptionEntity(AllEntities.CONTRAPTION.type, world);
entity.contraption = contraption;
entity.initialAngle = initialAngle;
entity.prevYaw = initialAngle;
entity.yaw = initialAngle;
entity.targetYaw = initialAngle;
if (contraption != null)
contraption.gatherStoredItems();
return entity;
}
public static ContraptionEntity createStationary(World world, Contraption contraption) {
ContraptionEntity entity = new ContraptionEntity(AllEntities.STATIONARY_CONTRAPTION.type, world);
entity.contraption = contraption;
if (contraption != null)
contraption.gatherStoredItems();
return entity;
}
public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) {
@ -131,6 +141,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return;
}
if (getMotion().length() > 1 / 4098f)
move(getMotion().x, getMotion().y, getMotion().z);
prevYaw = yaw;
prevPitch = pitch;
prevRoll = roll;
@ -160,7 +173,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch);
actorPosition = actorPosition.add(rotationOffset).add(posX, posY, posZ);
boolean newPosVisited = context.position == null;
boolean newPosVisited = false;
BlockPos gridPosition = new BlockPos(actorPosition);
if (!stalledPreviously) {
@ -170,7 +183,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
Vec3d relativeMotion = context.motion;
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition);
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition)
|| context.relativeMotion.length() > 0 && context.firstMovement;
}
}
@ -178,16 +192,18 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
context.position = actorPosition;
if (actor.isActive(context)) {
if (newPosVisited && !context.stall)
if (newPosVisited && !context.stall) {
actor.visitNewPosition(context, gridPosition);
context.firstMovement = false;
}
actor.tick(context);
contraption.stalled |= context.stall;
}
}
if (!world.isRemote) {
if (!stalledPreviously && contraption.stalled) {
setMotion(Vec3d.ZERO);
if (controllerTE != null)
controllerTE.onStall();
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this),
@ -240,6 +256,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
this.posX = x;
this.posY = y;
this.posZ = z;
if (this.isAddedToWorld() && !this.world.isRemote && world instanceof ServerWorld)
((ServerWorld) this.world).chunkCheck(this); // Forge - Process chunk registration after moving.
if (contraption != null) {
@ -277,16 +294,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return partialTicks == 1.0F ? roll : angleLerp(partialTicks, prevRoll, roll);
}
private float angleLerp(float pct, float current, float target) {
return current + getShortestAngleDiff(current, target) * pct;
}
private float getShortestAngleDiff(double current, double target) {
current = current % 360;
target = target % 360;
return (float) (((((target - current) % 360) + 540) % 360) - 180);
}
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
@SuppressWarnings("unchecked")
EntityType.Builder<ContraptionEntity> entityBuilder = (EntityType.Builder<ContraptionEntity>) builder;
@ -367,6 +374,17 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return dataManager.get(STALLED);
}
@OnlyIn(Dist.CLIENT)
@Override
public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch,
int posRotationIncrements, boolean teleport) {
// Stationary Anchors are responsible for keeping position and motion in sync
// themselves.
if (stationary)
return;
super.setPositionAndRotationDirect(x, y, z, yaw, pitch, posRotationIncrements, teleport);
}
@OnlyIn(Dist.CLIENT)
static void handleStallPacket(ContraptionStallPacket packet) {
Entity entity = Minecraft.getInstance().world.getEntityByID(packet.entityID);

View file

@ -20,6 +20,7 @@ public class MovementContext {
public CompoundNBT tileData;
public boolean stall;
public boolean firstMovement;
public CompoundNBT data;
public Contraption contraption;
public Object temporaryData;
@ -28,7 +29,8 @@ public class MovementContext {
this.world = world;
this.state = info.state;
this.tileData = info.nbt;
firstMovement = true;
motion = Vec3d.ZERO;
relativeMotion = Vec3d.ZERO;
rotation = Vec3d.ZERO;
@ -55,6 +57,7 @@ public class MovementContext {
if (nbt.contains("Position"))
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
context.stall = nbt.getBoolean("Stall");
context.firstMovement = nbt.getBoolean("FirstMovement");
context.data = nbt.getCompound("Data");
return context;
}
@ -66,6 +69,7 @@ public class MovementContext {
if (position != null)
nbt.put("Position", VecHelper.writeNBT(position));
nbt.putBoolean("Stall", stall);
nbt.putBoolean("FirstMovement", firstMovement);
nbt.put("Data", data);
return nbt;
}

View file

@ -0,0 +1,43 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldReader;
public abstract class BearingBlock extends DirectionalKineticBlock {
public BearingBlock() {
super(Properties.from(Blocks.PISTON));
}
@Override
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) {
return face == state.get(FACING).getOpposite();
}
@Override
protected boolean hasStaticPart() {
return true;
}
@Override
protected boolean turnBackOnWrenched() {
return true;
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(FACING).getAxis();
}
@Override
public boolean showCapacityWithAnnotation() {
return true;
}
}

View file

@ -13,10 +13,21 @@ import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class BearingContraption extends Contraption {
protected int sailBlocks;
protected Direction facing;
private static String type = "Bearing";
static {
register(type, BearingContraption::new);
}
@Override
protected String getType() {
return type;
}
public static BearingContraption assembleBearingAt(World world, BlockPos pos, Direction direction) {
if (isFrozen())
return null;

View file

@ -11,21 +11,21 @@ import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
public class MechanicalBearingTileEntityRenderer extends KineticTileEntityRenderer {
public class BearingTileEntityRenderer extends KineticTileEntityRenderer {
@Override
public void renderFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) {
super.renderFast(te, x, y, z, partialTicks, destroyStage, buffer);
MechanicalBearingTileEntity bearingTe = (MechanicalBearingTileEntity) te;
IBearingTileEntity bearingTe = (IBearingTileEntity) te;
final Direction facing = te.getBlockState().get(BlockStateProperties.FACING);
SuperByteBuffer superBuffer = AllBlockPartials.MECHANICAL_BEARING_TOP.renderOn(te.getBlockState());
superBuffer.rotateCentered(Axis.X, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing)));
if (facing.getAxis().isHorizontal())
superBuffer.rotateCentered(Axis.Y, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite())));
float interpolatedAngle = bearingTe.getInterpolatedAngle(partialTicks - 1);
kineticRotationTransform(superBuffer, bearingTe, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI),
kineticRotationTransform(superBuffer, te, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI),
getWorld());
superBuffer.translate(x, y, z).renderInto(buffer);
}
@ -33,7 +33,7 @@ public class MechanicalBearingTileEntityRenderer extends KineticTileEntityRender
@Override
protected SuperByteBuffer getRotatedModel(KineticTileEntity te) {
return AllBlockPartials.SHAFT_HALF.renderOnDirectional(te.getBlockState(),
te.getBlockState().get(MechanicalBearingBlock.FACING).getOpposite());
te.getBlockState().get(BearingBlock.FACING).getOpposite());
}
}

View file

@ -0,0 +1,14 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockReader;
public class ClockworkBearingBlock extends BearingBlock {
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new ClockworkBearingTileEntity();
}
}

View file

@ -0,0 +1,266 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkContraption.HandType;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class ClockworkBearingTileEntity extends KineticTileEntity implements IBearingTileEntity {
protected ContraptionEntity hourHand;
protected ContraptionEntity minuteHand;
protected float hourAngle;
protected float minuteAngle;
protected float clientHourAngleDiff;
protected float clientMinuteAngleDiff;
protected boolean running;
protected boolean assembleNextTick;
public ClockworkBearingTileEntity() {
super(AllTileEntities.CLOCKWORK_BEARING.type);
setLazyTickRate(3);
}
@Override
public void tick() {
super.tick();
if (world.isRemote) {
clientMinuteAngleDiff /= 2;
clientHourAngleDiff /= 2;
}
if (running && Contraption.isFrozen())
disassembleConstruct();
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
boolean canDisassemble = true;
if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption().blocks.isEmpty())) {
if (hourHand != null)
hourHand.getContraption().stop(world);
if (minuteHand != null)
minuteHand.getContraption().stop(world);
disassembleConstruct();
}
return;
} else {
assembleConstruct();
}
return;
}
if (!running)
return;
if (!(hourHand != null && hourHand.isStalled())) {
float newAngle = hourAngle + getHourArmSpeed();
hourAngle = (float) (newAngle % 360);
}
if (!(minuteHand != null && minuteHand.isStalled())) {
float newAngle = minuteAngle + getMinuteArmSpeed();
minuteAngle = (float) (newAngle % 360);
}
applyRotations();
}
protected void applyRotations() {
Axis axis = getBlockState().get(BlockStateProperties.FACING).getAxis();
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
Vec3d directionVec = new Vec3d(direction.getDirectionVec());
if (hourHand != null) {
Vec3d vec = new Vec3d(1, 1, 1).scale(hourAngle).mul(directionVec);
hourHand.rotateTo(vec.x, vec.y, vec.z);
}
if (minuteHand != null) {
Vec3d vec = new Vec3d(1, 1, 1).scale(minuteAngle).mul(directionVec);
minuteHand.rotateTo(vec.x, vec.y, vec.z);
}
}
@Override
public void lazyTick() {
super.lazyTick();
if (hourHand != null && !world.isRemote)
sendData();
}
public float getHourArmSpeed() {
float speed = getAngularSpeed() / 2f + clientHourAngleDiff / 3f;
if (speed != 0) {
int dayTime = (int) (world.getDayTime() % 24000);
int hours = (dayTime / 1000 + 6) % 24;
float hourTarget = (float) (-360 / 12f * (hours % 12));
speed = Math.max(speed, AngleHelper.getShortestAngleDiff(hourAngle, hourTarget));
}
return speed;
}
public float getMinuteArmSpeed() {
float speed = getAngularSpeed() + clientMinuteAngleDiff / 3f;
if (speed != 0) {
int dayTime = (int) (world.getDayTime() % 24000);
int minutes = (dayTime % 1000) * 60 / 1000;
float hourTarget = (float) (-360 / 60f * (minutes));
speed = Math.max(speed, AngleHelper.getShortestAngleDiff(minuteAngle, hourTarget));
}
return speed;
}
public float getAngularSpeed() {
float speed = -Math.abs(getSpeed() * 3 / 10f);
if (world.isRemote)
speed *= ServerSpeedProvider.get();
return speed;
}
public void assembleConstruct() {
Direction direction = getBlockState().get(BlockStateProperties.FACING);
// Collect Construct
Pair<ClockworkContraption, ClockworkContraption> contraption =
ClockworkContraption.assembleClockworkAt(world, pos, direction);
if (contraption == null)
return;
if (contraption.getLeft() == null)
return;
BlockPos anchor = pos.offset(direction);
contraption.getLeft().removeBlocksFromWorld(world, BlockPos.ZERO);
hourHand = ContraptionEntity.createStationary(world, contraption.getLeft()).controlledBy(this);
hourHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
world.addEntity(hourHand);
if (contraption.getRight() != null) {
anchor = pos.offset(direction, contraption.getRight().offset + 1);
contraption.getRight().removeBlocksFromWorld(world, BlockPos.ZERO);
minuteHand = ContraptionEntity.createStationary(world, contraption.getRight()).controlledBy(this);
minuteHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
world.addEntity(minuteHand);
}
// Run
running = true;
hourAngle = 0;
minuteAngle = 0;
sendData();
}
public void disassembleConstruct() {
if (!running)
return;
if (hourHand != null)
hourHand.disassemble();
if (minuteHand != null)
minuteHand.disassemble();
hourHand = null;
minuteHand = null;
running = false;
hourAngle = 0;
minuteAngle = 0;
sendData();
}
@Override
public void attach(ContraptionEntity contraption) {
if (contraption.getContraption() instanceof ClockworkContraption) {
ClockworkContraption cc = (ClockworkContraption) contraption.getContraption();
markDirty();
Direction facing = getBlockState().get(BlockStateProperties.FACING);
BlockPos anchor = pos.offset(facing, cc.offset + 1);
if (cc.handType == HandType.HOUR) {
this.hourHand = contraption;
hourHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
} else {
this.minuteHand = contraption;
minuteHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
}
if (!world.isRemote)
sendData();
}
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putFloat("HourAngle", hourAngle);
tag.putFloat("MinuteAngle", minuteAngle);
return super.write(tag);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
hourAngle = tag.getFloat("HourAngle");
minuteAngle = tag.getFloat("MinuteAngle");
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
float hourAngleBefore = hourAngle;
float minuteAngleBefore = minuteAngle;
super.readClientUpdate(tag);
if (running) {
clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle);
clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle);
hourAngle = hourAngleBefore;
minuteAngle = minuteAngleBefore;
}
}
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
assembleNextTick = true;
}
@Override
public boolean isValid() {
return !isRemoved();
}
@Override
public float getInterpolatedAngle(float partialTicks) {
if (hourHand != null && hourHand.isStalled())
partialTicks = 0;
return MathHelper.lerp(partialTicks, hourAngle, hourAngle + getHourArmSpeed());
}
@Override
public void onStall() {
if (!world.isRemote)
sendData();
}
@Override
public void remove() {
if (!world.isRemote)
disassembleConstruct();
super.remove();
}
}

View file

@ -0,0 +1,122 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiPredicate;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class ClockworkContraption extends Contraption {
protected Direction facing;
public HandType handType;
public int offset;
private Set<BlockPos> ignoreBlocks = new HashSet<>();
private static String type = "Clockwork";
static {
register(type, ClockworkContraption::new);
}
@Override
protected String getType() {
return type;
}
private void ignoreBlocks(Set<BlockPos> blocks, BlockPos anchor) {
for (BlockPos blockPos : blocks)
ignoreBlocks.add(anchor.add(blockPos));
}
public static Pair<ClockworkContraption, ClockworkContraption> assembleClockworkAt(World world, BlockPos pos,
Direction direction) {
if (isFrozen())
return null;
int hourArmBlocks = 0;
ClockworkContraption hourArm = new ClockworkContraption();
ClockworkContraption minuteArm = null;
hourArm.facing = direction;
hourArm.handType = HandType.HOUR;
if (!hourArm.searchMovedStructure(world, pos, direction))
return null;
for (int i = 0; i < 16; i++) {
BlockPos offsetPos = BlockPos.ZERO.offset(direction, i);
if (hourArm.blocks.containsKey(offsetPos))
continue;
hourArmBlocks = i;
break;
}
if (hourArmBlocks > 0) {
minuteArm = new ClockworkContraption();
minuteArm.facing = direction;
minuteArm.handType = HandType.MINUTE;
minuteArm.offset = hourArmBlocks;
minuteArm.ignoreBlocks(hourArm.blocks.keySet(), hourArm.anchor);
if (!minuteArm.searchMovedStructure(world, pos, direction))
return null;
if (minuteArm.blocks.isEmpty())
minuteArm = null;
}
hourArm.initActors(world);
if (minuteArm != null)
minuteArm.initActors(world);
return Pair.of(hourArm, minuteArm);
}
@Override
public boolean searchMovedStructure(World world, BlockPos pos, Direction direction) {
return super.searchMovedStructure(world, pos.offset(direction, offset + 1), direction);
}
@Override
public void disassemble(World world, BlockPos offset, float yaw, float pitch,
BiPredicate<BlockPos, BlockState> customPlacement) {
super.disassemble(world, offset, yaw, pitch, customPlacement);
}
@Override
protected boolean moveBlock(World world, BlockPos pos, Direction direction, List<BlockPos> frontier,
Set<BlockPos> visited) {
if (ignoreBlocks.contains(pos))
return true;
return super.moveBlock(world, pos, direction, frontier, visited);
}
@Override
public CompoundNBT writeNBT() {
CompoundNBT tag = super.writeNBT();
tag.putInt("facing", facing.getIndex());
tag.putInt("offset", offset);
tag.putString("HandType", NBTHelper.writeEnum(handType));
return tag;
}
@Override
public void readNBT(World world, CompoundNBT tag) {
facing = Direction.byIndex(tag.getInt("Facing"));
handType = NBTHelper.readEnum(tag.getString("HandType"), HandType.class);
offset = tag.getInt("offset");
super.readNBT(world, tag);
}
public static enum HandType {
HOUR, MINUTE
}
}

View file

@ -0,0 +1,9 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption;
public interface IBearingTileEntity extends IControlContraption {
float getInterpolatedAngle(float partialTicks);
}

View file

@ -1,25 +1,15 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class MechanicalBearingBlock extends DirectionalKineticBlock
implements IWithTileEntity<MechanicalBearingTileEntity> {
public MechanicalBearingBlock() {
super(Properties.from(Blocks.PISTON));
}
public class MechanicalBearingBlock extends BearingBlock implements IWithTileEntity<MechanicalBearingTileEntity> {
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
@ -35,29 +25,4 @@ public class MechanicalBearingBlock extends DirectionalKineticBlock
withTileEntityDo(worldIn, pos, MechanicalBearingTileEntity::neighbourChanged);
}
@Override
public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) {
return face == state.get(FACING).getOpposite();
}
@Override
protected boolean hasStaticPart() {
return true;
}
@Override
protected boolean turnBackOnWrenched() {
return true;
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(FACING).getAxis();
}
@Override
public boolean showCapacityWithAnnotation() {
return true;
}
}

View file

@ -1,11 +1,11 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.modules.contraptions.base.GeneratingKineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
@ -16,14 +16,13 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IControlContraption {
public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IBearingTileEntity {
protected boolean isWindmill;
protected ContraptionEntity movedContraption;
protected float angle;
protected boolean running;
protected boolean assembleNextTick;
protected boolean isWindmill;
protected float clientAngleDiff;
public MechanicalBearingTileEntity() {
@ -99,12 +98,11 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public void readClientUpdate(CompoundNBT tag) {
float angleBefore = angle;
super.readClientUpdate(tag);
clientAngleDiff = angle - angleBefore;
if (Math.abs(clientAngleDiff) > 20)
clientAngleDiff = 0;
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
angle = angleBefore;
}
@Override
public float getInterpolatedAngle(float partialTicks) {
if (movedContraption != null && movedContraption.isStalled())
partialTicks = 0;
@ -136,7 +134,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (isWindmill && contraption.getSailBlocks() == 0)
return;
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
movedContraption = new ContraptionEntity(world, contraption, 0).controlledBy(this);
movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this);
BlockPos anchor = pos.offset(direction);
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
world.addEntity(movedContraption);
@ -152,8 +150,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public void disassembleConstruct() {
if (!running)
return;
movedContraption.disassemble();
if (movedContraption != null)
movedContraption.disassemble();
movedContraption = null;
running = false;
angle = 0;
@ -209,7 +208,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
sendData();
}
private void applyRotation() {
protected void applyRotation() {
if (movedContraption != null) {
Axis axis = getBlockState().get(BlockStateProperties.FACING).getAxis();
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);

View file

@ -30,8 +30,8 @@ import net.minecraft.world.World;
public class CartAssemblerBlock extends AbstractRailBlock {
public static IProperty<RailShape> RAIL_SHAPE = EnumProperty.create("shape", RailShape.class, RailShape.EAST_WEST,
RailShape.NORTH_SOUTH);
public static IProperty<RailShape> RAIL_SHAPE =
EnumProperty.create("shape", RailShape.class, RailShape.EAST_WEST, RailShape.NORTH_SOUTH);
public static BooleanProperty POWERED = BlockStateProperties.POWERED;
public CartAssemblerBlock() {
@ -75,8 +75,8 @@ public class CartAssemblerBlock extends AbstractRailBlock {
Contraption contraption = MountedContraption.assembleMinecart(world, pos, cart);
if (contraption == null)
return;
ContraptionEntity entity = new ContraptionEntity(world, contraption,
ContraptionEntity.yawFromVector(cart.getMotion()));
float initialAngle = ContraptionEntity.yawFromVector(cart.getMotion());
ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialAngle);
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
world.addEntity(entity);
entity.startRiding(cart);

View file

@ -25,6 +25,17 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class MountedContraption extends Contraption {
private static String type = "Mounted";
static {
register(type, MountedContraption::new);
}
@Override
protected String getType() {
return type;
}
public static Contraption assembleMinecart(World world, BlockPos pos, AbstractMinecartEntity cart) {
if (isFrozen())
return null;

View file

@ -0,0 +1,201 @@
package com.simibubi.create.modules.contraptions.components.contraptions.piston;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public abstract class LinearActuatorTileEntity extends KineticTileEntity implements IControlContraption {
public float offset;
public boolean running;
protected boolean assembleNextTick;
public ContraptionEntity movedContraption;
protected boolean forceMove;
// Custom position sync
protected float clientOffsetDiff;
public LinearActuatorTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
setLazyTickRate(3);
}
@Override
public void tick() {
super.tick();
boolean contraptionPresent = movedContraption != null;
if (contraptionPresent)
if (!movedContraption.isAlive())
movedContraption = null;
if (world.isRemote)
clientOffsetDiff *= .75f;
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
if (getSpeed() == 0)
disassembleConstruct();
else
sendData();
return;
}
assembleConstruct();
return;
}
if (!running)
return;
contraptionPresent = movedContraption != null;
float movementSpeed = getMovementSpeed();
float newOffset = offset + movementSpeed;
if ((int) newOffset != (int) offset)
visitNewPosition();
if (!contraptionPresent || !movedContraption.isStalled())
offset = newOffset;
if (contraptionPresent)
applyContraptionMotion();
int extensionRange = getExtensionRange();
if (offset <= 0 || offset >= extensionRange) {
offset = offset <= 0 ? 0 : extensionRange;
if (!world.isRemote)
disassembleConstruct();
return;
}
}
@Override
public void lazyTick() {
super.lazyTick();
if (movedContraption != null && !world.isRemote)
sendData();
}
protected int getGridOffset(float offset) {
return MathHelper.clamp((int) (offset + .5f), 0, getExtensionRange());
}
public float getInterpolatedOffset(float partialTicks) {
float interpolatedOffset =
MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, getExtensionRange());
return interpolatedOffset;
}
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
assembleNextTick = true;
}
@Override
public void remove() {
this.removed = true;
if (!world.isRemote)
disassembleConstruct();
super.remove();
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putFloat("Offset", offset);
return super.write(tag);
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
if (forceMove) {
compound.putBoolean("ForceMovement", forceMove);
forceMove = false;
}
return super.writeToClient(compound);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
offset = tag.getFloat("Offset");
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
float offsetBefore = offset;
super.readClientUpdate(tag);
if (running) {
clientOffsetDiff = offset - offsetBefore;
offset = offsetBefore;
}
if (tag.contains("ForceMovement"))
if (movedContraption != null)
applyContraptionPosition();
}
protected abstract void assembleConstruct();
protected abstract void disassembleConstruct();
protected abstract int getExtensionRange();
protected abstract void visitNewPosition();
protected abstract Vec3d toMotionVector(float speed);
protected abstract Vec3d toPosition(float offset);
protected void applyContraptionMotion() {
if (movedContraption.isStalled())
movedContraption.setMotion(Vec3d.ZERO);
else
movedContraption.setMotion(getMotionVector());
}
protected void applyContraptionPosition() {
Vec3d vec = toPosition(offset);
movedContraption.setPosition(vec.x, vec.y, vec.z);
}
public float getMovementSpeed() {
float movementSpeed = getSpeed() / 512f + clientOffsetDiff / 2f;
if (world.isRemote)
movementSpeed *= ServerSpeedProvider.get();
return movementSpeed;
}
public Vec3d getMotionVector() {
return toMotionVector(getMovementSpeed());
}
@Override
public void onStall() {
if (!world.isRemote) {
forceMove = true;
sendData();
}
}
@Override
public boolean isValid() {
return !isRemoved();
}
@Override
public void attach(ContraptionEntity contraption) {
this.movedContraption = contraption;
if (!world.isRemote)
sendData();
}
}

View file

@ -2,10 +2,7 @@ package com.simibubi.create.modules.contraptions.components.contraptions.piston;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
import net.minecraft.nbt.CompoundNBT;
@ -13,17 +10,11 @@ import net.minecraft.state.properties.BlockStateProperties;
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.util.math.Vec3d;
public class MechanicalPistonTileEntity extends KineticTileEntity implements IControlContraption {
public class MechanicalPistonTileEntity extends LinearActuatorTileEntity {
protected float offset;
protected boolean running;
protected boolean assembleNextTick;
protected boolean hadCollisionWithOtherPiston;
protected ContraptionEntity movedContraption;
protected int extensionLength;
public MechanicalPistonTileEntity() {
@ -31,35 +22,18 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
}
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
assembleNextTick = true;
}
@Override
public void remove() {
this.removed = true;
if (!world.isRemote)
disassembleConstruct();
super.remove();
public void read(CompoundNBT tag) {
extensionLength = tag.getInt("ExtensionLength");
super.read(tag);
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putFloat("Offset", offset);
tag.putInt("ExtensionLength", extensionLength);
return super.write(tag);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
offset = tag.getFloat("Offset");
extensionLength = tag.getInt("ExtensionLength");
super.read(tag);
}
public void assembleConstruct() {
Direction direction = getBlockState().get(BlockStateProperties.FACING);
@ -82,19 +56,22 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
BlockPos startPos = BlockPos.ZERO.offset(direction, contraption.initialExtensionProgress);
contraption.removeBlocksFromWorld(world, startPos);
movedContraption = new ContraptionEntity(getWorld(), contraption, 0).controlledBy(this);
moveContraption();
movedContraption = ContraptionEntity.createStationary(getWorld(), contraption).controlledBy(this);
applyContraptionPosition();
forceMove = true;
world.addEntity(movedContraption);
}
@Override
public void disassembleConstruct() {
if (!running)
return;
if (!removed)
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3);
if (movedContraption != null)
if (movedContraption != null) {
applyContraptionPosition();
movedContraption.disassemble();
}
running = false;
movedContraption = null;
sendData();
@ -104,58 +81,31 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
}
@Override
public void tick() {
super.tick();
if (movedContraption != null && movedContraption.isStalled())
return;
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
if (getSpeed() == 0)
disassembleConstruct();
else
sendData();
return;
}
assembleConstruct();
return;
}
if (!running)
return;
float movementSpeed = getMovementSpeed();
if (world.isRemote)
movementSpeed *= ServerSpeedProvider.get();
float newOffset = offset + movementSpeed;
if (movedContraption == null)
return;
if (!world.isRemote && getModulatedOffset(newOffset) != getModulatedOffset(offset)) {
offset = newOffset;
sendData();
}
offset = newOffset;
moveContraption();
if (offset <= 0 || offset >= extensionLength) {
offset = offset <= 0 ? 0 : extensionLength;
if (!world.isRemote)
disassembleConstruct();
return;
}
public float getMovementSpeed() {
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
int movementModifier =
pistonDirection.getAxisDirection().getOffset() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1);
return super.getMovementSpeed() * -movementModifier;
}
public void moveContraption() {
if (movedContraption != null) {
Vec3d constructOffset = getConstructOffset(0.5f);
Vec3d vec = constructOffset.add(new Vec3d(movedContraption.getContraption().getAnchor()));
movedContraption.move(vec.x - movedContraption.posX, vec.y - movedContraption.posY,
vec.z - movedContraption.posZ);
}
@Override
protected int getExtensionRange() {
return extensionLength;
}
@Override
protected void visitNewPosition() {
}
@Override
protected Vec3d toMotionVector(float speed) {
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(speed);
}
@Override
protected Vec3d toPosition(float offset) {
Vec3d position = new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(offset);
return position.add(new Vec3d(movedContraption.getContraption().getAnchor()));
}
// private boolean hasBlockCollisions(float newOffset) {
@ -236,41 +186,4 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
// return false;
// }
private int getModulatedOffset(float offset) {
return MathHelper.clamp((int) (offset + .5f), 0, extensionLength);
}
public float getMovementSpeed() {
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
int movementModifier =
pistonDirection.getAxisDirection().getOffset() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1);
return getSpeed() * -movementModifier / 512f;
}
public Vec3d getConstructOffset(float partialTicks) {
float interpolatedOffset =
MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, extensionLength);
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset);
}
@Override
public void attach(ContraptionEntity contraption) {
if (contraption.getContraption() instanceof PistonContraption) {
this.movedContraption = contraption;
if (!world.isRemote)
sendData();
}
}
@Override
public void onStall() {
if (!world.isRemote)
sendData();
}
@Override
public boolean isValid() {
return !isRemoved();
}
}

View file

@ -37,6 +37,16 @@ public class PistonContraption extends Contraption {
protected int initialExtensionProgress;
protected Direction orientation;
private static String type = "Piston";
static {
register(type, PistonContraption::new);
}
@Override
protected String getType() {
return type;
}
public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
if (isFrozen())
return null;

View file

@ -0,0 +1,115 @@
package com.simibubi.create.modules.contraptions.components.contraptions.pulley;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.IHaveNoBlockItem;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.contraptions.base.HorizontalAxisKineticBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.state.EnumProperty;
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.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class PulleyBlock extends HorizontalAxisKineticBlock {
public static EnumProperty<Axis> HORIZONTAL_AXIS = BlockStateProperties.HORIZONTAL_AXIS;
public PulleyBlock() {
super(Properties.from(Blocks.ANDESITE));
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return new PulleyTileEntity();
}
@Override
protected boolean hasStaticPart() {
return true;
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return AllShapes.PULLEY.get(state.get(HORIZONTAL_AXIS));
}
private static void onRopeBroken(World world, BlockPos pulleyPos) {
TileEntity te = world.getTileEntity(pulleyPos);
if (!(te instanceof PulleyTileEntity))
return;
PulleyTileEntity pulley = (PulleyTileEntity) te;
pulley.offset = 0;
pulley.sendData();
}
private static class RopeBlockBase extends Block implements IHaveNoBlockItem {
public RopeBlockBase(Properties properties) {
super(properties);
}
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
if (isMoving)
return;
if (fromPos.equals(pos.down()) && this != AllBlocks.PULLEY_MAGNET.get())
if (!AllBlocks.ROPE.typeOf(worldIn.getBlockState(fromPos))
&& !AllBlocks.PULLEY_MAGNET.typeOf(worldIn.getBlockState(fromPos))) {
worldIn.destroyBlock(pos, true);
}
if (fromPos.equals(pos.up()))
if (!AllBlocks.ROPE.typeOf(worldIn.getBlockState(fromPos))
&& !AllBlocks.ROPE_PULLEY.typeOf(worldIn.getBlockState(fromPos))) {
worldIn.destroyBlock(pos, true);
}
}
@Override
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (!isMoving)
onRopeBroken(worldIn, pos.up());
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
worldIn.removeTileEntity(pos);
}
}
}
public static class MagnetBlock extends RopeBlockBase {
public MagnetBlock() {
super(Properties.from(Blocks.ANDESITE));
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return AllShapes.PULLEY_MAGNET;
}
}
public static class RopeBlock extends RopeBlockBase {
public RopeBlock() {
super(Properties.from(Blocks.WHITE_WOOL));
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return AllShapes.FOUR_VOXEL_POLE.get(Direction.UP);
}
}
}

View file

@ -0,0 +1,49 @@
package com.simibubi.create.modules.contraptions.components.contraptions.pulley;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class PulleyContraption extends Contraption {
int initialOffset;
private static String type = "Pulley";
static {
register(type, PulleyContraption::new);
}
@Override
protected String getType() {
return type;
}
public static PulleyContraption assemblePulleyAt(World world, BlockPos pos, int initialOffset) {
if (isFrozen())
return null;
PulleyContraption construct = new PulleyContraption();
construct.initialOffset = initialOffset;
if (!construct.searchMovedStructure(world, pos, Direction.DOWN))
return null;
construct.initActors(world);
return construct;
}
@Override
public CompoundNBT writeNBT() {
CompoundNBT writeNBT = super.writeNBT();
writeNBT.putInt("InitialOffset", initialOffset);
return writeNBT;
}
@Override
public void readNBT(World world, CompoundNBT nbt) {
initialOffset = nbt.getInt("InitialOffset");
super.readNBT(world, nbt);
}
}

View file

@ -0,0 +1,75 @@
package com.simibubi.create.modules.contraptions.components.contraptions.pulley;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class PulleyRenderer extends KineticTileEntityRenderer {
@Override
public void renderFast(KineticTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
BufferBuilder buffer) {
super.renderFast(te, x, y, z, partialTicks, destroyStage, buffer);
PulleyTileEntity pulley = (PulleyTileEntity) te;
BlockState blockState = te.getBlockState();
BlockPos pos = te.getPos();
SuperByteBuffer halfMagnet = AllBlockPartials.ROPE_HALF_MAGNET.renderOn(blockState);
SuperByteBuffer halfRope = AllBlockPartials.ROPE_HALF.renderOn(blockState);
SuperByteBuffer magnet = CreateClient.bufferCache.renderBlock(AllBlocks.PULLEY_MAGNET.getDefault());
SuperByteBuffer rope = CreateClient.bufferCache.renderBlock(AllBlocks.ROPE.getDefault());
boolean moving = pulley.running && (pulley.movedContraption == null || !pulley.movedContraption.isStalled());
float offset = pulley.getInterpolatedOffset(moving ? partialTicks : 0.5f);
if (pulley.movedContraption != null) {
ContraptionEntity e = pulley.movedContraption;
PulleyContraption c = (PulleyContraption) pulley.movedContraption.getContraption();
double entityPos = MathHelper.lerp(partialTicks, e.lastTickPosY, e.posY);
offset = (float) -(entityPos - c.getAnchor().getY() - c.initialOffset);
}
if (pulley.running || pulley.offset == 0)
renderAt(offset > .25f ? magnet : halfMagnet, x, y, z, offset, pos, buffer);
float f = offset % 1;
if (offset > .75f && (f < .25f || f > .75f))
renderAt(halfRope, x, y, z, f > .75f ? f - 1 : f, pos, buffer);
if (!pulley.running)
return;
for (int i = 0; i < offset - 1.25f; i++)
renderAt(rope, x, y, z, offset - i - 1, pos, buffer);
}
public void renderAt(SuperByteBuffer partial, double x, double y, double z, float offset, BlockPos pulleyPos,
BufferBuilder buffer) {
BlockPos actualPos = pulleyPos.down((int) offset);
int light = getWorld().getBlockState(actualPos).getPackedLightmapCoords(getWorld(), actualPos);
partial.translate(x, y - offset, z).light(light).renderInto(buffer);
}
@Override
protected SuperByteBuffer getRotatedModel(KineticTileEntity te) {
BlockState blockState = te.getBlockState();
return AllBlockPartials.ROPE_COIL.renderOnDirectional(blockState, horizontalFacing(blockState));
}
public Direction horizontalFacing(BlockState blockState) {
return Direction.getFacingFromAxis(AxisDirection.POSITIVE, blockState.get(PulleyBlock.HORIZONTAL_AXIS));
}
}

View file

@ -0,0 +1,129 @@
package com.simibubi.create.modules.contraptions.components.contraptions.pulley;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.LinearActuatorTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class PulleyTileEntity extends LinearActuatorTileEntity {
public PulleyTileEntity() {
super(AllTileEntities.ROPE_PULLEY.type);
}
@Override
public AxisAlignedBB getRenderBoundingBox() {
return super.getRenderBoundingBox().expand(0, -offset, 0);
}
@Override
protected void assembleConstruct() {
if (speed == 0)
return;
if (offset >= getExtensionRange() && getSpeed() > 0)
return;
if (offset <= 0 && getSpeed() < 0)
return;
if (!world.isRemote) {
for (int i = ((int) offset); i > 0; i--) {
BlockPos offset = pos.down(i);
world.setBlockState(offset, Blocks.AIR.getDefaultState(), 66);
}
// Collect Construct
BlockPos anchor = pos.down((int) (offset + 1));
PulleyContraption contraption = PulleyContraption.assemblePulleyAt(world, anchor, (int) offset);
if (contraption != null && !contraption.blocks.isEmpty()) {
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this);
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
world.addEntity(movedContraption);
forceMove = true;
}
}
running = true;
sendData();
}
@Override
protected void disassembleConstruct() {
if (!running)
return;
offset = getGridOffset(offset);
if (movedContraption != null)
applyContraptionPosition();
if (!world.isRemote) {
if (offset > 0) {
BlockPos magnetPos = pos.down((int) offset);
world.destroyBlock(magnetPos,
world.getBlockState(magnetPos).getCollisionShape(world, magnetPos).isEmpty());
world.setBlockState(magnetPos, AllBlocks.PULLEY_MAGNET.getDefault(), 66);
}
for (int i = 1; i <= ((int) offset) - 1; i++) {
BlockPos ropePos = pos.down(i);
world.destroyBlock(ropePos, world.getBlockState(ropePos).getCollisionShape(world, ropePos).isEmpty());
}
for (int i = 1; i <= ((int) offset) - 1; i++)
world.setBlockState(pos.down(i), AllBlocks.ROPE.getDefault(), 66);
if (movedContraption != null)
movedContraption.disassemble();
}
if (movedContraption != null)
movedContraption.remove();
movedContraption = null;
running = false;
sendData();
}
@Override
protected Vec3d toPosition(float offset) {
if (movedContraption.getContraption() instanceof PulleyContraption) {
PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption();
return new Vec3d(contraption.getAnchor()).add(0, contraption.initialOffset - offset, 0);
}
return Vec3d.ZERO;
}
@Override
protected void visitNewPosition() {
if (world.isRemote)
return;
if (movedContraption != null)
return;
if (getSpeed() <= 0)
return;
BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1);
BlockState stateBelow = world.getBlockState(posBelow);
if (stateBelow.getMaterial().isReplaceable() || stateBelow.getShape(world, posBelow).isEmpty())
return;
disassembleConstruct();
assembleNextTick = true;
}
@Override
protected int getExtensionRange() {
return Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), pos.getY() - 1);
}
@Override
protected Vec3d toMotionVector(float speed) {
return new Vec3d(0, -speed, 0);
}
}

View file

@ -107,8 +107,11 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
MechanicalCrafterTileEntity crafter = CrafterHelper.getCrafter(worldIn, pos);
if (crafter != null)
if (crafter != null) {
if (crafter.covered)
Block.spawnAsEntity(worldIn, pos, AllItems.SLOT_COVER.asStack());
crafter.ejectWholeGrid();
}
for (Direction direction : Direction.values()) {
if (direction.getAxis() == state.get(HORIZONTAL_FACING).getAxis())
@ -166,31 +169,55 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock
if (!(te instanceof MechanicalCrafterTileEntity))
return false;
MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te;
boolean wrenched = AllItems.WRENCH.typeOf(heldItem);
if (hit.getFace() == state.get(HORIZONTAL_FACING)) {
if (crafter.phase != Phase.IDLE && !AllItems.WRENCH.typeOf(heldItem)) {
if (crafter.phase != Phase.IDLE && !wrenched) {
crafter.ejectWholeGrid();
return true;
}
if (crafter.phase == Phase.IDLE && !isHand && !AllItems.WRENCH.typeOf(heldItem)) {
if (crafter.phase == Phase.IDLE && !isHand && !wrenched) {
if (worldIn.isRemote)
return true;
LazyOptional<IItemHandler> capability = crafter
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
if (AllItems.SLOT_COVER.typeOf(heldItem)) {
if (crafter.covered)
return false;
crafter.covered = true;
crafter.markDirty();
crafter.sendData();
if (!player.isCreative())
heldItem.shrink(1);
return true;
}
LazyOptional<IItemHandler> capability =
crafter.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
if (!capability.isPresent())
return false;
ItemStack remainder = ItemHandlerHelper.insertItem(capability.orElse(new ItemStackHandler()),
heldItem.copy(), false);
ItemStack remainder =
ItemHandlerHelper.insertItem(capability.orElse(new ItemStackHandler()), heldItem.copy(), false);
if (remainder.getCount() != heldItem.getCount())
player.setHeldItem(handIn, remainder);
return true;
}
ItemStack inSlot = crafter.inventory.getStackInSlot(0);
if (inSlot.isEmpty())
if (inSlot.isEmpty()) {
if (crafter.covered && !wrenched) {
if (worldIn.isRemote)
return true;
crafter.covered = false;
crafter.markDirty();
crafter.sendData();
if (!player.isCreative())
player.inventory.placeItemBackInInventory(worldIn, AllItems.SLOT_COVER.asStack());
return true;
}
return false;
}
if (!isHand && !ItemHandlerHelper.canItemStacksStack(heldItem, inSlot))
return false;
if (worldIn.isRemote)

View file

@ -55,6 +55,8 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (phase != Phase.IDLE)
return stack;
if (covered)
return stack;
return super.insertItem(slot, stack, simulate);
};
@ -73,6 +75,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
protected boolean reRender;
protected Phase phase;
protected int countDown;
protected boolean covered;
protected GroupedItems groupedItemsBeforeCraft; // for rendering on client
private InsertingBehaviour inserting;
@ -120,6 +123,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
compound.putString("Phase", phase.name());
compound.putInt("CountDown", countDown);
compound.putBoolean("Cover", covered);
return super.write(compound);
}
@ -166,6 +170,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
if (phase.name().equals(name))
this.phase = phase;
countDown = compound.getInt("CountDown");
covered = compound.getBoolean("Cover");
super.read(compound);
}
@ -368,7 +373,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
}
public boolean craftingItemPresent() {
return !inventory.getStackInSlot(0).isEmpty();
return !inventory.getStackInSlot(0).isEmpty() || covered;
}
protected void checkCompletedRecipe() {

View file

@ -146,7 +146,7 @@ public class MechanicalCrafterTileEntityRenderer extends SafeTileEntityRenderer<
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(blockState);
BlockPos pos = te.getPos();
if (te.phase != Phase.IDLE && te.phase != Phase.CRAFTING && te.phase != Phase.INSERTING) {
if ((te.covered || te.phase != Phase.IDLE) && te.phase != Phase.CRAFTING && te.phase != Phase.INSERTING) {
SuperByteBuffer lidBuffer = renderAndTransform(AllBlockPartials.MECHANICAL_CRAFTER_LID, blockState, pos);
lidBuffer.translate(x, y, z).renderInto(buffer);
}

View file

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.relays.encased;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.DirectionalAxisKineticBlock;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.RotatedPillarKineticBlock;
@ -185,7 +186,7 @@ public class EncasedBeltBlock extends RotatedPillarKineticBlock {
@Override
public String getName() {
return name().toLowerCase();
return Lang.asId(name());
}
}

View file

@ -0,0 +1,16 @@
{
"forge_marker": 1,
"defaults": {
"model": "create:block/bearing/clockwork"
},
"variants": {
"facing" : {
"up" : { },
"down" : { "x": 180 },
"north" : { "x": 90 },
"east" : { "x": 90, "y": 90 },
"south" : { "x": 90, "y": 180 },
"west" : { "x": 90, "y": 270 }
}
}
}

View file

@ -1,7 +1,7 @@
{
"forge_marker": 1,
"defaults": {
"model": "create:block/mechanical_bearing_base"
"model": "create:block/bearing/regular"
},
"variants": {
"facing" : {

View file

@ -0,0 +1,5 @@
{
"variants": {
"" : { "model": "create:block/pulley/magnet" }
}
}

View file

@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "create:block/pulley/rope" }
}
}

View file

@ -0,0 +1,12 @@
{
"forge_marker": 1,
"defaults": {
"model": "create:block/pulley/casing"
},
"variants": {
"axis": {
"z": { },
"x": { "y": 90 }
}
}
}

View file

@ -26,6 +26,7 @@
"item.create.propeller": "Propeller",
"item.create.whisk": "Whisk",
"item.create.brass_hand": "Hand",
"item.create.slot_cover": "Crafter Slot Cover",
"item.create.flour": "Wheat Flour",
"item.create.dough": "Dough",
"item.create.wrench": "Wrench",
@ -117,6 +118,10 @@
"block.create.mechanical_piston_head": "Mechanical Piston Head",
"block.create.piston_pole": "Piston Extension Pole",
"block.create.mechanical_bearing": "Mechanical Bearing",
"block.create.clockwork_bearing": "Clockwork Bearing",
"block.create.rope_pulley": "Rope Pulley",
"block.create.rope": "Rope",
"block.create.pulley_magnet": "Pulley Magnet",
"block.create.translation_chassis": "Linear Chassis",
"block.create.rotation_chassis": "Radial Chassis",
@ -991,6 +996,9 @@
"item.create.shadow_steel.tooltip": "SHADOW STEEL",
"item.create.shadow_steel.tooltip.summary": "A Chromatic material forged _in_ _the_ _void._",
"item.create.slot_cover.tooltip": "SLOT COVER",
"item.create.slot_cover.tooltip.summary": "Used to mark a _Mechanical_ _Crafter_ as an empty slot in a recipe. Crafters do not necessarily have to form a full square grid, this cover find its use when there are recipes where _ingredients_ _are_ _diagonal_ to each other.",
"item.create.logistical_controller_calculation.tooltip": "WIP",
"item.create.logistical_controller_request.tooltip": "WIP",
"item.create.logistical_controller_storage.tooltip": "WIP",

View file

@ -0,0 +1,9 @@
{
"parent": "create:block/bearing/regular",
"textures": {
"particle": "create:block/clockwork_bearing_side",
"gearbox": "create:block/brass_gearbox",
"bearing_side": "create:block/clockwork_bearing_side",
"brass_casing": "create:block/brass_casing"
}
}

View file

@ -0,0 +1,195 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"3": "create:block/gearbox_top",
"4": "create:block/gearbox",
"particle": "create:block/pulley_rope"
},
"elements": [
{
"name": "side",
"from": [2, 2, 14],
"to": [14, 14, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"north": {"uv": [2, 2, 14, 14], "texture": "#4"},
"south": {"uv": [2, 2, 14, 14], "texture": "#4"},
"up": {"uv": [0, 0, 1, 12], "rotation": 270, "texture": "#3"},
"down": {"uv": [2, 11, 14, 12], "texture": "#4"}
}
},
{
"name": "side",
"from": [2, 2, 1],
"to": [14, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"north": {"uv": [14, 2, 2, 14], "texture": "#4"},
"south": {"uv": [14, 2, 2, 14], "texture": "#4"},
"up": {"uv": [1, 0, 0, 12], "rotation": 270, "texture": "#3"},
"down": {"uv": [2, 12, 14, 11], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 2, 14],
"to": [2, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [14, 2, 16, 14], "texture": "#4"},
"east": {"uv": [0, 2, 2, 14], "texture": "#4"},
"south": {"uv": [0, 2, 2, 14], "texture": "#4"},
"west": {"uv": [14, 2, 16, 14], "texture": "#4"},
"up": {"uv": [0, 14, 2, 16], "texture": "#4"},
"down": {"uv": [0, 0, 2, 2], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 2, 0],
"to": [2, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [2, 2, 0, 14], "texture": "#4"},
"east": {"uv": [2, 2, 0, 14], "texture": "#4"},
"south": {"uv": [16, 2, 14, 14], "texture": "#4"},
"west": {"uv": [16, 2, 14, 14], "texture": "#4"},
"up": {"uv": [0, 16, 2, 14], "texture": "#4"},
"down": {"uv": [0, 2, 2, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [14, 2, 14],
"to": [16, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [2, 2, 0, 14], "rotation": 180, "texture": "#4"},
"east": {"uv": [2, 2, 0, 14], "rotation": 180, "texture": "#3"},
"south": {"uv": [16, 2, 14, 14], "rotation": 180, "texture": "#4"},
"west": {"uv": [2, 2, 0, 14], "texture": "#4"},
"up": {"uv": [2, 14, 0, 16], "texture": "#4"},
"down": {"uv": [2, 0, 0, 2], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [14, 2, 0],
"to": [16, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [14, 2, 16, 14], "rotation": 180, "texture": "#4"},
"east": {"uv": [0, 2, 2, 14], "rotation": 180, "texture": "#3"},
"south": {"uv": [0, 2, 2, 14], "rotation": 180, "texture": "#4"},
"west": {"uv": [0, 2, 2, 14], "texture": "#4"},
"up": {"uv": [2, 16, 0, 14], "texture": "#4"},
"down": {"uv": [2, 2, 0, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 0, 14],
"to": [16, 2, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [0, 14, 16, 16], "texture": "#4"},
"east": {"uv": [0, 14, 2, 16], "texture": "#4"},
"south": {"uv": [0, 14, 16, 16], "texture": "#4"},
"west": {"uv": [14, 14, 16, 16], "texture": "#4"},
"up": {"uv": [0, 0, 12, 2], "texture": "#4"},
"down": {"uv": [0, 14, 16, 16], "rotation": 180, "texture": "#3"}
}
},
{
"name": "side_frame",
"from": [0, 14, 14],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 15, 8]},
"faces": {
"north": {"uv": [0, 16, 16, 14], "texture": "#4"},
"east": {"uv": [0, 16, 2, 14], "texture": "#4"},
"south": {"uv": [0, 16, 16, 14], "texture": "#4"},
"west": {"uv": [14, 16, 16, 14], "texture": "#4"},
"up": {"uv": [0, 16, 16, 14], "rotation": 180, "texture": "#3"},
"down": {"uv": [0, 2, 12, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 0, 0],
"to": [16, 2, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [16, 14, 0, 16], "texture": "#4"},
"east": {"uv": [2, 14, 0, 16], "texture": "#4"},
"south": {"uv": [16, 14, 0, 16], "texture": "#4"},
"west": {"uv": [16, 14, 14, 16], "texture": "#4"},
"up": {"uv": [0, 2, 12, 0], "texture": "#4"},
"down": {"uv": [0, 14, 16, 16], "texture": "#3"}
}
},
{
"name": "side_frame",
"from": [0, 14, 0],
"to": [16, 16, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 15, 8]},
"faces": {
"north": {"uv": [16, 16, 0, 14], "texture": "#4"},
"east": {"uv": [2, 16, 0, 14], "texture": "#4"},
"south": {"uv": [16, 16, 0, 14], "texture": "#4"},
"west": {"uv": [16, 16, 14, 14], "texture": "#4"},
"up": {"uv": [0, 2, 16, 0], "rotation": 180, "texture": "#3"},
"down": {"uv": [0, 0, 12, 2], "texture": "#4"}
}
},
{
"name": "front",
"from": [1, 1, 2],
"to": [3, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"east": {"uv": [2, 0, 14, 2], "texture": "#3"},
"west": {"uv": [2, 14, 14, 16], "texture": "#3"},
"up": {"uv": [2, 0, 14, 2], "rotation": 90, "texture": "#3"},
"down": {"uv": [2, 14, 14, 16], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [13, 1, 2],
"to": [15, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"east": {"uv": [14, 14, 2, 16], "texture": "#3"},
"west": {"uv": [14, 0, 2, 2], "texture": "#3"},
"up": {"uv": [2, 2, 14, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [2, 16, 14, 14], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [13, 13, 2],
"to": [15, 15, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 8]},
"faces": {
"east": {"uv": [14, 16, 2, 14], "texture": "#3"},
"west": {"uv": [14, 2, 2, 0], "texture": "#3"},
"up": {"uv": [14, 16, 2, 14], "rotation": 90, "texture": "#3"},
"down": {"uv": [14, 2, 2, 0], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [1, 13, 2],
"to": [3, 15, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 8]},
"faces": {
"east": {"uv": [2, 2, 14, 0], "texture": "#3"},
"west": {"uv": [2, 16, 14, 14], "texture": "#3"},
"up": {"uv": [14, 14, 2, 16], "rotation": 90, "texture": "#3"},
"down": {"uv": [14, 0, 2, 2], "rotation": 90, "texture": "#3"}
}
}
]
}

View file

@ -0,0 +1,323 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"0": "create:block/axis",
"1": "create:block/axis_top",
"3": "create:block/gearbox_top",
"4": "create:block/gearbox",
"5": "create:block/pulley_rope",
"6": "create:block/pulley_magnet",
"particle": "create:block/pulley_magnet"
},
"elements": [
{
"name": "coil",
"from": [4, 4, 2],
"to": [12, 12, 14],
"rotation": {"angle": -45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"east": {"uv": [0, 0, 12, 8], "texture": "#5"},
"west": {"uv": [0, 0, 12, 8], "texture": "#5"},
"up": {"uv": [0, 0, 12, 8], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 12, 8], "rotation": 90, "texture": "#5"}
}
},
{
"name": "coil",
"from": [3.5, 3.5, 9],
"to": [12.5, 12.5, 13],
"rotation": {"angle": -45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"north": {"uv": [0, 0, 9, 9], "texture": "#5"},
"east": {"uv": [0, 0, 4, 9], "texture": "#5"},
"south": {"uv": [0, 0, 9, 9], "texture": "#5"},
"west": {"uv": [0, 0, 4, 9], "rotation": 180, "texture": "#5"},
"up": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"}
}
},
{
"name": "coil",
"from": [3.5, 3.5, 3],
"to": [12.5, 12.5, 7],
"rotation": {"angle": 45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"north": {"uv": [0, 0, 9, 9], "texture": "#5"},
"east": {"uv": [0, 0, 4, 9], "texture": "#5"},
"south": {"uv": [0, 0, 9, 9], "texture": "#5"},
"west": {"uv": [0, 0, 4, 9], "rotation": 180, "texture": "#5"},
"up": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"}
}
},
{
"name": "side",
"from": [2, 2, 14],
"to": [14, 14, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"north": {"uv": [2, 2, 14, 14], "texture": "#4"},
"south": {"uv": [2, 2, 14, 14], "texture": "#4"},
"up": {"uv": [0, 0, 1, 12], "rotation": 270, "texture": "#3"},
"down": {"uv": [2, 11, 14, 12], "texture": "#4"}
}
},
{
"name": "side",
"from": [2, 2, 1],
"to": [14, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"north": {"uv": [14, 2, 2, 14], "texture": "#4"},
"south": {"uv": [14, 2, 2, 14], "texture": "#4"},
"up": {"uv": [1, 0, 0, 12], "rotation": 270, "texture": "#3"},
"down": {"uv": [2, 12, 14, 11], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 2, 14],
"to": [2, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [14, 2, 16, 14], "texture": "#4"},
"east": {"uv": [0, 2, 2, 14], "texture": "#4"},
"south": {"uv": [0, 2, 2, 14], "texture": "#4"},
"west": {"uv": [14, 2, 16, 14], "texture": "#4"},
"up": {"uv": [0, 14, 2, 16], "texture": "#4"},
"down": {"uv": [0, 0, 2, 2], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 2, 0],
"to": [2, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [2, 2, 0, 14], "texture": "#4"},
"east": {"uv": [2, 2, 0, 14], "texture": "#4"},
"south": {"uv": [16, 2, 14, 14], "texture": "#4"},
"west": {"uv": [16, 2, 14, 14], "texture": "#4"},
"up": {"uv": [0, 16, 2, 14], "texture": "#4"},
"down": {"uv": [0, 2, 2, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [14, 2, 14],
"to": [16, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [2, 2, 0, 14], "rotation": 180, "texture": "#4"},
"east": {"uv": [2, 2, 0, 14], "rotation": 180, "texture": "#3"},
"south": {"uv": [16, 2, 14, 14], "rotation": 180, "texture": "#4"},
"west": {"uv": [2, 2, 0, 14], "texture": "#4"},
"up": {"uv": [2, 14, 0, 16], "texture": "#4"},
"down": {"uv": [2, 0, 0, 2], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [14, 2, 0],
"to": [16, 14, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [14, 2, 16, 14], "rotation": 180, "texture": "#4"},
"east": {"uv": [0, 2, 2, 14], "rotation": 180, "texture": "#3"},
"south": {"uv": [0, 2, 2, 14], "rotation": 180, "texture": "#4"},
"west": {"uv": [0, 2, 2, 14], "texture": "#4"},
"up": {"uv": [2, 16, 0, 14], "texture": "#4"},
"down": {"uv": [2, 2, 0, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 0, 14],
"to": [16, 2, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [0, 14, 16, 16], "texture": "#4"},
"east": {"uv": [0, 14, 2, 16], "texture": "#4"},
"south": {"uv": [0, 14, 16, 16], "texture": "#4"},
"west": {"uv": [14, 14, 16, 16], "texture": "#4"},
"up": {"uv": [0, 0, 12, 2], "texture": "#4"},
"down": {"uv": [0, 14, 16, 16], "rotation": 180, "texture": "#3"}
}
},
{
"name": "side_frame",
"from": [0, 14, 14],
"to": [16, 16, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 15, 8]},
"faces": {
"north": {"uv": [0, 16, 16, 14], "texture": "#4"},
"east": {"uv": [0, 16, 2, 14], "texture": "#4"},
"south": {"uv": [0, 16, 16, 14], "texture": "#4"},
"west": {"uv": [14, 16, 16, 14], "texture": "#4"},
"up": {"uv": [0, 16, 16, 14], "rotation": 180, "texture": "#3"},
"down": {"uv": [0, 2, 12, 0], "texture": "#4"}
}
},
{
"name": "side_frame",
"from": [0, 0, 0],
"to": [16, 2, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [16, 14, 0, 16], "texture": "#4"},
"east": {"uv": [2, 14, 0, 16], "texture": "#4"},
"south": {"uv": [16, 14, 0, 16], "texture": "#4"},
"west": {"uv": [16, 14, 14, 16], "texture": "#4"},
"up": {"uv": [0, 2, 12, 0], "texture": "#4"},
"down": {"uv": [0, 14, 16, 16], "texture": "#3"}
}
},
{
"name": "side_frame",
"from": [0, 14, 0],
"to": [16, 16, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 15, 8]},
"faces": {
"north": {"uv": [16, 16, 0, 14], "texture": "#4"},
"east": {"uv": [2, 16, 0, 14], "texture": "#4"},
"south": {"uv": [16, 16, 0, 14], "texture": "#4"},
"west": {"uv": [16, 16, 14, 14], "texture": "#4"},
"up": {"uv": [0, 2, 16, 0], "rotation": 180, "texture": "#3"},
"down": {"uv": [0, 0, 12, 2], "texture": "#4"}
}
},
{
"name": "front",
"from": [1, 1, 2],
"to": [3, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"east": {"uv": [2, 0, 14, 2], "texture": "#3"},
"west": {"uv": [2, 14, 14, 16], "texture": "#3"},
"up": {"uv": [2, 0, 14, 2], "rotation": 90, "texture": "#3"},
"down": {"uv": [2, 14, 14, 16], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [13, 1, 2],
"to": [15, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 8]},
"faces": {
"east": {"uv": [14, 14, 2, 16], "texture": "#3"},
"west": {"uv": [14, 0, 2, 2], "texture": "#3"},
"up": {"uv": [2, 2, 14, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [2, 16, 14, 14], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [13, 13, 2],
"to": [15, 15, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 8]},
"faces": {
"east": {"uv": [14, 16, 2, 14], "texture": "#3"},
"west": {"uv": [14, 2, 2, 0], "texture": "#3"},
"up": {"uv": [14, 16, 2, 14], "rotation": 90, "texture": "#3"},
"down": {"uv": [14, 2, 2, 0], "rotation": 90, "texture": "#3"}
}
},
{
"name": "front",
"from": [1, 13, 2],
"to": [3, 15, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 10, 8]},
"faces": {
"east": {"uv": [2, 2, 14, 0], "texture": "#3"},
"west": {"uv": [2, 16, 14, 14], "texture": "#3"},
"up": {"uv": [14, 14, 2, 16], "rotation": 90, "texture": "#3"},
"down": {"uv": [14, 0, 2, 2], "rotation": 90, "texture": "#3"}
}
},
{
"name": "Axis",
"from": [6, 6, 0],
"to": [10, 10, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [6, 6, 10, 10], "rotation": 180, "texture": "#1"},
"east": {"uv": [6, 0, 10, 16], "rotation": 90, "texture": "#0"},
"south": {"uv": [6, 6, 10, 10], "texture": "#1"},
"west": {"uv": [6, 0, 10, 16], "rotation": 270, "texture": "#0"},
"up": {"uv": [6, 0, 10, 16], "texture": "#0"},
"down": {"uv": [6, 0, 10, 16], "rotation": 180, "texture": "#0"}
}
},
{
"name": "rope",
"from": [6, 2, 6],
"to": [10, 8, 10],
"rotation": {"angle": 0, "axis": "y", "origin": [7.75, 0, 8]},
"faces": {
"north": {"uv": [12, 8, 16, 14], "texture": "#6"},
"east": {"uv": [12, 8, 16, 14], "texture": "#6"},
"south": {"uv": [12, 8, 16, 14], "texture": "#6"},
"west": {"uv": [12, 8, 16, 14], "texture": "#6"},
"up": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#6"}
}
},
{
"name": "magnet",
"from": [3, 0, 3],
"to": [13, 2, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 23, 8]},
"faces": {
"north": {"uv": [0, 10, 10, 12], "texture": "#6"},
"east": {"uv": [0, 10, 10, 12], "texture": "#6"},
"south": {"uv": [0, 10, 10, 12], "texture": "#6"},
"west": {"uv": [0, 10, 10, 12], "texture": "#6"},
"up": {"uv": [0, 0, 10, 10], "texture": "#6"},
"down": {"uv": [0, 0, 10, 10], "texture": "#6"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2.5, 0],
"scale": [0.375, 0.375, 0.375]
},
"firstperson_righthand": {
"rotation": [0, 45, 0],
"scale": [0.4, 0.4, 0.4]
},
"firstperson_lefthand": {
"rotation": [0, 225, 0],
"scale": [0.4, 0.4, 0.4]
},
"ground": {
"translation": [0, 3, 0],
"scale": [0.25, 0.25, 0.25]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
{
"name": "shaft",
"origin": [8, 8, 8],
"children": [17]
},
{
"name": "rope_half_magnet",
"origin": [8, 8, 8],
"children": [18, 19]
}
]
}

View file

@ -0,0 +1,37 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"6": "create:block/pulley_magnet",
"particle": "create:block/pulley_magnet"
},
"elements": [
{
"name": "rope",
"from": [6, 2, 6],
"to": [10, 16, 10],
"rotation": {"angle": 0, "axis": "y", "origin": [7.75, 0, 8]},
"faces": {
"north": {"uv": [12, 0, 16, 14], "texture": "#6"},
"east": {"uv": [12, 0, 16, 14], "texture": "#6"},
"south": {"uv": [12, 0, 16, 14], "texture": "#6"},
"west": {"uv": [12, 0, 16, 14], "texture": "#6"},
"up": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#6"}
}
},
{
"name": "magnet",
"from": [3, 0, 3],
"to": [13, 2, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 23, 8]},
"faces": {
"north": {"uv": [0, 10, 10, 12], "texture": "#6"},
"east": {"uv": [0, 10, 10, 12], "texture": "#6"},
"south": {"uv": [0, 10, 10, 12], "texture": "#6"},
"west": {"uv": [0, 10, 10, 12], "texture": "#6"},
"up": {"uv": [0, 0, 10, 10], "texture": "#6"},
"down": {"uv": [0, 0, 10, 10], "texture": "#6"}
}
}
]
}

View file

@ -0,0 +1,24 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"5": "create:block/pulley_rope",
"particle": "create:block/pulley_rope"
},
"elements": [
{
"name": "rope",
"from": [6, 0, 6],
"to": [10, 16, 10],
"rotation": {"angle": 0, "axis": "y", "origin": [7.75, 0, 8]},
"faces": {
"north": {"uv": [0, 0, 4, 16], "texture": "#5"},
"east": {"uv": [0, 0, 4, 16], "texture": "#5"},
"south": {"uv": [0, 0, 4, 16], "texture": "#5"},
"west": {"uv": [0, 0, 4, 16], "texture": "#5"},
"up": {"uv": [0, 0, 4, 4], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 4], "texture": "#5"}
}
}
]
}

View file

@ -0,0 +1,66 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"0": "create:block/axis",
"1": "create:block/axis_top",
"5": "create:block/pulley_rope"
},
"elements": [
{
"name": "coil",
"from": [4, 4, 2],
"to": [12, 12, 14],
"rotation": {"angle": -45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"east": {"uv": [0, 0, 12, 8], "texture": "#5"},
"west": {"uv": [0, 0, 12, 8], "texture": "#5"},
"up": {"uv": [0, 0, 12, 8], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 12, 8], "rotation": 90, "texture": "#5"}
}
},
{
"name": "coil",
"from": [3.5, 3.5, 9],
"to": [12.5, 12.5, 13],
"rotation": {"angle": -45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"north": {"uv": [0, 0, 9, 9], "texture": "#5"},
"east": {"uv": [0, 0, 4, 9], "texture": "#5"},
"south": {"uv": [0, 0, 9, 9], "texture": "#5"},
"west": {"uv": [0, 0, 4, 9], "rotation": 180, "texture": "#5"},
"up": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"}
}
},
{
"name": "coil",
"from": [3.5, 3.5, 3],
"to": [12.5, 12.5, 7],
"rotation": {"angle": 45, "axis": "z", "origin": [8, 8, -10]},
"faces": {
"north": {"uv": [0, 0, 9, 9], "texture": "#5"},
"east": {"uv": [0, 0, 4, 9], "texture": "#5"},
"south": {"uv": [0, 0, 9, 9], "texture": "#5"},
"west": {"uv": [0, 0, 4, 9], "rotation": 180, "texture": "#5"},
"up": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 9], "rotation": 90, "texture": "#5"}
}
},
{
"name": "Axis",
"from": [6, 6, 0],
"to": [10, 10, 16],
"shade": false,
"rotation": {"angle": 0, "axis": "x", "origin": [8, 1, 8]},
"faces": {
"north": {"uv": [6, 6, 10, 10], "rotation": 180, "texture": "#1"},
"east": {"uv": [6, 0, 10, 16], "rotation": 90, "texture": "#0"},
"south": {"uv": [6, 6, 10, 10], "texture": "#1"},
"west": {"uv": [6, 0, 10, 16], "rotation": 270, "texture": "#0"},
"up": {"uv": [6, 0, 10, 16], "texture": "#0"},
"down": {"uv": [6, 0, 10, 16], "rotation": 180, "texture": "#0"}
}
}
]
}

View file

@ -0,0 +1,24 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"5": "create:block/pulley_rope",
"particle": "create:block/pulley_rope"
},
"elements": [
{
"name": "rope",
"from": [6, 0, 6],
"to": [10, 8, 10],
"rotation": {"angle": 0, "axis": "y", "origin": [7.75, 0, 8]},
"faces": {
"north": {"uv": [0, 8, 4, 16], "texture": "#5"},
"east": {"uv": [0, 8, 4, 16], "texture": "#5"},
"south": {"uv": [0, 8, 4, 16], "texture": "#5"},
"west": {"uv": [0, 8, 4, 16], "texture": "#5"},
"up": {"uv": [0, 0, 4, 4], "rotation": 90, "texture": "#5"},
"down": {"uv": [0, 0, 4, 4], "texture": "#5"}
}
}
]
}

View file

@ -0,0 +1,37 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"6": "create:block/pulley_magnet",
"particle": "create:block/pulley_magnet"
},
"elements": [
{
"name": "rope",
"from": [6, 2, 6],
"to": [10, 8, 10],
"rotation": {"angle": 0, "axis": "y", "origin": [7.75, 0, 8]},
"faces": {
"north": {"uv": [12, 8, 16, 14], "texture": "#6"},
"east": {"uv": [12, 8, 16, 14], "texture": "#6"},
"south": {"uv": [12, 8, 16, 14], "texture": "#6"},
"west": {"uv": [12, 8, 16, 14], "texture": "#6"},
"up": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#6"}
}
},
{
"name": "magnet",
"from": [3, 0, 3],
"to": [13, 2, 13],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 23, 8]},
"faces": {
"north": {"uv": [0, 10, 10, 12], "texture": "#6"},
"east": {"uv": [0, 10, 10, 12], "texture": "#6"},
"south": {"uv": [0, 10, 10, 12], "texture": "#6"},
"west": {"uv": [0, 10, 10, 12], "texture": "#6"},
"up": {"uv": [0, 0, 10, 10], "texture": "#6"},
"down": {"uv": [0, 0, 10, 10], "texture": "#6"}
}
}
]
}

View file

@ -0,0 +1,9 @@
{
"parent": "create:item/mechanical_bearing",
"textures": {
"particle": "create:block/clockwork_bearing_side",
"bearing_top": "create:block/bearing_top",
"gearbox": "create:block/brass_gearbox",
"bearing_side": "create:block/clockwork_bearing_side"
}
}

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/pulley/item"
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "create:item/slot_cover"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "create:clockwork_bearing"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "create:rope_pulley"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,32 @@
{
"type": "crafting_shaped",
"pattern": [
" B ",
"SCS",
" I "
],
"key": {
"S": {
"item": "create:electron_tube"
},
"B": {
"item": "create:turntable"
},
"C": {
"item": "create:brass_casing"
},
"I": {
"item": "create:shaft"
}
},
"result": {
"item": "create:clockwork_bearing",
"count": 1
},
"conditions": [
{
"type": "create:module",
"module": "contraptions"
}
]
}

View file

@ -25,7 +25,7 @@
},
"result": {
"item": "create:mechanical_crafter",
"count": 1
"count": 3
},
"conditions": [
{

View file

@ -0,0 +1,32 @@
{
"type": "crafting_shaped",
"pattern": [
" B ",
"SCS",
" I "
],
"key": {
"S": {
"item": "create:shaft"
},
"B": {
"item": "create:andesite_casing"
},
"C": {
"tag": "minecraft:wool"
},
"I": {
"tag": "forge:plates/iron"
}
},
"result": {
"item": "create:rope_pulley",
"count": 1
},
"conditions": [
{
"type": "create:module",
"module": "contraptions"
}
]
}

View file

@ -0,0 +1,21 @@
{
"type": "crafting_shaped",
"pattern": [
"AAA"
],
"key": {
"A": {
"tag": "forge:nuggets/brass"
}
},
"result": {
"item": "create:slot_cover",
"count": 1
},
"conditions": [
{
"type": "create:module",
"module": "contraptions"
}
]
}