Mounted Storage and Contraption Stalling

- Saws are now portable and chop trees while mounted
- Portable contraptions can now hold an inventory
- Saw, Drill and Harvester now fill a contraptions internal storage before dropping items
- Mounted blocks can now hold moving contraptions in place
- Saw and Drill now briefly stall contraptions while breaking blocks in front of themselves
- Refactored IHaveMovementBehaviour to IPortableBlock and MovementBehaviour
- Fixed Harvester blades rotating in the wrong direction sometimes
- Shadows on portable contraptions are now a little less aggressive
- Added a block for item exchange with storage on contraptions
- Fixed link range config registering with wrong id
- Added a utility for purposely slowing down animations on the client to match server tps
- Smart Tileentities now lazy tick on initialization
- Fixed crash when breaking active bearings
- Fixed crash when cart assembler fails to assemble a contraption
- Fixed goggles having missing textures
- Reworked Schematicannon Model
- Removed Schematicannon Creatifier from creative tab
This commit is contained in:
simibubi 2020-02-12 01:36:18 +01:00
parent 45195df7f9
commit e0b36a79c9
63 changed files with 1725 additions and 555 deletions

View file

@ -10,6 +10,7 @@ import com.simibubi.create.modules.IModule;
import com.simibubi.create.modules.contraptions.CasingBlock;
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.MechanicalBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.LinearChassisBlock;
@ -70,8 +71,8 @@ import com.simibubi.create.modules.palettes.CTWindowBlock;
import com.simibubi.create.modules.palettes.GlassPaneBlock;
import com.simibubi.create.modules.palettes.HorizontalCTGlassBlock;
import com.simibubi.create.modules.palettes.LayeredCTBlock;
import com.simibubi.create.modules.palettes.VerticalCTGlassBlock;
import com.simibubi.create.modules.palettes.ScoriaBlock;
import com.simibubi.create.modules.palettes.VerticalCTGlassBlock;
import com.simibubi.create.modules.schematics.block.CreativeCrateBlock;
import com.simibubi.create.modules.schematics.block.SchematicTableBlock;
import com.simibubi.create.modules.schematics.block.SchematicannonBlock;
@ -129,11 +130,6 @@ public enum AllBlocks {
MECHANICAL_PRESS(new MechanicalPressBlock()),
MECHANICAL_MIXER(new MechanicalMixerBlock()),
BASIN(new BasinBlock()),
MECHANICAL_CRAFTER(new MechanicalCrafterBlock()),
FLYWHEEL(new FlywheelBlock()),
FURNACE_ENGINE(new FurnaceEngineBlock()),
SPEED_GAUGE(new GaugeBlock(GaugeBlock.Type.SPEED)),
STRESS_GAUGE(new GaugeBlock(GaugeBlock.Type.STRESS)),
@ -149,6 +145,7 @@ public enum AllBlocks {
SAW(new SawBlock()),
HARVESTER(new HarvesterBlock()),
DEPLOYER(new DeployerBlock()),
PORTABLE_STORAGE_INTERFACE(new PortableStorageInterfaceBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()),
ANALOG_LEVER(new AnalogLeverBlock()),
@ -157,6 +154,10 @@ public enum AllBlocks {
COPPER_CASING(new CasingBlock("copper_casing")),
BRASS_CASING(new CasingBlock("crafter_top")),
MECHANICAL_CRAFTER(new MechanicalCrafterBlock()),
FLYWHEEL(new FlywheelBlock()),
FURNACE_ENGINE(new FurnaceEngineBlock()),
__LOGISTICS__(),
CONTACT(new ContactBlock()),
REDSTONE_BRIDGE(new RedstoneLinkBlock()),

View file

@ -8,6 +8,8 @@ import com.simibubi.create.foundation.behaviour.filtering.FilteringCountUpdatePa
import com.simibubi.create.foundation.command.ConfigureConfigPacket;
import com.simibubi.create.foundation.packet.NbtPacket;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionStallPacket;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ConfigureChassisPacket;
import com.simibubi.create.modules.contraptions.components.mixer.ConfigureMixerPacket;
import com.simibubi.create.modules.contraptions.components.motor.ConfigureMotorPacket;
@ -45,8 +47,10 @@ public enum AllPackets {
// Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new),
SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new),
BEAM_EFFECT(BlockzapperBeamPacket.class, BlockzapperBeamPacket::new),
CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new),
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new),
;

View file

@ -1,8 +1,6 @@
package com.simibubi.create;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers;
import com.simibubi.create.foundation.advancement.SandpaperUseTrigger;
import net.minecraft.advancements.CriteriaTriggers;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View file

@ -5,7 +5,7 @@ public class CLogistics extends ConfigBase {
public ConfigInt extractorDelay = i(20, 10, "extractorDelay", Comments.extractorDelay);
public ConfigInt extractorInventoryScanDelay = i(40, 10, "extractorInventoryScanDelay", Comments.extractorInventoryScanDelay);
public ConfigInt extractorAmount = i(16, 1, 64, "extractorAmount", Comments.extractorAmount);
public ConfigInt linkRange = i(128, 1, "extractorDelay", Comments.linkRange);
public ConfigInt linkRange = i(128, 1, "linkRange", Comments.linkRange);
@Override
public String getName() {

View file

@ -8,6 +8,10 @@ public class CServer extends ConfigBase {
public ConfigBool enablePalettes = b(true, "enablePalettes");
public ConfigBool enableLogistics = b(true, "enableLogistics");
public ConfigGroup infrastructure = group(0, "infrastructure", Comments.infrastructure);
public ConfigInt tickrateSyncTimer =
i(20, 5, "tickrateSyncTimer", "[in Ticks]", Comments.tickrateSyncTimer, Comments.tickrateSyncTimer2);
public CKinetics kinetics = nested(0, CKinetics::new, Comments.kinetics);
public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics);
public CSchematics schematics = nested(0, CSchematics::new, Comments.schematics);
@ -26,6 +30,10 @@ public class CServer extends ConfigBase {
static String curiosities = "Everything that spins";
static String modules = "Configure which Modules should be accessible in recipes and creative menus.";
static String control = "You can try inhibiting related game mechanics for troubleshooting repeated crashes.";
static String infrastructure = "The Backbone of Create";
static String tickrateSyncTimer =
"The amount of time a server waits before sending out tickrate synchronization packets.";
static String tickrateSyncTimer2 = "These packets help animations to be more accurate when tps is below 20.";
}
}

View file

@ -2,17 +2,13 @@ package com.simibubi.create.foundation.advancement;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.criterion.CriterionInstance;
import net.minecraft.advancements.criterion.ItemPredicate;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
public class SandpaperUseTrigger extends CriterionTriggerBase<SandpaperUseTrigger.Instance> {

View file

@ -58,6 +58,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
public void initialize() {
behaviours.values().forEach(TileEntityBehaviour::initialize);
lazyTick();
}
public void updateClient(CompoundNBT compound) {

View file

@ -33,7 +33,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
super(te, attachments);
customAmountFilter = stack -> 64;
customFilter = stack -> true;
callback = onExtract;
setCallback(onExtract);
}
public ExtractingBehaviour withAmountThreshold(Function<ItemStack, Integer> filter) {
@ -47,11 +47,15 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
}
public boolean extract() {
return extract(getAmountToExtract());
}
public int getAmountToExtract() {
int amount = -1;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null && !filter.anyAmount())
amount = filter.getAmount();
return extract(amount);
return amount;
}
public boolean extract(int exactAmount) {
@ -60,11 +64,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
if (AllConfigs.SERVER.control.freezeExtractors.get())
return false;
Predicate<ItemStack> test = customFilter;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null)
test = customFilter.and(filter::test);
Predicate<ItemStack> test = getFilterTest();
for (IItemHandler inv : getInventories()) {
ItemStack extract = ItemStack.EMPTY;
if (exactAmount != -1)
@ -81,9 +81,21 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
return false;
}
public Predicate<ItemStack> getFilterTest() {
Predicate<ItemStack> test = customFilter;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null)
test = customFilter.and(filter::test);
return test;
}
@Override
public IBehaviourType<?> getType() {
return TYPE;
}
public void setCallback(Consumer<ItemStack> callback) {
this.callback = callback;
}
}

View file

@ -13,8 +13,9 @@ import net.minecraft.util.math.BlockPos;
public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour {
public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE = new IBehaviourType<SingleTargetAutoExtractingBehaviour>() {
};
public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE =
new IBehaviourType<SingleTargetAutoExtractingBehaviour>() {
};
private Supplier<Direction> attachmentDirection;
boolean synced;
@ -28,8 +29,8 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour
advantageOnNextSync = false;
}
public SingleTargetAutoExtractingBehaviour dontSynchronize() {
synced = false;
public SingleTargetAutoExtractingBehaviour setSynchronized(boolean sync) {
synced = sync;
return this;
}

View file

@ -33,7 +33,10 @@ public class AllShapes {
makeCuboidShape(4, 4, 11, 12, 12, 17)), Direction.SOUTH),
FURNACE_ENGINE = VoxelShaper.forHorizontal(VoxelShapes.or(
makeCuboidShape(1, 1, 0, 15, 15, 16),
makeCuboidShape(0, 0, 9, 16, 16, 14)), Direction.SOUTH)
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)
;

View file

@ -6,7 +6,9 @@ import java.util.function.Function;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.AxisAlignedBB;
public class NBTHelper {
@ -44,5 +46,24 @@ public class NBTHelper {
public static List<ItemStack> readItemList(ListNBT stacks) {
return readCompoundList(stacks, ItemStack::read);
}
public static ListNBT writeAABB(AxisAlignedBB bb) {
ListNBT bbtag = new ListNBT();
bbtag.add(new FloatNBT((float) bb.minX));
bbtag.add(new FloatNBT((float) bb.minY));
bbtag.add(new FloatNBT((float) bb.minZ));
bbtag.add(new FloatNBT((float) bb.maxX));
bbtag.add(new FloatNBT((float) bb.maxY));
bbtag.add(new FloatNBT((float) bb.maxZ));
return bbtag;
}
public static AxisAlignedBB readAABB(ListNBT bbtag) {
if (bbtag == null || bbtag.isEmpty())
return null;
return new AxisAlignedBB(bbtag.getFloat(0), bbtag.getFloat(1), bbtag.getFloat(2), bbtag.getFloat(3),
bbtag.getFloat(4), bbtag.getFloat(5));
}
}

View file

@ -0,0 +1,83 @@
package com.simibubi.create.foundation.utility;
import java.util.function.Supplier;
import com.simibubi.create.AllPackets;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.network.NetworkEvent.Context;
import net.minecraftforge.fml.network.PacketDistributor;
@EventBusSubscriber
public class ServerSpeedProvider {
static int clientTimer = 0;
static int serverTimer = 0;
static boolean initialized = false;
static InterpolatedChasingValue modifier = new InterpolatedChasingValue().withSpeed(.25f);
@SubscribeEvent
public static void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase == Phase.START)
return;
serverTimer++;
if (serverTimer > getSyncInterval()) {
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new Packet());
serverTimer = 0;
}
}
public static Integer getSyncInterval() {
return AllConfigs.SERVER.tickrateSyncTimer.get();
}
@SubscribeEvent
public static void onClientTick(TickEvent.ClientTickEvent event) {
if (event.phase == Phase.START)
return;
modifier.tick();
clientTimer++;
}
public static float get() {
return modifier.value;
}
public static class Packet extends SimplePacketBase {
public Packet() {
}
public Packet(PacketBuffer buffer) {
}
@Override
public void write(PacketBuffer buffer) {
}
@Override
public void handle(Supplier<Context> context) {
context.get().enqueueWork(() -> {
if (!initialized) {
initialized = true;
clientTimer = 0;
return;
}
float target = ((float) getSyncInterval()) / Math.max(clientTimer, 1);
modifier.target(target);
clientTimer = 0;
});
context.get().setPacketHandled(true);
}
}
}

View file

@ -23,7 +23,7 @@ import net.minecraft.world.server.ServerWorld;
public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
private static final AtomicInteger NEXT_BREAKER_ID = new AtomicInteger();
public static final AtomicInteger NEXT_BREAKER_ID = new AtomicInteger();
protected int ticksUntilNextProgress;
protected int destroyProgress;
protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet();
@ -119,6 +119,10 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
}
public boolean canBreak(BlockState stateToBreak, float blockHardness) {
return isBreakable(stateToBreak, blockHardness);
}
public static boolean isBreakable(BlockState stateToBreak, float blockHardness) {
return !(stateToBreak.getMaterial().isLiquid() || stateToBreak.getBlock() instanceof AirBlock
|| blockHardness == -1);
}

View file

@ -0,0 +1,122 @@
package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class BlockBreakingMovementBehaviour extends MovementBehaviour {
@Override
public void startMoving(MovementContext context) {
context.data.putInt("BreakerId", -BlockBreakingKineticTileEntity.NEXT_BREAKER_ID.incrementAndGet());
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world;
BlockState stateVisited = world.getBlockState(pos);
if (world.isRemote)
return;
if (stateVisited.getCollisionShape(world, pos).isEmpty())
return;
if (stateVisited.getBlockHardness(world, pos) == -1)
return;
if (!canBreak(stateVisited))
return;
context.data.put("BreakingPos", NBTUtil.writeBlockPos(pos));
context.stall = true;
}
@Override
public void stopMoving(MovementContext context) {
CompoundNBT data = context.data;
if (!data.contains("BreakingPos"))
return;
World world = context.world;
int id = data.getInt("BreakerId");
BlockPos breakingPos = NBTUtil.readBlockPos(data.getCompound("BreakingPos"));
data.remove("Progress");
data.remove("TicksUntilNextProgress");
data.remove("BreakingPos");
context.stall = false;
world.sendBlockBreakProgress(id, breakingPos, -1);
}
@Override
public void tick(MovementContext context) {
CompoundNBT data = context.data;
if (!data.contains("BreakingPos"))
return;
if (context.relativeMotion.equals(Vec3d.ZERO)) {
context.stall = false;
return;
}
int ticksUntilNextProgress = data.getInt("TicksUntilNextProgress");
if (ticksUntilNextProgress-- > 0) {
data.putInt("TicksUntilNextProgress", ticksUntilNextProgress);
return;
}
World world = context.world;
BlockPos breakingPos = NBTUtil.readBlockPos(data.getCompound("BreakingPos"));
int destroyProgress = data.getInt("Progress");
int id = data.getInt("BreakerId");
BlockState stateToBreak = world.getBlockState(breakingPos);
float blockHardness = stateToBreak.getBlockHardness(world, breakingPos);
if (!BlockBreakingKineticTileEntity.isBreakable(stateToBreak, blockHardness) || !canBreak(stateToBreak)) {
if (destroyProgress != 0) {
destroyProgress = 0;
data.remove("Progress");
data.remove("TicksUntilNextProgress");
data.remove("BreakingPos");
context.stall = false;
world.sendBlockBreakProgress(id, breakingPos, -1);
}
return;
}
float breakSpeed = MathHelper.clamp(Math.abs(context.getAnimationSpeed()) / 500f, 1 / 128f, 16f);
destroyProgress += MathHelper.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress);
if (destroyProgress >= 10) {
BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack));
onBlockBroken(context, breakingPos);
ticksUntilNextProgress = -1;
world.sendBlockBreakProgress(id, breakingPos, -1);
data.remove("Progress");
data.remove("TicksUntilNextProgress");
data.remove("BreakingPos");
context.stall = false;
return;
}
ticksUntilNextProgress = (int) (blockHardness / breakSpeed);
world.sendBlockBreakProgress(id, breakingPos, (int) destroyProgress);
data.putInt("TicksUntilNextProgress", ticksUntilNextProgress);
data.putInt("Progress", destroyProgress);
}
protected boolean canBreak(BlockState state) {
return true;
}
protected void onBlockBroken(MovementContext context, BlockPos pos) {
}
}

View file

@ -1,36 +1,28 @@
package com.simibubi.create.modules.contraptions.components.actors;
import java.util.List;
import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
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.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class DrillBlock extends DirectionalKineticBlock
implements IHaveMovementBehavior, IWithTileEntity<DrillTileEntity> {
public class DrillBlock extends DirectionalKineticBlock implements IPortableBlock, IWithTileEntity<DrillTileEntity> {
public static MovementBehaviour MOVEMENT = new DrillMovementBehaviour();
public DrillBlock() {
super(Properties.from(Blocks.IRON_BLOCK));
@ -76,44 +68,10 @@ public class DrillBlock extends DirectionalKineticBlock
protected boolean hasStaticPart() {
return true;
}
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return DrillTileEntityRenderer.renderInContraption(context);
}
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.get(FACING).getOpposite());
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world;
BlockState stateVisited = world.getBlockState(pos);
if (world.isRemote)
return;
if (stateVisited.getCollisionShape(world, pos).isEmpty())
return;
if (stateVisited.getBlockHardness(world, pos) == -1)
return;
world.playEvent(2001, pos, Block.getStateId(stateVisited));
List<ItemStack> drops = Block.getDrops(stateVisited, (ServerWorld) world, pos, null);
world.setBlockState(pos, Blocks.AIR.getDefaultState());
for (ItemStack stack : drops) {
ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack);
itemEntity.setMotion(context.motion.add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
world.addEntity(itemEntity);
}
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -0,0 +1,30 @@
package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion,
context.state.get(DrillBlock.FACING).getOpposite());
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(DrillBlock.FACING).getDirectionVec()).scale(.65f);
}
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return DrillTileEntityRenderer.renderInContraption(context);
}
}

View file

@ -9,7 +9,7 @@ import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior.MovementContext;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction.Axis;
@ -29,9 +29,10 @@ public class DrillTileEntityRenderer extends KineticTileEntityRenderer {
BlockState state = context.state;
SuperByteBuffer buffer = getRotatingModel(state);
float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, state.get(FACING).getOpposite())
? context.getAnimationSpeed()
: 0);
float speed = (float) (context.contraption.stalled
|| !VecHelper.isVecPointingTowards(context.relativeMotion, state.get(FACING).getOpposite())
? context.getAnimationSpeed()
: 0);
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
float time = AnimationTickHolder.getRenderTick() / 20;
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);

View file

@ -1,43 +1,29 @@
package com.simibubi.create.modules.contraptions.components.actors;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.CropsBlock;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.SugarCaneBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IProperty;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.IPlantable;
public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBehavior {
public class HarvesterBlock extends HorizontalBlock implements IPortableBlock {
public static MovementBehaviour MOVEMENT = new HarvesterMovementBehaviour();
public HarvesterBlock() {
super(Properties.from(Blocks.IRON_BLOCK));
@ -70,12 +56,6 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
super.fillStateContainer(builder);
}
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return HarvesterTileEntityRenderer.renderInContraption(context);
}
@Override
public BlockRenderLayer getRenderLayer() {
return BlockRenderLayer.CUTOUT;
@ -94,8 +74,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
if (context.getFace().getAxis().isVertical())
facing = context.getPlacementHorizontalFacing().getOpposite();
else {
BlockState blockState = context.getWorld()
.getBlockState(context.getPos().offset(context.getFace().getOpposite()));
BlockState blockState =
context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite()));
if (AllBlocks.HARVESTER.typeOf(blockState))
facing = blockState.get(HORIZONTAL_FACING);
else
@ -105,118 +85,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
}
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion,
context.state.get(HORIZONTAL_FACING).getOpposite());
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.5);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world;
BlockState stateVisited = world.getBlockState(pos);
boolean notCropButCuttable = false;
if (world.isRemote)
return;
if (stateVisited.getBlock() == Blocks.SUGAR_CANE) {
notCropButCuttable = true;
pos = pos.up();
stateVisited = world.getBlockState(pos);
}
if (!isValidCrop(world, pos, stateVisited)) {
if (isValidOther(world, pos, stateVisited))
notCropButCuttable = true;
else
return;
}
List<ItemStack> drops = Block.getDrops(stateVisited, (ServerWorld) world, pos, null);
world.playEvent(2001, pos, Block.getStateId(stateVisited));
world.setBlockState(pos, cutCrop(world, pos, stateVisited));
boolean seedSubtracted = notCropButCuttable;
for (ItemStack stack : drops) {
if (!seedSubtracted && stack.isItemEqual(new ItemStack(stateVisited.getBlock()))) {
stack.shrink(1);
seedSubtracted = true;
}
ItemEntity itemEntity = new ItemEntity(world, pos.getX() + .5f, pos.getY() + .25f, pos.getZ() + .5f, stack);
itemEntity.setMotion(context.motion.add(0, 0.5f, 0).scale(world.rand.nextFloat() * .3f));
world.addEntity(itemEntity);
}
}
private boolean isValidCrop(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock) {
CropsBlock crop = (CropsBlock) state.getBlock();
if (!crop.isMaxAge(state))
return false;
return true;
}
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
if (((IntegerProperty) property).getAllowedValues().size() - 1 != state.get((IntegerProperty) property)
.intValue())
continue;
return true;
}
}
return false;
}
private boolean isValidOther(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock)
return false;
if (state.getBlock() instanceof SugarCaneBlock)
return true;
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
return false;
}
if (state.getBlock() instanceof IPlantable)
return true;
}
return false;
}
private BlockState cutCrop(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock) {
CropsBlock crop = (CropsBlock) state.getBlock();
return crop.withAge(0);
}
if (state.getBlock() == Blocks.SUGAR_CANE) {
return Blocks.AIR.getDefaultState();
}
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
return state.with((IntegerProperty) property, Integer.valueOf(0));
}
}
return Blocks.AIR.getDefaultState();
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -0,0 +1,148 @@
package com.simibubi.create.modules.contraptions.components.actors;
import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.CropsBlock;
import net.minecraft.block.SugarCaneBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IProperty;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.IPlantable;
public class HarvesterMovementBehaviour extends MovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion,
context.state.get(HORIZONTAL_FACING).getOpposite());
}
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return HarvesterTileEntityRenderer.renderInContraption(context);
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.5);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
World world = context.world;
BlockState stateVisited = world.getBlockState(pos);
boolean notCropButCuttable = false;
if (world.isRemote)
return;
if (stateVisited.getBlock() == Blocks.SUGAR_CANE) {
notCropButCuttable = true;
pos = pos.up();
stateVisited = world.getBlockState(pos);
}
if (!isValidCrop(world, pos, stateVisited)) {
if (isValidOther(world, pos, stateVisited))
notCropButCuttable = true;
else
return;
}
MutableBoolean seedSubtracted = new MutableBoolean(notCropButCuttable);
BlockState state = stateVisited;
BlockHelper.destroyBlock(world, pos, 1, stack -> {
if (!seedSubtracted.getValue() && stack.isItemEqual(new ItemStack(state.getBlock()))) {
stack.shrink(1);
seedSubtracted.setTrue();
}
dropItem(context, stack);
});
world.setBlockState(pos, cutCrop(world, pos, stateVisited));
}
private boolean isValidCrop(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock) {
CropsBlock crop = (CropsBlock) state.getBlock();
if (!crop.isMaxAge(state))
return false;
return true;
}
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
if (((IntegerProperty) property).getAllowedValues().size() - 1 != state.get((IntegerProperty) property)
.intValue())
continue;
return true;
}
}
return false;
}
private boolean isValidOther(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock)
return false;
if (state.getBlock() instanceof SugarCaneBlock)
return true;
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
return false;
}
if (state.getBlock() instanceof IPlantable)
return true;
}
return false;
}
private BlockState cutCrop(World world, BlockPos pos, BlockState state) {
if (state.getBlock() instanceof CropsBlock) {
CropsBlock crop = (CropsBlock) state.getBlock();
return crop.withAge(0);
}
if (state.getBlock() == Blocks.SUGAR_CANE) {
return Blocks.AIR.getDefaultState();
}
if (state.getCollisionShape(world, pos).isEmpty()) {
for (IProperty<?> property : state.getProperties()) {
if (!(property instanceof IntegerProperty))
continue;
if (!property.getName().equals(BlockStateProperties.AGE_0_1.getName()))
continue;
return state.with((IntegerProperty) property, Integer.valueOf(0));
}
}
return Blocks.AIR.getDefaultState();
}
}

View file

@ -7,7 +7,7 @@ import com.simibubi.create.foundation.block.SafeTileEntityRendererFast;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior.MovementContext;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BufferBuilder;
@ -19,16 +19,18 @@ import net.minecraft.world.World;
public class HarvesterTileEntityRenderer extends SafeTileEntityRendererFast<HarvesterTileEntity> {
@Override
public void renderFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) {
public void renderFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
BufferBuilder buffer) {
SuperByteBuffer superBuffer = renderHead(getWorld(), te.getPos(), te.getBlockState(), 0);
superBuffer.translate(x, y, z).renderInto(buffer);
}
public static SuperByteBuffer renderInContraption(MovementContext context) {
BlockState state = context.state;
float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, state.get(HORIZONTAL_FACING).getOpposite())
? context.getAnimationSpeed() * state.get(HORIZONTAL_FACING).getAxisDirection().getOffset()
Direction facing = state.get(HORIZONTAL_FACING);
int offset = facing.getAxisDirection().getOffset() * (facing.getAxis() == Axis.X ? 1 : -1);
float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite())
? context.getAnimationSpeed() * offset
: 0);
float time = AnimationTickHolder.getRenderTick() / 20;
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);

View file

@ -0,0 +1,39 @@
package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.item.BlockItemUseContext;
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;
public class PortableStorageInterfaceBlock extends ProperDirectionalBlock implements IPortableBlock {
public static MovementBehaviour MOVEMENT = new StorageInterfaceMovement();
public PortableStorageInterfaceBlock() {
super(Properties.from(Blocks.ANDESITE));
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
return getDefaultState().with(FACING, context.getNearestLookingDirection().getOpposite());
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return AllShapes.PORTABLE_STORAGE_INTERFACE.get(state.get(FACING));
}
@Override
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -0,0 +1,60 @@
package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.items.ItemHandlerHelper;
public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return SawBlock.isHorizontal(context.state);
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(SawBlock.FACING).getDirectionVec()).scale(.65f);
}
@Override
protected boolean canBreak(BlockState state) {
return super.canBreak(state) && state.isIn(BlockTags.LOGS);
}
@Override
protected void onBlockBroken(MovementContext context, BlockPos pos) {
Tree tree = TreeCutter.cutTree(context.world, pos);
if (tree != null) {
for (BlockPos log : tree.logs)
BlockHelper.destroyBlock(context.world, log, 1 / 2f, stack -> dropItemFromCutTree(context, log, stack));
for (BlockPos leaf : tree.leaves)
BlockHelper.destroyBlock(context.world, leaf, 1 / 8f,
stack -> dropItemFromCutTree(context, leaf, stack));
}
}
public void dropItemFromCutTree(MovementContext context, BlockPos pos, ItemStack stack) {
ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, stack, false);
if (remainder.isEmpty())
return;
World world = context.world;
Vec3d dropPos = VecHelper.getCenterOf(pos);
float distance = (float) dropPos.distanceTo(context.position);
ItemEntity entity = new ItemEntity(world, dropPos.x, dropPos.y, dropPos.z, remainder);
entity.setMotion(context.relativeMotion.scale(distance / 20f));
world.addEntity(entity);
}
}

View file

@ -0,0 +1,157 @@
package com.simibubi.create.modules.contraptions.components.actors;
import java.util.function.Predicate;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.behaviour.inventory.SingleTargetAutoExtractingBehaviour;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import com.simibubi.create.modules.logistics.block.transposer.TransposerBlock;
import com.simibubi.create.modules.logistics.block.transposer.TransposerTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTUtil;
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.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
public class StorageInterfaceMovement extends MovementBehaviour {
private static final String _exporting_ = "Exporting";
private static final String _delay_ = "Delay";
private static final String _workingPos_ = "WorkingPos";
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
Direction currentFacing = getCurrentFacing(context);
TransposerTileEntity transposer = getValidTransposer(context.world, pos, currentFacing.getAxis());
if (transposer == null)
return;
context.data.put(_workingPos_, NBTUtil.writeBlockPos(pos));
context.data.putBoolean(_exporting_,
TransposerBlock.getBlockFacing(transposer.getBlockState()) != currentFacing);
context.stall = true;
}
@Override
public void tick(MovementContext context) {
if (!context.data.contains(_workingPos_))
return;
if (context.world.isRemote)
return;
BlockPos pos = NBTUtil.readBlockPos(context.data.getCompound(_workingPos_));
TransposerTileEntity transposer = getValidTransposer(context.world, pos, getCurrentFacing(context).getAxis());
if (transposer == null) {
reset(context);
return;
}
int nextExtract = context.data.getInt(_delay_);
if (nextExtract > 0) {
nextExtract--;
context.data.putInt(_delay_, nextExtract);
return;
}
boolean extract = context.data.getBoolean(_exporting_);
boolean success = false;
IItemHandlerModifiable inv = context.contraption.inventory;
SingleTargetAutoExtractingBehaviour extracting =
TileEntityBehaviour.get(transposer, SingleTargetAutoExtractingBehaviour.TYPE);
FilteringBehaviour filtering = TileEntityBehaviour.get(transposer, FilteringBehaviour.TYPE);
if (extract) {
// Export from Contraption
Predicate<ItemStack> test = extracting.getFilterTest();
int exactAmount = extracting.getAmountToExtract();
ItemStack itemExtracted = ItemStack.EMPTY;
if (exactAmount != -1)
itemExtracted = ItemHelper.extract(inv, test, exactAmount, false);
else
itemExtracted = ItemHelper.extract(inv, test, transposer::amountToExtract, false);
if (!itemExtracted.isEmpty()) {
transposer.onExtract(itemExtracted);
success = exactAmount == -1;
}
} else {
// Import to Contraption
if (extracting != null) {
extracting.setSynchronized(false);
extracting.withAdditionalFilter(stack -> {
if (filtering.anyAmount())
return true;
return ItemHandlerHelper.insertItemStacked(inv, stack, true).isEmpty();
});
extracting.withAmountThreshold(stack -> {
ItemStack tester = stack.copy();
tester.setCount(64);
return 64 - ItemHandlerHelper.insertItemStacked(inv, stack, true).getCount();
});
extracting.setCallback(stack -> {
ItemHandlerHelper.insertItemStacked(inv, stack, false);
});
success = extracting.extract() && filtering.anyAmount();
extracting.setSynchronized(true);
transposer.applyFilteringCallbacks();
extracting.setCallback(transposer::onExtract);
}
}
if (!success) {
reset(context);
return;
}
context.data.putInt(_delay_, AllConfigs.SERVER.logistics.extractorDelay.get());
}
@Override
public void stopMoving(MovementContext context) {
reset(context);
}
public void reset(MovementContext context) {
context.data.remove(_workingPos_);
context.data.remove(_delay_);
context.data.remove(_exporting_);
context.stall = false;
}
private TransposerTileEntity getValidTransposer(World world, BlockPos pos, Axis validAxis) {
TileEntity te = world.getTileEntity(pos);
if (!(te instanceof TransposerTileEntity))
return null;
if (TransposerBlock.getBlockFacing(world.getBlockState(pos)).getAxis() != validAxis)
return null;
if (world.isBlockPowered(pos))
return null;
return (TransposerTileEntity) te;
}
private Direction getCurrentFacing(MovementContext context) {
Vec3d directionVec = new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING).getDirectionVec());
directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z);
return Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z);
}
}

View file

@ -4,20 +4,24 @@ import static net.minecraft.state.properties.BlockStateProperties.AXIS;
import static net.minecraft.state.properties.BlockStateProperties.FACING;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior.MovementContext;
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;
@ -27,14 +31,14 @@ import com.simibubi.create.modules.contraptions.components.contraptions.mounted.
import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonContraption;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.FallingBlock;
import net.minecraft.block.PistonBlock;
import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.SlimeBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties;
@ -44,21 +48,30 @@ import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class Contraption {
public Map<BlockPos, BlockInfo> blocks;
public Map<BlockPos, MountedStorage> storage;
public List<MutablePair<BlockInfo, MovementContext>> actors;
public CombinedInvWrapper inventory;
public AxisAlignedBB constructCollisionBox;
public boolean stalled;
protected Set<BlockPos> cachedColliders;
protected Direction cachedColliderDirection;
protected BlockPos anchor;
public Contraption() {
blocks = new HashMap<>();
storage = new HashMap<>();
actors = new ArrayList<>();
}
@ -137,15 +150,22 @@ public class Contraption {
return false;
for (int limit = 1000; limit > 0; limit--) {
if (frontier.isEmpty())
if (frontier.isEmpty()) {
onAssembled(world, pos);
return true;
}
if (!moveBlock(world, frontier.remove(0), direction, frontier, visited))
return false;
}
return false;
}
protected void onAssembled(World world, BlockPos pos) {
List<IItemHandlerModifiable> list =
storage.values().stream().map(MountedStorage::getItemHandler).collect(Collectors.toList());
inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
}
protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
return true;
}
@ -417,15 +437,16 @@ public class Contraption {
return true;
if (blockState.getBlock() instanceof ShulkerBoxBlock)
return false;
return PistonBlock.canPush(blockState, world, pos, direction, true, direction);
return blockState.getPushReaction() != PushReaction.BLOCK;
}
protected BlockInfo capture(World world, BlockPos pos) {
protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
BlockState blockstate = world.getBlockState(pos);
if (AllBlocks.SAW.typeOf(blockstate))
blockstate = blockstate.with(SawBlock.RUNNING, true);
CompoundNBT compoundnbt = getTileEntityNBT(world, pos);
return new BlockInfo(pos, blockstate, compoundnbt);
TileEntity tileentity = world.getTileEntity(pos);
return Pair.of(new BlockInfo(pos, blockstate, compoundnbt), tileentity);
}
public static CompoundNBT getTileEntityNBT(World world, BlockPos pos) {
@ -440,13 +461,20 @@ public class Contraption {
return compoundnbt;
}
public void add(BlockPos pos, BlockInfo block) {
public void add(BlockPos pos, Pair<BlockInfo, TileEntity> pair) {
BlockInfo captured = pair.getKey();
BlockPos localPos = pos.subtract(anchor);
BlockInfo blockInfo = new BlockInfo(localPos, block.state, block.nbt);
blocks.put(localPos, blockInfo);
if (block.state.getBlock() instanceof IHaveMovementBehavior)
getActors().add(MutablePair.of(blockInfo, null));
BlockInfo blockInfo = new BlockInfo(localPos, captured.state, captured.nbt);
if (blocks.put(localPos, blockInfo) != null)
return;
constructCollisionBox = constructCollisionBox.union(new AxisAlignedBB(localPos));
TileEntity te = pair.getValue();
if (te != null && MountedStorage.canUseAsStorage(te))
storage.put(localPos, new MountedStorage(te));
if (captured.state.getBlock() instanceof IPortableBlock)
getActors().add(MutablePair.of(blockInfo, null));
}
public static Contraption fromNBT(World world, CompoundNBT nbt) {
@ -463,6 +491,7 @@ public class Contraption {
}
public void readNBT(World world, CompoundNBT nbt) {
blocks.clear();
nbt.getList("Blocks", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
@ -471,23 +500,31 @@ public class Contraption {
blocks.put(info.pos, info);
});
actors.clear();
nbt.getList("Actors", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
MovementContext context = MovementContext.readNBT(world, comp);
context.contraption = this;
getActors().add(MutablePair.of(info, context));
});
storage.clear();
nbt.getList("Storage", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
storage.put(NBTUtil.readBlockPos(comp.getCompound("Pos")), new MountedStorage(comp.getCompound("Data")));
});
List<IItemHandlerModifiable> list =
storage.values().stream().map(MountedStorage::getItemHandler).collect(Collectors.toList());
inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
if (nbt.contains("BoundsFront"))
constructCollisionBox = readAABB(nbt.getList("BoundsFront", 5));
constructCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsFront", 5));
stalled = nbt.getBoolean("Stalled");
anchor = NBTUtil.readBlockPos(nbt.getCompound("Anchor"));
}
public AxisAlignedBB getCollisionBoxFront() {
return constructCollisionBox;
}
public CompoundNBT writeNBT() {
CompoundNBT nbt = new CompoundNBT();
@ -498,14 +535,14 @@ public class Contraption {
if (this instanceof BearingContraption)
nbt.putString("Type", "Bearing");
ListNBT blocks = new ListNBT();
ListNBT blocksNBT = new ListNBT();
for (BlockInfo block : this.blocks.values()) {
CompoundNBT c = new CompoundNBT();
c.put("Block", NBTUtil.writeBlockState(block.state));
c.put("Pos", NBTUtil.writeBlockPos(block.pos));
if (block.nbt != null)
c.put("Data", block.nbt);
blocks.add(c);
blocksNBT.add(c);
}
ListNBT actorsNBT = new ListNBT();
@ -515,41 +552,37 @@ public class Contraption {
actor.right.writeToNBT(compound);
actorsNBT.add(compound);
}
ListNBT storageNBT = new ListNBT();
for (BlockPos pos : storage.keySet()) {
CompoundNBT c = new CompoundNBT();
MountedStorage mountedStorage = storage.get(pos);
if (!mountedStorage.isWorking())
continue;
c.put("Pos", NBTUtil.writeBlockPos(pos));
c.put("Data", mountedStorage.serialize());
storageNBT.add(c);
}
nbt.put("Blocks", blocksNBT);
nbt.put("Actors", actorsNBT);
nbt.put("Storage", storageNBT);
nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
nbt.putBoolean("Stalled", stalled);
if (constructCollisionBox != null) {
ListNBT bb = writeAABB(constructCollisionBox);
ListNBT bb = NBTHelper.writeAABB(constructCollisionBox);
nbt.put("BoundsFront", bb);
}
nbt.put("Blocks", blocks);
nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
return nbt;
}
public ListNBT writeAABB(AxisAlignedBB bb) {
ListNBT bbtag = new ListNBT();
bbtag.add(new FloatNBT((float) bb.minX));
bbtag.add(new FloatNBT((float) bb.minY));
bbtag.add(new FloatNBT((float) bb.minZ));
bbtag.add(new FloatNBT((float) bb.maxX));
bbtag.add(new FloatNBT((float) bb.maxY));
bbtag.add(new FloatNBT((float) bb.maxZ));
return bbtag;
}
public AxisAlignedBB readAABB(ListNBT bbtag) {
if (bbtag == null || bbtag.isEmpty())
return null;
return new AxisAlignedBB(bbtag.getFloat(0), bbtag.getFloat(1), bbtag.getFloat(2), bbtag.getFloat(3),
bbtag.getFloat(4), bbtag.getFloat(5));
}
public static boolean isFrozen() {
return AllConfigs.SERVER.control.freezePistonConstructs.get();
}
public void disassemble(IWorld world, BlockPos offset, float yaw, float pitch) {
public void disassemble(World world, BlockPos offset, float yaw, float pitch) {
disassemble(world, offset, yaw, pitch, (pos, state) -> false);
}
@ -566,8 +599,9 @@ public class Contraption {
}
}
public void disassemble(IWorld world, BlockPos offset, float yaw, float pitch,
public void disassemble(World world, BlockPos offset, float yaw, float pitch,
BiPredicate<BlockPos, BlockState> customPlacement) {
stop(world);
for (BlockInfo block : blocks.values()) {
BlockPos targetPos = block.pos.add(offset);
BlockState state = block.state;
@ -589,7 +623,13 @@ public class Contraption {
block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt);
if (storage.containsKey(block.pos)) {
MountedStorage mountedStorage = storage.get(block.pos);
if (mountedStorage.isWorking())
mountedStorage.fill(tileEntity);
}
}
}
}
@ -597,11 +637,16 @@ public class Contraption {
for (MutablePair<BlockInfo, MovementContext> pair : actors) {
BlockState blockState = pair.left.state;
MovementContext context = new MovementContext(world, blockState);
((IHaveMovementBehavior) blockState.getBlock()).startMoving(context);
context.contraption = this;
getMovement(blockState).startMoving(context);
pair.setRight(context);
}
}
public AxisAlignedBB getCollisionBoxFront() {
return constructCollisionBox;
}
public List<MutablePair<BlockInfo, MovementContext>> getActors() {
return actors;
}
@ -610,4 +655,26 @@ public class Contraption {
return anchor;
}
public void stop(World world) {
foreachActor(world, (behaviour, ctx) -> {
behaviour.stopMoving(ctx);
ctx.position = null;
ctx.motion = Vec3d.ZERO;
ctx.relativeMotion = Vec3d.ZERO;
ctx.rotation = Vec3d.ZERO;
});
}
public void foreachActor(World world, BiConsumer<MovementBehaviour, MovementContext> callBack) {
for (MutablePair<BlockInfo, MovementContext> pair : actors)
callBack.accept(getMovement(pair.getLeft().state), pair.getRight());
}
protected static MovementBehaviour getMovement(BlockState state) {
Block block = state.getBlock();
if (!(block instanceof IPortableBlock))
return null;
return ((IPortableBlock) block).getMovementBehaviour();
}
}

View file

@ -3,16 +3,21 @@ package com.simibubi.create.modules.contraptions.components.contraptions;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllEntities;
import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior.MovementContext;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.IPacket;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@ -20,8 +25,11 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.fml.network.PacketDistributor;
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
@ -29,8 +37,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected float initialAngle;
protected BlockPos controllerPos;
protected IControlContraption controllerTE;
protected Vec3d motionBeforeStall;
public float movementSpeedModifier;
private static final DataParameter<Boolean> STALLED =
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
public float prevYaw;
public float prevPitch;
@ -46,6 +56,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public ContraptionEntity(EntityType<?> entityTypeIn, World worldIn) {
super(entityTypeIn, worldIn);
motionBeforeStall = Vec3d.ZERO;
}
protected ContraptionEntity(World world) {
@ -59,7 +70,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
this.prevYaw = initialAngle;
this.yaw = initialAngle;
this.targetYaw = initialAngle;
movementSpeedModifier = 1;
}
public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) {
@ -70,8 +80,13 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override
public void tick() {
if (contraption == null) {
remove();
return;
}
attachToController();
Entity e = getRidingEntity();
if (e != null) {
Vec3d movementVector = e.getMotion();
@ -97,7 +112,19 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
pitch = angleLerp(speed, pitch, targetPitch);
}
boolean wasStalled = isStalled();
tickActors(movementVector);
if (isStalled()) {
if (!wasStalled)
motionBeforeStall = e.getMotion();
e.setMotion(0, 0, 0);
}
if (wasStalled && !isStalled()) {
e.setMotion(motionBeforeStall);
motionBeforeStall = Vec3d.ZERO;
}
super.tick();
return;
}
@ -111,47 +138,62 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
}
public void tickActors(Vec3d movementVector) {
movementSpeedModifier = 1;
float anglePitch = getPitch(1);
float angleYaw = getYaw(1);
float angleRoll = getRoll(1);
Vec3d rotationVec = new Vec3d(angleRoll, angleYaw, anglePitch);
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
boolean stalledPreviously = contraption.stalled;
if (!world.isRemote)
contraption.stalled = false;
for (MutablePair<BlockInfo, MovementContext> pair : contraption.actors) {
MovementContext context = pair.right;
BlockInfo blockInfo = pair.left;
IHaveMovementBehavior actor = (IHaveMovementBehavior) blockInfo.state.getBlock();
MovementBehaviour actor = Contraption.getMovement(blockInfo.state);
Vec3d actorPosition = new Vec3d(blockInfo.pos);
actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch);
actorPosition = actorPosition.add(rotationOffset).add(posX, posY, posZ);
Vec3d previousPosition = context.position;
boolean newPosVisited = context.position == null;
BlockPos gridPosition = new BlockPos(actorPosition);
boolean newPosVisited = true;
if (previousPosition != null) {
context.motion = actorPosition.subtract(previousPosition);
Vec3d relativeMotion = context.motion;
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition);
if (!stalledPreviously) {
Vec3d previousPosition = context.position;
if (previousPosition != null) {
context.motion = actorPosition.subtract(previousPosition);
Vec3d relativeMotion = context.motion;
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition);
}
}
context.rotation = rotationVec;
context.position = actorPosition;
if (actor.isActive(context)) {
if (newPosVisited)
if (newPosVisited && !context.stall)
actor.visitNewPosition(context, gridPosition);
actor.tick(context);
contraption.stalled |= context.stall;
}
if (movementSpeedModifier > context.movementSpeedModifier)
movementSpeedModifier = context.movementSpeedModifier;
}
if (!world.isRemote) {
if (!stalledPreviously && contraption.stalled) {
if (controllerTE != null)
controllerTE.onStall();
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this),
new ContraptionStallPacket(getEntityId(), posX, posY, posZ, yaw, pitch, roll));
}
dataManager.set(STALLED, contraption.stalled);
} else {
contraption.stalled = isStalled();
}
}
@ -171,6 +213,11 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
getShortestAngleDiff(this.pitch, pitch));
}
@Override
public void notifyDataManagerChange(DataParameter<?> key) {
super.notifyDataManagerChange(key);
}
public void rotate(double roll, double yaw, double pitch) {
// Collision and stuff
@ -242,12 +289,16 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override
protected void registerData() {
this.dataManager.register(STALLED, false);
}
@Override
protected void readAdditional(CompoundNBT compound) {
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
initialAngle = compound.getFloat("InitialAngle");
ListNBT vecNBT = compound.getList("CachedMotion", 6);
if (!vecNBT.isEmpty())
motionBeforeStall = new Vec3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2));
if (compound.contains("Controller"))
controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller"));
prevYaw = initialAngle;
@ -256,12 +307,14 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
}
public void attachToController() {
if (controllerPos != null && controllerTE == null) {
if (controllerPos != null && (controllerTE == null || !controllerTE.isValid())) {
if (!world.isBlockPresent(controllerPos))
return;
TileEntity te = world.getTileEntity(controllerPos);
if (te == null || !(te instanceof IControlContraption))
if (te == null || !(te instanceof IControlContraption)) {
remove();
return;
}
IControlContraption controllerTE = (IControlContraption) te;
this.controllerTE = controllerTE;
controllerTE.attach(this);
@ -272,6 +325,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected void writeAdditional(CompoundNBT compound) {
compound.put("Contraption", getContraption().writeNBT());
compound.putFloat("InitialAngle", initialAngle);
compound.put("CachedMotion", newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
if (controllerPos != null)
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
}
@ -303,4 +357,24 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return contraption;
}
public boolean isStalled() {
return dataManager.get(STALLED);
}
@OnlyIn(Dist.CLIENT)
static void handleStallPacket(ContraptionStallPacket packet) {
Entity entity = Minecraft.getInstance().world.getEntityByID(packet.entityID);
if (!(entity instanceof ContraptionEntity))
return;
ContraptionEntity ce = (ContraptionEntity) entity;
if (ce.getRidingEntity() == null) {
ce.posX = packet.x;
ce.posY = packet.y;
ce.posZ = packet.z;
}
ce.yaw = packet.yaw;
ce.pitch = packet.pitch;
ce.roll = packet.roll;
}
}

View file

@ -10,7 +10,6 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.utility.PlacementSimulationWorld;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior.MovementContext;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer;
@ -18,7 +17,8 @@ import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.client.model.data.EmptyModelData;
@ -31,7 +31,7 @@ public class ContraptionRenderer {
public static void render(World world, Contraption c, Consumer<SuperByteBuffer> transform, BufferBuilder buffer) {
SuperByteBuffer contraptionBuffer = CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c));
transform.accept(contraptionBuffer);
contraptionBuffer.light((lx, ly, lz) -> world.getCombinedLight(new BlockPos(lx, ly, lz), 0)).renderInto(buffer);
contraptionBuffer.light((lx, ly, lz) -> getLight(world, lx, ly, lz)).renderInto(buffer);
renderActors(world, c, transform, buffer);
}
@ -69,8 +69,7 @@ public class ContraptionRenderer {
context.world = world;
BlockInfo blockInfo = actor.getLeft();
IHaveMovementBehavior block = (IHaveMovementBehavior) blockInfo.state.getBlock();
SuperByteBuffer render = block.renderInContraption(context);
SuperByteBuffer render = Contraption.getMovement(blockInfo.state).renderInContraption(context);
if (render == null)
continue;
@ -80,8 +79,24 @@ public class ContraptionRenderer {
render.translate(posX, posY, posZ);
transform.accept(render);
render.light((lx, ly, lz) -> world.getCombinedLight(new BlockPos(lx, ly, lz), 0)).renderInto(buffer);
render.light((lx, ly, lz) -> getLight(world, lx, ly, lz)).renderInto(buffer);
}
}
public static int getLight(World world, float lx, float ly, float lz) {
MutableBlockPos pos = new MutableBlockPos();
float sky = 0, block = 0;
float offset = 1 / 8f;
for (float zOffset = offset; zOffset >= -offset; zOffset -= 2 * offset)
for (float yOffset = offset; yOffset >= -offset; yOffset -= 2 * offset)
for (float xOffset = offset; xOffset >= -offset; xOffset -= 2 * offset) {
pos.setPos(lx + xOffset, ly + yOffset, lz + zOffset);
sky += world.getLightFor(LightType.SKY, pos) / 8f;
block += world.getLightFor(LightType.BLOCK, pos) / 8f;
}
return ((int) sky) << 20 | ((int) block) << 4;
}
}

View file

@ -0,0 +1,60 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import java.util.function.Supplier;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.network.NetworkEvent.Context;
public class ContraptionStallPacket extends SimplePacketBase {
int entityID;
float x;
float y;
float z;
float yaw;
float pitch;
float roll;
public ContraptionStallPacket(int entityID, double posX, double posY, double posZ, float yaw, float pitch, float roll) {
this.entityID = entityID;
this.x = (float) posX;
this.y = (float) posY;
this.z = (float) posZ;
this.yaw = yaw;
this.pitch = pitch;
this.roll = roll;
}
public ContraptionStallPacket(PacketBuffer buffer) {
entityID = buffer.readInt();
x = buffer.readFloat();
y = buffer.readFloat();
z = buffer.readFloat();
yaw = buffer.readFloat();
pitch = buffer.readFloat();
roll = buffer.readFloat();
}
@Override
public void write(PacketBuffer buffer) {
buffer.writeInt(entityID);
writeAll(buffer, x, y, z, yaw, pitch, roll);
}
@Override
public void handle(Supplier<Context> context) {
context.get().enqueueWork(
() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> ContraptionEntity.handleStallPacket(this)));
context.get().setPacketHandled(true);
}
private void writeAll(PacketBuffer buffer, float... floats) {
for (float f : floats)
buffer.writeFloat(f);
}
}

View file

@ -4,4 +4,9 @@ public interface IControlContraption {
public void attach(ContraptionEntity contraption);
default void onStall() {
}
public boolean isValid();
}

View file

@ -1,99 +0,0 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
public interface IHaveMovementBehavior {
public class MovementContext {
public Vec3d position;
public Vec3d motion;
public Vec3d relativeMotion;
public Vec3d rotation;
public World world;
public BlockState state;
public float movementSpeedModifier;
public CompoundNBT data;
public MovementContext(World world, BlockState state) {
this.world = world;
this.state = state;
motion = Vec3d.ZERO;
relativeMotion = Vec3d.ZERO;
rotation = Vec3d.ZERO;
position = null;
data = new CompoundNBT();
movementSpeedModifier = 1;
}
public float getAnimationSpeed() {
int modifier = 1000;
double length = -motion.length();
if (Math.abs(length) < 1 / 512f)
return 0;
return (((int) (length * modifier + 100 * Math.signum(length))) / 100) * 100;
}
public static MovementContext readNBT(World world, CompoundNBT nbt) {
BlockState state = NBTUtil.readBlockState(nbt.getCompound("State"));
MovementContext context = new MovementContext(world, state);
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
context.rotation = VecHelper.readNBT(nbt.getList("Rotation", NBT.TAG_DOUBLE));
if (nbt.contains("Position"))
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
context.movementSpeedModifier = nbt.getFloat("SpeedModifier");
context.data = nbt.getCompound("Data");
return context;
}
public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("State", NBTUtil.writeBlockState(state));
nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
nbt.put("Rotation", VecHelper.writeNBT(rotation));
if (position != null)
nbt.put("Position", VecHelper.writeNBT(position));
nbt.putFloat("SpeedModifier", movementSpeedModifier);
nbt.put("Data", data);
return nbt;
}
}
default boolean isActive(MovementContext context) {
return true;
}
default void tick(MovementContext context) {
}
default void startMoving(MovementContext context) {
}
default void visitNewPosition(MovementContext context, BlockPos pos) {
}
default Vec3d getActiveAreaOffset(MovementContext context) {
return Vec3d.ZERO;
}
@OnlyIn(value = Dist.CLIENT)
default SuperByteBuffer renderInContraption(MovementContext context) {
return null;
}
}

View file

@ -0,0 +1,7 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
public interface IPortableBlock {
public MovementBehaviour getMovementBehaviour();
}

View file

@ -0,0 +1,79 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.AllTileEntities;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;
public class MountedStorage {
private static final ItemStackHandler dummyHandler = new ItemStackHandler();
ItemStackHandler handler;
boolean working;
public MountedStorage(TileEntity te) {
handler = dummyHandler;
if (te != null) {
IItemHandler teHandler =
te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(dummyHandler);
if (teHandler != dummyHandler && teHandler instanceof IItemHandlerModifiable) {
IItemHandlerModifiable inv = (IItemHandlerModifiable) teHandler;
handler = new ItemStackHandler(teHandler.getSlots());
for (int slot = 0; slot < handler.getSlots(); slot++) {
handler.setStackInSlot(slot, inv.getStackInSlot(slot));
inv.setStackInSlot(slot, ItemStack.EMPTY);
}
}
}
working = te != null && handler != dummyHandler;
}
public MountedStorage(CompoundNBT nbt) {
handler = new ItemStackHandler();
working = nbt != null;
if (working)
handler.deserializeNBT(nbt);
}
public void fill(TileEntity te) {
IItemHandler teHandler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(dummyHandler);
if (teHandler != dummyHandler && teHandler instanceof IItemHandlerModifiable) {
IItemHandlerModifiable inv = (IItemHandlerModifiable) teHandler;
for (int slot = 0; slot < Math.min(inv.getSlots(), handler.getSlots()); slot++)
inv.setStackInSlot(slot, handler.getStackInSlot(slot));
}
}
public IItemHandlerModifiable getItemHandler() {
return handler;
}
public CompoundNBT serialize() {
return working ? handler.serializeNBT() : null;
}
public boolean isWorking() {
return working;
}
public static boolean canUseAsStorage(TileEntity te) {
if (te == null)
return false;
TileEntityType<?> type = te.getType();
if (type == TileEntityType.CHEST || type == TileEntityType.SHULKER_BOX || type == TileEntityType.BARREL)
return true;
if (type == AllTileEntities.FLEXCRATE.type)
return true;
return false;
}
}

View file

@ -0,0 +1,52 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.ItemHandlerHelper;
public abstract class MovementBehaviour {
public boolean isActive(MovementContext context) {
return true;
}
public void tick(MovementContext context) {
}
public void startMoving(MovementContext context) {
}
public void visitNewPosition(MovementContext context, BlockPos pos) {
}
public Vec3d getActiveAreaOffset(MovementContext context) {
return Vec3d.ZERO;
}
public void dropItem(MovementContext context, ItemStack stack) {
ItemStack remainder = ItemHandlerHelper.insertItem(context.contraption.inventory, stack, false);
if (remainder.isEmpty())
return;
Vec3d vec = context.position;
ItemEntity itemEntity = new ItemEntity(context.world, vec.x, vec.y, vec.z, remainder);
itemEntity.setMotion(context.motion.add(0, 0.5f, 0).scale(context.world.rand.nextFloat() * .3f));
context.world.addEntity(itemEntity);
}
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return null;
}
public void stopMoving(MovementContext context) {
}
}

View file

@ -0,0 +1,72 @@
package com.simibubi.create.modules.contraptions.components.contraptions;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT;
public class MovementContext {
public Vec3d position;
public Vec3d motion;
public Vec3d relativeMotion;
public Vec3d rotation;
public World world;
public BlockState state;
public boolean stall;
public CompoundNBT data;
public Contraption contraption;
public MovementContext(World world, BlockState state) {
this.world = world;
this.state = state;
motion = Vec3d.ZERO;
relativeMotion = Vec3d.ZERO;
rotation = Vec3d.ZERO;
position = null;
data = new CompoundNBT();
stall = false;
}
public float getAnimationSpeed() {
int modifier = 1000;
double length = -motion.length();
if (world.isRemote && contraption.stalled)
return 700;
if (Math.abs(length) < 1 / 512f)
return 0;
return (((int) (length * modifier + 100 * Math.signum(length))) / 100) * 100;
}
public static MovementContext readNBT(World world, CompoundNBT nbt) {
BlockState state = NBTUtil.readBlockState(nbt.getCompound("State"));
MovementContext context = new MovementContext(world, state);
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
context.rotation = VecHelper.readNBT(nbt.getList("Rotation", NBT.TAG_DOUBLE));
if (nbt.contains("Position"))
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
context.stall = nbt.getBoolean("Stall");
context.data = nbt.getCompound("Data");
return context;
}
public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("State", NBTUtil.writeBlockState(state));
nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
nbt.put("Rotation", VecHelper.writeNBT(rotation));
if (position != null)
nbt.put("Position", VecHelper.writeNBT(position));
nbt.putBoolean("Stall", stall);
nbt.put("Data", data);
return nbt;
}
}

View file

@ -1,9 +1,12 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlockTags;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@ -26,10 +29,10 @@ public class BearingContraption extends Contraption {
}
@Override
public void add(BlockPos pos, BlockInfo block) {
if (AllBlockTags.WINDMILL_SAILS.matches(block.state))
public void add(BlockPos pos, Pair<BlockInfo, TileEntity> capture) {
if (AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state))
sailBlocks++;
super.add(pos, block);
super.add(pos, capture);
}
@Override

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.AllTileEntities;
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;
@ -9,6 +10,8 @@ import com.simibubi.create.modules.contraptions.components.contraptions.IControl
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;
@ -30,7 +33,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public float getAddedStressCapacity() {
return isWindmill ? super.getAddedStressCapacity() : 0;
}
@Override
public float getStressApplied() {
return isWindmill ? 0 : super.getStressApplied();
@ -90,6 +93,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
}
public float getInterpolatedAngle(float partialTicks) {
if (movedContraption != null && movedContraption.isStalled())
partialTicks = 0;
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
}
@ -100,7 +105,10 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
}
public float getAngularSpeed() {
return getSpeed() * 3 / 10f;
float speed = getSpeed() * 3 / 10f;
if (world.isRemote)
speed *= ServerSpeedProvider.get();
return speed;
}
public void assembleConstruct() {
@ -148,6 +156,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
if (movedContraption != null)
movedContraption.getContraption().stop(world);
boolean canDisassemble = Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45;
if (speed == 0 && (canDisassemble || movedContraption == null
|| movedContraption.getContraption().blocks.isEmpty())) {
@ -165,17 +175,21 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (!running)
return;
float angularSpeed = getAngularSpeed();
float newAngle = angle + angularSpeed;
angle = (float) (newAngle % 360);
if (!(movedContraption != null && movedContraption.isStalled())) {
float angularSpeed = getAngularSpeed();
float newAngle = angle + angularSpeed;
angle = (float) (newAngle % 360);
}
applyRotation();
}
private void applyRotation() {
if (movedContraption != null) {
Direction direction = getBlockState().get(BlockStateProperties.FACING);
Axis axis = getBlockState().get(BlockStateProperties.FACING).getAxis();
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
Vec3d vec = new Vec3d(1, 1, 1).scale(angle).mul(new Vec3d(direction.getDirectionVec()));
movedContraption.rotateTo(vec.x, vec.y, -vec.z);
movedContraption.rotateTo(vec.x, vec.y, vec.z);
}
}
@ -183,6 +197,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public void attach(ContraptionEntity contraption) {
if (contraption.getContraption() instanceof BearingContraption) {
this.movedContraption = contraption;
markDirty();
BlockPos anchor = pos.offset(getBlockState().get(BlockStateProperties.FACING));
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
if (!world.isRemote)
@ -190,4 +205,15 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
}
}
@Override
public void onStall() {
if (!world.isRemote)
sendData();
}
@Override
public boolean isValid() {
return !isRemoved();
}
}

View file

@ -24,7 +24,7 @@ public class MechanicalBearingTileEntityRenderer extends KineticTileEntityRender
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);
float interpolatedAngle = bearingTe.getInterpolatedAngle(partialTicks - 1);
kineticRotationTransform(superBuffer, bearingTe, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI),
getWorld());
superBuffer.translate(x, y, z).renderInto(buffer);

View file

@ -73,6 +73,8 @@ public class CartAssemblerBlock extends AbstractRailBlock {
return;
Contraption contraption = MountedContraption.assembleMinecart(world, pos, cart);
if (contraption == null)
return;
ContraptionEntity entity = new ContraptionEntity(world, contraption,
ContraptionEntity.yawFromMotion(cart.getMotion()));
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());

View file

@ -4,6 +4,8 @@ import static com.simibubi.create.modules.contraptions.components.contraptions.m
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
@ -11,6 +13,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.RailShape;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
@ -36,9 +39,9 @@ public class MountedContraption extends Contraption {
return null;
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z;
contraption.add(pos, new BlockInfo(pos,
contraption.add(pos, Pair.of(new BlockInfo(pos,
AllBlocks.MINECART_ANCHOR.block.getDefaultState().with(BlockStateProperties.HORIZONTAL_AXIS, axis),
null));
null), null));
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
contraption.initActors(world);
@ -59,11 +62,13 @@ public class MountedContraption extends Contraption {
}
@Override
protected BlockInfo capture(World world, BlockPos pos) {
BlockInfo capture = super.capture(world, pos);
protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
Pair<BlockInfo, TileEntity> pair = super.capture(world, pos);
BlockInfo capture = pair.getKey();
if (AllBlocks.CART_ASSEMBLER.typeOf(capture.state))
return new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null);
return capture;
return Pair.of(new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null),
pair.getValue());
return pair;
}
@Override
@ -72,7 +77,7 @@ public class MountedContraption extends Contraption {
}
@Override
public void disassemble(IWorld world, BlockPos offset, float yaw, float pitch) {
public void disassemble(World world, BlockPos offset, float yaw, float pitch) {
super.disassemble(world, offset, yaw, pitch, (pos, state) -> AllBlocks.MINECART_ANCHOR.typeOf(state));
}

View file

@ -2,6 +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;
@ -105,6 +106,9 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
public void tick() {
super.tick();
if (movedContraption != null && movedContraption.isStalled())
return;
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;
if (running) {
@ -122,6 +126,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
return;
float movementSpeed = getMovementSpeed();
if (world.isRemote)
movementSpeed *= ServerSpeedProvider.get();
float newOffset = offset + movementSpeed;
if (movedContraption == null)
@ -146,7 +152,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
if (movedContraption != null) {
Vec3d constructOffset = getConstructOffset(0.5f);
Vec3d vec = constructOffset.add(new Vec3d(movedContraption.getContraption().getAnchor()));
movedContraption.setPosition(vec.x, vec.y, vec.z);
movedContraption.move(vec.x - movedContraption.posX, vec.y - movedContraption.posY,
vec.z - movedContraption.posZ);
}
}
@ -234,14 +241,14 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
public float getMovementSpeed() {
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
int movementModifier = pistonDirection.getAxisDirection().getOffset()
* (pistonDirection.getAxis() == Axis.Z ? -1 : 1);
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);
float interpolatedOffset =
MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, extensionLength);
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset);
}
@ -254,4 +261,15 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
}
}
@Override
public void onStall() {
if (!world.isRemote)
sendData();
}
@Override
public boolean isValid() {
return !isRemoved();
}
}

View file

@ -8,8 +8,11 @@ import static net.minecraft.state.properties.BlockStateProperties.FACING;
import java.util.ArrayList;
import java.util.List;
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.Contraption;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
@ -132,13 +135,13 @@ public class PistonContraption extends Contraption {
return true;
}
public void add(BlockPos pos, BlockInfo block) {
// super.add(pos, block);
super.add(pos.offset(orientation, -initialExtensionProgress), block);
@Override
public void add(BlockPos pos, Pair<BlockInfo, TileEntity> capture) {
super.add(pos.offset(orientation, -initialExtensionProgress), capture);
}
@Override
public void disassemble(IWorld world, BlockPos offset, float yaw, float pitch) {
public void disassemble(World world, BlockPos offset, float yaw, float pitch) {
super.disassemble(world, offset, yaw, pitch, (pos, state) -> {
BlockPos pistonPos = anchor.offset(orientation, -initialExtensionProgress - 1);
BlockState pistonState = world.getBlockState(pistonPos);
@ -175,7 +178,7 @@ public class PistonContraption extends Contraption {
initialExtensionProgress = nbt.getInt("InitialLength");
orientation = Direction.byIndex(nbt.getInt("Orientation"));
if (nbt.contains("BoundsBack"))
pistonCollisionBox = readAABB(nbt.getList("BoundsBack", 5));
pistonCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsBack", 5));
}
@Override
@ -183,7 +186,7 @@ public class PistonContraption extends Contraption {
CompoundNBT nbt = super.writeNBT();
if (pistonCollisionBox != null) {
ListNBT bb = writeAABB(pistonCollisionBox);
ListNBT bb = NBTHelper.writeAABB(pistonCollisionBox);
nbt.put("BoundsBack", bb);
}
nbt.putInt("InitialLength", initialExtensionProgress);

View file

@ -57,9 +57,8 @@ public class NozzleTileEntity extends SmartTileEntity {
@Override
public void initialize() {
super.initialize();
fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING).getOpposite());
lazyTick();
super.initialize();
}
@Override

View file

@ -47,11 +47,6 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity {
return generatedCapacity;
}
@Override
public void initialize() {
super.initialize();
}
@Override
public AxisAlignedBB getRenderBoundingBox() {
return super.getRenderBoundingBox().grow(2);

View file

@ -39,12 +39,6 @@ public class EngineTileEntity extends SmartTileEntity {
return super.getRenderBoundingBox().grow(1.5f);
}
@Override
public void initialize() {
super.initialize();
lazyTick();
}
@Override
public void lazyTick() {
super.lazyTick();

View file

@ -3,7 +3,9 @@ package com.simibubi.create.modules.contraptions.components.saw;
import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.contraptions.base.DirectionalAxisKineticBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.components.actors.SawMovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -29,11 +31,11 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
public class SawBlock extends DirectionalAxisKineticBlock
implements IWithTileEntity<SawTileEntity>, IHaveMovementBehavior {
public class SawBlock extends DirectionalAxisKineticBlock implements IWithTileEntity<SawTileEntity>, IPortableBlock {
public static final BooleanProperty RUNNING = BooleanProperty.create("running");
public static DamageSource damageSourceSaw = new DamageSource("create.saw").setDamageBypassesArmor();
public static MovementBehaviour MOVEMENT = new SawMovementBehaviour();
public SawBlock() {
super(Properties.from(Blocks.ANDESITE));
@ -103,7 +105,7 @@ public class SawBlock extends DirectionalAxisKineticBlock
return PushReaction.PUSH_ONLY;
}
public boolean isHorizontal(BlockState state) {
public static boolean isHorizontal(BlockState state) {
return state.get(FACING).getAxis().isHorizontal();
}
@ -133,7 +135,11 @@ public class SawBlock extends DirectionalAxisKineticBlock
worldIn.removeTileEntity(pos);
}
}
@Override
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -4,8 +4,8 @@ import java.util.Random;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -16,15 +16,14 @@ import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.TickPriority;
import net.minecraft.world.World;
public class ContactBlock extends ProperDirectionalBlock implements IHaveMovementBehavior {
public class ContactBlock extends ProperDirectionalBlock implements IPortableBlock {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static MovementBehaviour MOVEMENT = new ContactMovementBehaviour();
public ContactBlock() {
super(Properties.from(Blocks.ANDESITE));
@ -102,33 +101,8 @@ public class ContactBlock extends ProperDirectionalBlock implements IHaveMovemen
}
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
BlockState block = context.state;
World world = context.world;
if (world.isRemote)
return;
BlockState visitedState = world.getBlockState(pos);
if (!AllBlocks.CONTACT.typeOf(visitedState))
return;
Vec3d contact = new Vec3d(block.get(FACING).getDirectionVec());
contact = VecHelper.rotate(contact, context.rotation.x, context.rotation.y, context.rotation.z);
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
if (!hasValidContact(world, pos.offset(direction.getOpposite()), direction))
return;
int ticksToStayActive = 4;
world.setBlockState(pos, visitedState.with(POWERED, true));
world.getPendingBlockTicks().scheduleTick(pos, this, ticksToStayActive, TickPriority.NORMAL);
return;
public MovementBehaviour getMovementBehaviour() {
return MOVEMENT;
}
}

View file

@ -0,0 +1,60 @@
package com.simibubi.create.modules.contraptions.redstone;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.TickPriority;
import net.minecraft.world.World;
public class ContactMovementBehaviour extends MovementBehaviour {
@Override
public Vec3d getActiveAreaOffset(MovementContext context) {
return new Vec3d(context.state.get(ContactBlock.FACING).getDirectionVec()).scale(.65f);
}
@Override
public void visitNewPosition(MovementContext context, BlockPos pos) {
BlockState block = context.state;
World world = context.world;
if (world.isRemote)
return;
deactivateLastVisitedContact(context);
BlockState visitedState = world.getBlockState(pos);
if (!AllBlocks.CONTACT.typeOf(visitedState))
return;
Vec3d contact = new Vec3d(block.get(ContactBlock.FACING).getDirectionVec());
contact = VecHelper.rotate(contact, context.rotation.x, context.rotation.y, context.rotation.z);
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
if (!ContactBlock.hasValidContact(world, pos.offset(direction.getOpposite()), direction))
return;
world.setBlockState(pos, visitedState.with(ContactBlock.POWERED, true));
context.data.put("lastContact", NBTUtil.writeBlockPos(pos));
return;
}
@Override
public void stopMoving(MovementContext context) {
deactivateLastVisitedContact(context);
}
public void deactivateLastVisitedContact(MovementContext context) {
if (context.data.contains("lastContact")) {
BlockPos last = NBTUtil.readBlockPos(context.data.getCompound("lastContact"));
context.world.getPendingBlockTicks().scheduleTick(last, AllBlocks.CONTACT.get(), 1, TickPriority.NORMAL);
context.data.remove("lastContact");
}
}
}

View file

@ -8,6 +8,7 @@ import java.util.List;
import java.util.function.Function;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
@ -62,6 +63,7 @@ public class BeltInventory {
float beltSpeed = belt.getDirectionAwareBeltMovementSpeed();
Direction movementFacing = belt.getMovementFacing();
float spacing = 1;
boolean onClient = belt.getWorld().isRemote;
Items: while (iterator.hasNext()) {
stackInFront = current;
@ -76,9 +78,10 @@ public class BeltInventory {
}
float movement = beltSpeed;
if (onClient)
movement *= ServerSpeedProvider.get();
// Don't move if locked
boolean onClient = belt.getWorld().isRemote;
if (onClient && current.locked)
continue;

View file

@ -8,7 +8,6 @@ import com.simibubi.create.modules.contraptions.GogglesItem;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper;

View file

@ -1,7 +1,6 @@
package com.simibubi.create.modules.curiosities.tools;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers;
import com.simibubi.create.foundation.advancement.SandpaperUseTrigger;
import com.simibubi.create.foundation.block.render.CustomRenderedItemModel;
import com.simibubi.create.foundation.item.IHaveCustomItemModel;
import com.simibubi.create.foundation.utility.VecHelper;

View file

@ -37,19 +37,23 @@ public class TransposerTileEntity extends ExtractorTileEntity {
inserting = new InsertingBehaviour(this,
Attachments.toward(() -> AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite()));
behaviours.add(inserting);
applyFilteringCallbacks();
}
public void applyFilteringCallbacks() {
extracting.withAmountThreshold(this::amountToExtract).withAdditionalFilter(this::shouldExtract);
}
public void filterChanged(ItemStack stack) {
}
protected int amountToExtract(ItemStack stack) {
public int amountToExtract(ItemStack stack) {
ItemStack tester = stack.copy();
tester.setCount(64);
return 64 - inserting.insert(tester, true).getCount();
}
protected boolean shouldExtract(ItemStack stack) {
public boolean shouldExtract(ItemStack stack) {
if (isTargetingBelt()) {
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite();
BlockPos targetPos = pos.offset(facing);
@ -79,7 +83,7 @@ public class TransposerTileEntity extends ExtractorTileEntity {
}
@Override
protected void onExtract(ItemStack stack) {
public void onExtract(ItemStack stack) {
if (isTargetingBelt()) {
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite();
BlockPos targetPos = pos.offset(facing);

View file

@ -0,0 +1,36 @@
package com.simibubi.create.modules.schematics.block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class LaunchedBlock {
private final SchematicannonTileEntity te;
public int totalTicks;
public int ticksRemaining;
public BlockPos target;
public BlockState state;
public LaunchedBlock(SchematicannonTileEntity schematicannonTileEntity, BlockPos target, BlockState state) {
te = schematicannonTileEntity;
this.target = target;
this.state = state;
totalTicks = (int) (Math.max(10, MathHelper.sqrt(MathHelper.sqrt(target.distanceSq(te.getPos()))) * 4f));
ticksRemaining = totalTicks;
}
public LaunchedBlock(SchematicannonTileEntity schematicannonTileEntity, BlockPos target, BlockState state,
int ticksLeft, int total) {
te = schematicannonTileEntity;
this.target = target;
this.state = state;
this.totalTicks = total;
this.ticksRemaining = ticksLeft;
}
public void update() {
if (ticksRemaining > 0)
ticksRemaining--;
}
}

View file

@ -11,14 +11,12 @@ import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
@ -39,13 +37,6 @@ public class SchematicannonBlock extends Block {
return new SchematicannonTileEntity();
}
@Override
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn,
BlockPos currentPos, BlockPos facingPos) {
((SchematicannonTileEntity) worldIn.getTileEntity(currentPos)).findInventories();
return stateIn;
}
@Override
public boolean isSolid(BlockState state) {
return false;

View file

@ -0,0 +1,44 @@
package com.simibubi.create.modules.schematics.block;
import com.simibubi.create.AllItems;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraftforge.items.ItemStackHandler;
public class SchematicannonInventory extends ItemStackHandler {
/**
*
*/
private final SchematicannonTileEntity te;
public SchematicannonInventory(SchematicannonTileEntity schematicannonTileEntity) {
super(5);
te = schematicannonTileEntity;
}
@Override
protected void onContentsChanged(int slot) {
super.onContentsChanged(slot);
te.markDirty();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
switch (slot) {
case 0: // Blueprint Slot
return AllItems.BLUEPRINT.typeOf(stack);
case 1: // Blueprint output
return false;
case 2: // Book input
return stack.isItemEqual(new ItemStack(Items.BOOK))
|| stack.isItemEqual(new ItemStack(Items.WRITTEN_BOOK));
case 3: // Material List output
return false;
case 4: // Gunpowder
return stack.isItemEqual(new ItemStack(Items.GUNPOWDER));
default:
return super.isItemValid(slot, stack);
}
}
}

View file

@ -56,7 +56,7 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
}
if (!tileEntityIn.flyingBlocks.isEmpty()) {
for (SchematicannonTileEntity.LaunchedBlock block : tileEntityIn.flyingBlocks) {
for (LaunchedBlock block : tileEntityIn.flyingBlocks) {
if (block.ticksRemaining == 0)
continue;

View file

@ -9,7 +9,8 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.config.CSchematics;
import com.simibubi.create.foundation.block.SyncedTileEntity;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.type.Cuboid;
import com.simibubi.create.modules.schematics.MaterialChecklist;
import com.simibubi.create.modules.schematics.SchematicWorld;
@ -34,7 +35,6 @@ import net.minecraft.state.properties.BedPart;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.DoubleBlockHalf;
import net.minecraft.state.properties.SlabType;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
@ -42,7 +42,6 @@ import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.gen.feature.template.Template;
@ -51,9 +50,8 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
public class SchematicannonTileEntity extends SyncedTileEntity implements ITickableTileEntity, INamedContainerProvider {
public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider {
public static final int NEIGHBOUR_CHECKING = 100;
public static final int MAX_ANCHOR_DISTANCE = 256;
@ -105,63 +103,6 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Render
public boolean firstRenderTick;
public class SchematicannonInventory extends ItemStackHandler {
public SchematicannonInventory() {
super(5);
}
@Override
protected void onContentsChanged(int slot) {
super.onContentsChanged(slot);
markDirty();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
switch (slot) {
case 0: // Blueprint Slot
return AllItems.BLUEPRINT.typeOf(stack);
case 1: // Blueprint output
return false;
case 2: // Book input
return stack.isItemEqual(new ItemStack(Items.BOOK))
|| stack.isItemEqual(new ItemStack(Items.WRITTEN_BOOK));
case 3: // Material List output
return false;
case 4: // Gunpowder
return stack.isItemEqual(new ItemStack(Items.GUNPOWDER));
default:
return super.isItemValid(slot, stack);
}
}
}
public class LaunchedBlock {
public int totalTicks;
public int ticksRemaining;
public BlockPos target;
public BlockState state;
public LaunchedBlock(BlockPos target, BlockState state) {
this.target = target;
this.state = state;
totalTicks = (int) (Math.max(10, MathHelper.sqrt(MathHelper.sqrt(target.distanceSq(pos))) * 4f));
ticksRemaining = totalTicks;
}
public LaunchedBlock(BlockPos target, BlockState state, int ticksLeft, int total) {
this.target = target;
this.state = state;
this.totalTicks = total;
this.ticksRemaining = ticksLeft;
}
public void update() {
if (ticksRemaining > 0)
ticksRemaining--;
}
}
public SchematicannonTileEntity() {
this(AllTileEntities.SCHEMATICANNON.type);
}
@ -179,9 +120,10 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
public SchematicannonTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
setLazyTickRate(30);
attachedInventories = new LinkedList<>();
flyingBlocks = new LinkedList<>();
inventory = new SchematicannonInventory();
inventory = new SchematicannonInventory(this);
statusMsg = "idle";
state = State.STOPPED;
replaceMode = 2;
@ -271,7 +213,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Always write to Server tile
if (world == null || !world.isRemote) {
flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2));
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
continue;
}
@ -284,7 +226,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Add new server side blocks
if (i >= flyingBlocks.size()) {
flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2));
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
continue;
}
@ -346,6 +288,8 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
@Override
public void tick() {
super.tick();
if (neighbourCheckCooldown-- <= 0) {
neighbourCheckCooldown = NEIGHBOUR_CHECKING;
findInventories();
@ -757,7 +701,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
protected void launchBlock(BlockPos target, BlockState state) {
if (state.getBlock() != Blocks.AIR)
blocksPlaced++;
flyingBlocks.add(new LaunchedBlock(target, state));
flyingBlocks.add(new LaunchedBlock(this, target, state));
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_GENERIC_EXPLODE,
SoundCategory.BLOCKS, .1f, 1.1f);
}
@ -817,4 +761,14 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
sendUpdate = true;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
}
@Override
public void lazyTick() {
super.lazyTick();
findInventories();
}
}

View file

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

View file

@ -96,6 +96,7 @@
"block.create.belt": "Mechanical Belt",
"block.create.crushing_wheel": "Crushing Wheel",
"block.create.drill": "Mechanical Drill",
"block.create.portable_storage_interface": "Portable Storage Interface",
"block.create.harvester": "Mechanical Harvester",
"block.create.saw": "Mechanical Saw",
"block.create.water_wheel": "Water Wheel",

View file

@ -0,0 +1,165 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"0": "create:block/brass_casing",
"5": "create:block/andesite_casing_short",
"6": "create:block/gearbox_top",
"7": "block/dark_oak_log",
"1_2": "create:block/transposer",
"particle": "create:block/extractor"
},
"elements": [
{
"name": "Center",
"from": [2, 1, 2],
"to": [14, 11, 14],
"faces": {
"up": {"uv": [2, 4, 14, 16], "texture": "#7"},
"down": {"uv": [2, 2, 14, 14], "texture": "#6"}
}
},
{
"name": "Side",
"from": [0, 0, 0],
"to": [2, 12, 16],
"faces": {
"north": {"uv": [14, 4, 16, 16], "texture": "#5"},
"east": {"uv": [0, 4, 16, 16], "texture": "#5"},
"south": {"uv": [0, 4, 2, 16], "texture": "#5"},
"west": {"uv": [0, 4, 16, 16], "texture": "#5"},
"up": {"uv": [0, 0, 2, 16], "texture": "#6"},
"down": {"uv": [0, 0, 2, 16], "texture": "#6"}
}
},
{
"name": "Side",
"from": [14, 0, 0],
"to": [16, 12, 16],
"faces": {
"north": {"uv": [0, 4, 2, 16], "texture": "#5"},
"east": {"uv": [0, 4, 16, 16], "texture": "#5"},
"south": {"uv": [14, 4, 16, 16], "texture": "#5"},
"west": {"uv": [0, 4, 16, 16], "texture": "#5"},
"up": {"uv": [14, 0, 16, 16], "texture": "#6"},
"down": {"uv": [14, 0, 16, 16], "texture": "#6"}
}
},
{
"name": "Short Side",
"from": [2, 0, 0],
"to": [14, 12, 2],
"faces": {
"north": {"uv": [2, 4, 14, 16], "texture": "#5"},
"south": {"uv": [2, 4, 14, 16], "texture": "#5"},
"up": {"uv": [2, 0, 14, 2], "texture": "#6"},
"down": {"uv": [2, 14, 14, 16], "texture": "#6"}
}
},
{
"name": "Short Side",
"from": [2, 0, 14],
"to": [14, 12, 16],
"faces": {
"north": {"uv": [2, 4, 14, 16], "texture": "#5"},
"south": {"uv": [2, 4, 14, 16], "texture": "#5"},
"up": {"uv": [2, 14, 14, 16], "texture": "#6"},
"down": {"uv": [2, 0, 14, 2], "texture": "#6"}
}
},
{
"from": [4, 11, 4],
"to": [12, 15, 12],
"faces": {
"north": {"uv": [1, 4, 5, 12], "rotation": 90, "texture": "#0"},
"east": {"uv": [1, 4, 5, 12], "rotation": 90, "texture": "#0"},
"south": {"uv": [1, 4, 5, 12], "rotation": 90, "texture": "#0"},
"west": {"uv": [1, 4, 5, 12], "rotation": 90, "texture": "#0"},
"up": {"uv": [7, 7, 15, 15], "rotation": 90, "texture": "#1_2"}
}
},
{
"from": [3, 11, 11],
"to": [5, 16, 13],
"faces": {
"north": {"uv": [0, 14, 5, 16], "rotation": 90, "texture": "#0"},
"east": {"uv": [11, 14, 16, 16], "rotation": 270, "texture": "#1_2"},
"south": {"uv": [6, 14, 11, 16], "rotation": 90, "texture": "#1_2"},
"west": {"uv": [6, 6, 11, 8], "rotation": 90, "texture": "#1_2"},
"up": {"uv": [4, 6, 6, 8], "rotation": 180, "texture": "#1_2"}
}
},
{
"from": [11, 11, 11],
"to": [13, 16, 13],
"faces": {
"north": {"uv": [0, 16, 5, 14], "rotation": 90, "texture": "#0"},
"east": {"uv": [11, 6, 6, 8], "rotation": 270, "texture": "#1_2"},
"south": {"uv": [6, 16, 11, 14], "rotation": 90, "texture": "#1_2"},
"west": {"uv": [16, 14, 11, 16], "rotation": 90, "texture": "#1_2"},
"up": {"uv": [6, 6, 4, 8], "rotation": 180, "texture": "#1_2"}
}
},
{
"from": [3, 11, 3],
"to": [5, 16, 5],
"faces": {
"north": {"uv": [11, 14, 6, 16], "rotation": 270, "texture": "#1_2"},
"east": {"uv": [11, 16, 16, 14], "rotation": 270, "texture": "#1_2"},
"south": {"uv": [5, 14, 0, 16], "rotation": 270, "texture": "#0"},
"west": {"uv": [6, 8, 11, 6], "rotation": 90, "texture": "#1_2"},
"up": {"uv": [4, 8, 6, 6], "rotation": 180, "texture": "#1_2"}
}
},
{
"from": [11, 11, 3],
"to": [13, 16, 5],
"faces": {
"north": {"uv": [11, 16, 6, 14], "rotation": 270, "texture": "#1_2"},
"east": {"uv": [11, 8, 6, 6], "rotation": 270, "texture": "#1_2"},
"south": {"uv": [5, 16, 0, 14], "rotation": 270, "texture": "#0"},
"west": {"uv": [16, 16, 11, 14], "rotation": 90, "texture": "#1_2"},
"up": {"uv": [6, 8, 4, 6], "rotation": 180, "texture": "#1_2"}
}
}
],
"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, -45, -90],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"rotation": [-90, 0, 0],
"scale": [0.5, 0.5, 0.5]
}
},
"groups": [
{
"name": "group",
"origin": [8, 8, 8],
"children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
]
}

View file

@ -3,7 +3,7 @@
"parent": "block/block",
"textures": {
"0": "create:block/brass_casing",
"1": "create:block/black_stained_glass",
"1": "block/black_stained_glass",
"2": "create:item/goggles",
"particle": "create:block/brass_casing"
},

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 423 B

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 564 B

View file

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