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.CasingBlock;
import com.simibubi.create.modules.contraptions.components.actors.DrillBlock; 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.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.clock.CuckooClockBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingBlock; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.LinearChassisBlock; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.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.GlassPaneBlock;
import com.simibubi.create.modules.palettes.HorizontalCTGlassBlock; import com.simibubi.create.modules.palettes.HorizontalCTGlassBlock;
import com.simibubi.create.modules.palettes.LayeredCTBlock; 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.ScoriaBlock;
import com.simibubi.create.modules.palettes.VerticalCTGlassBlock;
import com.simibubi.create.modules.schematics.block.CreativeCrateBlock; import com.simibubi.create.modules.schematics.block.CreativeCrateBlock;
import com.simibubi.create.modules.schematics.block.SchematicTableBlock; import com.simibubi.create.modules.schematics.block.SchematicTableBlock;
import com.simibubi.create.modules.schematics.block.SchematicannonBlock; import com.simibubi.create.modules.schematics.block.SchematicannonBlock;
@ -129,11 +130,6 @@ public enum AllBlocks {
MECHANICAL_PRESS(new MechanicalPressBlock()), MECHANICAL_PRESS(new MechanicalPressBlock()),
MECHANICAL_MIXER(new MechanicalMixerBlock()), MECHANICAL_MIXER(new MechanicalMixerBlock()),
BASIN(new BasinBlock()), BASIN(new BasinBlock()),
MECHANICAL_CRAFTER(new MechanicalCrafterBlock()),
FLYWHEEL(new FlywheelBlock()),
FURNACE_ENGINE(new FurnaceEngineBlock()),
SPEED_GAUGE(new GaugeBlock(GaugeBlock.Type.SPEED)), SPEED_GAUGE(new GaugeBlock(GaugeBlock.Type.SPEED)),
STRESS_GAUGE(new GaugeBlock(GaugeBlock.Type.STRESS)), STRESS_GAUGE(new GaugeBlock(GaugeBlock.Type.STRESS)),
@ -149,6 +145,7 @@ public enum AllBlocks {
SAW(new SawBlock()), SAW(new SawBlock()),
HARVESTER(new HarvesterBlock()), HARVESTER(new HarvesterBlock()),
DEPLOYER(new DeployerBlock()), DEPLOYER(new DeployerBlock()),
PORTABLE_STORAGE_INTERFACE(new PortableStorageInterfaceBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()), CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()), MINECART_ANCHOR(new MinecartAnchorBlock()),
ANALOG_LEVER(new AnalogLeverBlock()), ANALOG_LEVER(new AnalogLeverBlock()),
@ -157,6 +154,10 @@ public enum AllBlocks {
COPPER_CASING(new CasingBlock("copper_casing")), COPPER_CASING(new CasingBlock("copper_casing")),
BRASS_CASING(new CasingBlock("crafter_top")), BRASS_CASING(new CasingBlock("crafter_top")),
MECHANICAL_CRAFTER(new MechanicalCrafterBlock()),
FLYWHEEL(new FlywheelBlock()),
FURNACE_ENGINE(new FurnaceEngineBlock()),
__LOGISTICS__(), __LOGISTICS__(),
CONTACT(new ContactBlock()), CONTACT(new ContactBlock()),
REDSTONE_BRIDGE(new RedstoneLinkBlock()), 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.command.ConfigureConfigPacket;
import com.simibubi.create.foundation.packet.NbtPacket; import com.simibubi.create.foundation.packet.NbtPacket;
import com.simibubi.create.foundation.packet.SimplePacketBase; 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.contraptions.chassis.ConfigureChassisPacket;
import com.simibubi.create.modules.contraptions.components.mixer.ConfigureMixerPacket; import com.simibubi.create.modules.contraptions.components.mixer.ConfigureMixerPacket;
import com.simibubi.create.modules.contraptions.components.motor.ConfigureMotorPacket; import com.simibubi.create.modules.contraptions.components.motor.ConfigureMotorPacket;
@ -45,8 +47,10 @@ public enum AllPackets {
// Server to Client // Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new), SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new),
SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new),
BEAM_EFFECT(BlockzapperBeamPacket.class, BlockzapperBeamPacket::new), BEAM_EFFECT(BlockzapperBeamPacket.class, BlockzapperBeamPacket::new),
CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new), CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new),
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new),
; ;

View file

@ -1,8 +1,6 @@
package com.simibubi.create; package com.simibubi.create;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers; 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.LogManager;
import org.apache.logging.log4j.Logger; 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 extractorDelay = i(20, 10, "extractorDelay", Comments.extractorDelay);
public ConfigInt extractorInventoryScanDelay = i(40, 10, "extractorInventoryScanDelay", Comments.extractorInventoryScanDelay); public ConfigInt extractorInventoryScanDelay = i(40, 10, "extractorInventoryScanDelay", Comments.extractorInventoryScanDelay);
public ConfigInt extractorAmount = i(16, 1, 64, "extractorAmount", Comments.extractorAmount); 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 @Override
public String getName() { public String getName() {

View file

@ -8,6 +8,10 @@ public class CServer extends ConfigBase {
public ConfigBool enablePalettes = b(true, "enablePalettes"); public ConfigBool enablePalettes = b(true, "enablePalettes");
public ConfigBool enableLogistics = b(true, "enableLogistics"); 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 CKinetics kinetics = nested(0, CKinetics::new, Comments.kinetics);
public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics); public CLogistics logistics = nested(0, CLogistics::new, Comments.logistics);
public CSchematics schematics = nested(0, CSchematics::new, Comments.schematics); 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 curiosities = "Everything that spins";
static String modules = "Configure which Modules should be accessible in recipes and creative menus."; 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 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.JsonDeserializationContext;
import com.google.gson.JsonObject; 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.advancements.criterion.ItemPredicate;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
public class SandpaperUseTrigger extends CriterionTriggerBase<SandpaperUseTrigger.Instance> { public class SandpaperUseTrigger extends CriterionTriggerBase<SandpaperUseTrigger.Instance> {

View file

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

View file

@ -33,7 +33,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
super(te, attachments); super(te, attachments);
customAmountFilter = stack -> 64; customAmountFilter = stack -> 64;
customFilter = stack -> true; customFilter = stack -> true;
callback = onExtract; setCallback(onExtract);
} }
public ExtractingBehaviour withAmountThreshold(Function<ItemStack, Integer> filter) { public ExtractingBehaviour withAmountThreshold(Function<ItemStack, Integer> filter) {
@ -47,11 +47,15 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
} }
public boolean extract() { public boolean extract() {
return extract(getAmountToExtract());
}
public int getAmountToExtract() {
int amount = -1; int amount = -1;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE); FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null && !filter.anyAmount()) if (filter != null && !filter.anyAmount())
amount = filter.getAmount(); amount = filter.getAmount();
return extract(amount); return amount;
} }
public boolean extract(int exactAmount) { public boolean extract(int exactAmount) {
@ -60,11 +64,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
if (AllConfigs.SERVER.control.freezeExtractors.get()) if (AllConfigs.SERVER.control.freezeExtractors.get())
return false; return false;
Predicate<ItemStack> test = customFilter; Predicate<ItemStack> test = getFilterTest();
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null)
test = customFilter.and(filter::test);
for (IItemHandler inv : getInventories()) { for (IItemHandler inv : getInventories()) {
ItemStack extract = ItemStack.EMPTY; ItemStack extract = ItemStack.EMPTY;
if (exactAmount != -1) if (exactAmount != -1)
@ -81,9 +81,21 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
return false; 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 @Override
public IBehaviourType<?> getType() { public IBehaviourType<?> getType() {
return TYPE; 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 class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour {
public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE = new IBehaviourType<SingleTargetAutoExtractingBehaviour>() { public static IBehaviourType<SingleTargetAutoExtractingBehaviour> TYPE =
}; new IBehaviourType<SingleTargetAutoExtractingBehaviour>() {
};
private Supplier<Direction> attachmentDirection; private Supplier<Direction> attachmentDirection;
boolean synced; boolean synced;
@ -28,8 +29,8 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour
advantageOnNextSync = false; advantageOnNextSync = false;
} }
public SingleTargetAutoExtractingBehaviour dontSynchronize() { public SingleTargetAutoExtractingBehaviour setSynchronized(boolean sync) {
synced = false; synced = sync;
return this; return this;
} }

View file

@ -33,7 +33,10 @@ public class AllShapes {
makeCuboidShape(4, 4, 11, 12, 12, 17)), Direction.SOUTH), makeCuboidShape(4, 4, 11, 12, 12, 17)), Direction.SOUTH),
FURNACE_ENGINE = VoxelShaper.forHorizontal(VoxelShapes.or( FURNACE_ENGINE = VoxelShaper.forHorizontal(VoxelShapes.or(
makeCuboidShape(1, 1, 0, 15, 15, 16), 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.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.AxisAlignedBB;
public class NBTHelper { public class NBTHelper {
@ -44,5 +46,24 @@ public class NBTHelper {
public static List<ItemStack> readItemList(ListNBT stacks) { public static List<ItemStack> readItemList(ListNBT stacks) {
return readCompoundList(stacks, ItemStack::read); 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 { 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 ticksUntilNextProgress;
protected int destroyProgress; protected int destroyProgress;
protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet(); protected int breakerId = -NEXT_BREAKER_ID.incrementAndGet();
@ -119,6 +119,10 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
} }
public boolean canBreak(BlockState stateToBreak, float blockHardness) { 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 return !(stateToBreak.getMaterial().isLiquid() || stateToBreak.getBlock() instanceof AirBlock
|| blockHardness == -1); || 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; package com.simibubi.create.modules.contraptions.components.actors;
import java.util.List;
import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.foundation.utility.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.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.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction; 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.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos; 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.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; 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 public class DrillBlock extends DirectionalKineticBlock implements IPortableBlock, IWithTileEntity<DrillTileEntity> {
implements IHaveMovementBehavior, IWithTileEntity<DrillTileEntity> {
public static MovementBehaviour MOVEMENT = new DrillMovementBehaviour();
public DrillBlock() { public DrillBlock() {
super(Properties.from(Blocks.IRON_BLOCK)); super(Properties.from(Blocks.IRON_BLOCK));
@ -76,44 +68,10 @@ public class DrillBlock extends DirectionalKineticBlock
protected boolean hasStaticPart() { protected boolean hasStaticPart() {
return true; return true;
} }
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return DrillTileEntityRenderer.renderInContraption(context);
}
@Override @Override
public boolean isActive(MovementContext context) { public MovementBehaviour getMovementBehaviour() {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.get(FACING).getOpposite()); return MOVEMENT;
}
@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);
}
} }
} }

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

View file

@ -1,43 +1,29 @@
package com.simibubi.create.modules.contraptions.components.actors; package com.simibubi.create.modules.contraptions.components.actors;
import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.CropsBlock;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.SugarCaneBlock;
import net.minecraft.block.material.PushReaction; import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext; 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.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; 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.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader; 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() { public HarvesterBlock() {
super(Properties.from(Blocks.IRON_BLOCK)); super(Properties.from(Blocks.IRON_BLOCK));
@ -70,12 +56,6 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
super.fillStateContainer(builder); super.fillStateContainer(builder);
} }
@Override
@OnlyIn(value = Dist.CLIENT)
public SuperByteBuffer renderInContraption(MovementContext context) {
return HarvesterTileEntityRenderer.renderInContraption(context);
}
@Override @Override
public BlockRenderLayer getRenderLayer() { public BlockRenderLayer getRenderLayer() {
return BlockRenderLayer.CUTOUT; return BlockRenderLayer.CUTOUT;
@ -94,8 +74,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
if (context.getFace().getAxis().isVertical()) if (context.getFace().getAxis().isVertical())
facing = context.getPlacementHorizontalFacing().getOpposite(); facing = context.getPlacementHorizontalFacing().getOpposite();
else { else {
BlockState blockState = context.getWorld() BlockState blockState =
.getBlockState(context.getPos().offset(context.getFace().getOpposite())); context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite()));
if (AllBlocks.HARVESTER.typeOf(blockState)) if (AllBlocks.HARVESTER.typeOf(blockState))
facing = blockState.get(HORIZONTAL_FACING); facing = blockState.get(HORIZONTAL_FACING);
else else
@ -105,118 +85,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
} }
@Override @Override
public boolean isActive(MovementContext context) { public MovementBehaviour getMovementBehaviour() {
return !VecHelper.isVecPointingTowards(context.relativeMotion, return MOVEMENT;
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();
} }
} }

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.AnimationTickHolder;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper; 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.block.BlockState;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
@ -19,16 +19,18 @@ import net.minecraft.world.World;
public class HarvesterTileEntityRenderer extends SafeTileEntityRendererFast<HarvesterTileEntity> { public class HarvesterTileEntityRenderer extends SafeTileEntityRendererFast<HarvesterTileEntity> {
@Override @Override
public void renderFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks, public void renderFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
int destroyStage, BufferBuilder buffer) { BufferBuilder buffer) {
SuperByteBuffer superBuffer = renderHead(getWorld(), te.getPos(), te.getBlockState(), 0); SuperByteBuffer superBuffer = renderHead(getWorld(), te.getPos(), te.getBlockState(), 0);
superBuffer.translate(x, y, z).renderInto(buffer); superBuffer.translate(x, y, z).renderInto(buffer);
} }
public static SuperByteBuffer renderInContraption(MovementContext context) { public static SuperByteBuffer renderInContraption(MovementContext context) {
BlockState state = context.state; BlockState state = context.state;
float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, state.get(HORIZONTAL_FACING).getOpposite()) Direction facing = state.get(HORIZONTAL_FACING);
? context.getAnimationSpeed() * state.get(HORIZONTAL_FACING).getAxisDirection().getOffset() int offset = facing.getAxisDirection().getOffset() * (facing.getAxis() == Axis.X ? 1 : -1);
float speed = (float) (!VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite())
? context.getAnimationSpeed() * offset
: 0); : 0);
float time = AnimationTickHolder.getRenderTick() / 20; float time = AnimationTickHolder.getRenderTick() / 20;
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI); 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 static net.minecraft.state.properties.BlockStateProperties.FACING;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.config.AllConfigs; 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.bearing.BearingContraption;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; 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.contraptions.piston.PistonContraption;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock; import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.FallingBlock; import net.minecraft.block.FallingBlock;
import net.minecraft.block.PistonBlock;
import net.minecraft.block.ShulkerBoxBlock; import net.minecraft.block.ShulkerBoxBlock;
import net.minecraft.block.SlimeBlock; import net.minecraft.block.SlimeBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties; 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.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
public class Contraption { public class Contraption {
public Map<BlockPos, BlockInfo> blocks; public Map<BlockPos, BlockInfo> blocks;
public Map<BlockPos, MountedStorage> storage;
public List<MutablePair<BlockInfo, MovementContext>> actors; public List<MutablePair<BlockInfo, MovementContext>> actors;
public CombinedInvWrapper inventory;
public AxisAlignedBB constructCollisionBox; public AxisAlignedBB constructCollisionBox;
public boolean stalled;
protected Set<BlockPos> cachedColliders; protected Set<BlockPos> cachedColliders;
protected Direction cachedColliderDirection; protected Direction cachedColliderDirection;
protected BlockPos anchor; protected BlockPos anchor;
public Contraption() { public Contraption() {
blocks = new HashMap<>(); blocks = new HashMap<>();
storage = new HashMap<>();
actors = new ArrayList<>(); actors = new ArrayList<>();
} }
@ -137,15 +150,22 @@ public class Contraption {
return false; return false;
for (int limit = 1000; limit > 0; limit--) { for (int limit = 1000; limit > 0; limit--) {
if (frontier.isEmpty()) if (frontier.isEmpty()) {
onAssembled(world, pos);
return true; return true;
}
if (!moveBlock(world, frontier.remove(0), direction, frontier, visited)) if (!moveBlock(world, frontier.remove(0), direction, frontier, visited))
return false; return false;
} }
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) { protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
return true; return true;
} }
@ -417,15 +437,16 @@ public class Contraption {
return true; return true;
if (blockState.getBlock() instanceof ShulkerBoxBlock) if (blockState.getBlock() instanceof ShulkerBoxBlock)
return false; 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); BlockState blockstate = world.getBlockState(pos);
if (AllBlocks.SAW.typeOf(blockstate)) if (AllBlocks.SAW.typeOf(blockstate))
blockstate = blockstate.with(SawBlock.RUNNING, true); blockstate = blockstate.with(SawBlock.RUNNING, true);
CompoundNBT compoundnbt = getTileEntityNBT(world, pos); 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) { public static CompoundNBT getTileEntityNBT(World world, BlockPos pos) {
@ -440,13 +461,20 @@ public class Contraption {
return compoundnbt; 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); BlockPos localPos = pos.subtract(anchor);
BlockInfo blockInfo = new BlockInfo(localPos, block.state, block.nbt); BlockInfo blockInfo = new BlockInfo(localPos, captured.state, captured.nbt);
blocks.put(localPos, blockInfo);
if (block.state.getBlock() instanceof IHaveMovementBehavior) if (blocks.put(localPos, blockInfo) != null)
getActors().add(MutablePair.of(blockInfo, null)); return;
constructCollisionBox = constructCollisionBox.union(new AxisAlignedBB(localPos)); 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) { public static Contraption fromNBT(World world, CompoundNBT nbt) {
@ -463,6 +491,7 @@ public class Contraption {
} }
public void readNBT(World world, CompoundNBT nbt) { public void readNBT(World world, CompoundNBT nbt) {
blocks.clear();
nbt.getList("Blocks", 10).forEach(c -> { nbt.getList("Blocks", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c; CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")), BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
@ -471,23 +500,31 @@ public class Contraption {
blocks.put(info.pos, info); blocks.put(info.pos, info);
}); });
actors.clear();
nbt.getList("Actors", 10).forEach(c -> { nbt.getList("Actors", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c; CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos"))); BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
MovementContext context = MovementContext.readNBT(world, comp); MovementContext context = MovementContext.readNBT(world, comp);
context.contraption = this;
getActors().add(MutablePair.of(info, context)); 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")) 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")); anchor = NBTUtil.readBlockPos(nbt.getCompound("Anchor"));
} }
public AxisAlignedBB getCollisionBoxFront() {
return constructCollisionBox;
}
public CompoundNBT writeNBT() { public CompoundNBT writeNBT() {
CompoundNBT nbt = new CompoundNBT(); CompoundNBT nbt = new CompoundNBT();
@ -498,14 +535,14 @@ public class Contraption {
if (this instanceof BearingContraption) if (this instanceof BearingContraption)
nbt.putString("Type", "Bearing"); nbt.putString("Type", "Bearing");
ListNBT blocks = new ListNBT(); ListNBT blocksNBT = new ListNBT();
for (BlockInfo block : this.blocks.values()) { for (BlockInfo block : this.blocks.values()) {
CompoundNBT c = new CompoundNBT(); CompoundNBT c = new CompoundNBT();
c.put("Block", NBTUtil.writeBlockState(block.state)); c.put("Block", NBTUtil.writeBlockState(block.state));
c.put("Pos", NBTUtil.writeBlockPos(block.pos)); c.put("Pos", NBTUtil.writeBlockPos(block.pos));
if (block.nbt != null) if (block.nbt != null)
c.put("Data", block.nbt); c.put("Data", block.nbt);
blocks.add(c); blocksNBT.add(c);
} }
ListNBT actorsNBT = new ListNBT(); ListNBT actorsNBT = new ListNBT();
@ -515,41 +552,37 @@ public class Contraption {
actor.right.writeToNBT(compound); actor.right.writeToNBT(compound);
actorsNBT.add(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("Actors", actorsNBT);
nbt.put("Storage", storageNBT);
nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
nbt.putBoolean("Stalled", stalled);
if (constructCollisionBox != null) { if (constructCollisionBox != null) {
ListNBT bb = writeAABB(constructCollisionBox); ListNBT bb = NBTHelper.writeAABB(constructCollisionBox);
nbt.put("BoundsFront", bb); nbt.put("BoundsFront", bb);
} }
nbt.put("Blocks", blocks);
nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
return nbt; 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() { public static boolean isFrozen() {
return AllConfigs.SERVER.control.freezePistonConstructs.get(); 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); 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) { BiPredicate<BlockPos, BlockState> customPlacement) {
stop(world);
for (BlockInfo block : blocks.values()) { for (BlockInfo block : blocks.values()) {
BlockPos targetPos = block.pos.add(offset); BlockPos targetPos = block.pos.add(offset);
BlockState state = block.state; BlockState state = block.state;
@ -589,7 +623,13 @@ public class Contraption {
block.nbt.putInt("y", targetPos.getY()); block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ()); block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt); 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) { for (MutablePair<BlockInfo, MovementContext> pair : actors) {
BlockState blockState = pair.left.state; BlockState blockState = pair.left.state;
MovementContext context = new MovementContext(world, blockState); MovementContext context = new MovementContext(world, blockState);
((IHaveMovementBehavior) blockState.getBlock()).startMoving(context); context.contraption = this;
getMovement(blockState).startMoving(context);
pair.setRight(context); pair.setRight(context);
} }
} }
public AxisAlignedBB getCollisionBoxFront() {
return constructCollisionBox;
}
public List<MutablePair<BlockInfo, MovementContext>> getActors() { public List<MutablePair<BlockInfo, MovementContext>> getActors() {
return actors; return actors;
} }
@ -610,4 +655,26 @@ public class Contraption {
return anchor; 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 org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllEntities; import com.simibubi.create.AllEntities;
import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.utility.VecHelper; 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.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity; import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.IPacket; import net.minecraft.network.IPacket;
import net.minecraft.network.PacketBuffer; 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.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; 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.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraft.world.server.ServerWorld; 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.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.fml.network.PacketDistributor;
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData { public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
@ -29,8 +37,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected float initialAngle; protected float initialAngle;
protected BlockPos controllerPos; protected BlockPos controllerPos;
protected IControlContraption controllerTE; 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 prevYaw;
public float prevPitch; public float prevPitch;
@ -46,6 +56,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public ContraptionEntity(EntityType<?> entityTypeIn, World worldIn) { public ContraptionEntity(EntityType<?> entityTypeIn, World worldIn) {
super(entityTypeIn, worldIn); super(entityTypeIn, worldIn);
motionBeforeStall = Vec3d.ZERO;
} }
protected ContraptionEntity(World world) { protected ContraptionEntity(World world) {
@ -59,7 +70,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
this.prevYaw = initialAngle; this.prevYaw = initialAngle;
this.yaw = initialAngle; this.yaw = initialAngle;
this.targetYaw = initialAngle; this.targetYaw = initialAngle;
movementSpeedModifier = 1;
} }
public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) { public <T extends TileEntity & IControlContraption> ContraptionEntity controlledBy(T controller) {
@ -70,8 +80,13 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override @Override
public void tick() { public void tick() {
if (contraption == null) {
remove();
return;
}
attachToController(); attachToController();
Entity e = getRidingEntity(); Entity e = getRidingEntity();
if (e != null) { if (e != null) {
Vec3d movementVector = e.getMotion(); Vec3d movementVector = e.getMotion();
@ -97,7 +112,19 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
pitch = angleLerp(speed, pitch, targetPitch); pitch = angleLerp(speed, pitch, targetPitch);
} }
boolean wasStalled = isStalled();
tickActors(movementVector); 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(); super.tick();
return; return;
} }
@ -111,47 +138,62 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public void tickActors(Vec3d movementVector) { public void tickActors(Vec3d movementVector) {
movementSpeedModifier = 1;
float anglePitch = getPitch(1); float anglePitch = getPitch(1);
float angleYaw = getYaw(1); float angleYaw = getYaw(1);
float angleRoll = getRoll(1); float angleRoll = getRoll(1);
Vec3d rotationVec = new Vec3d(angleRoll, angleYaw, anglePitch); Vec3d rotationVec = new Vec3d(angleRoll, angleYaw, anglePitch);
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
boolean stalledPreviously = contraption.stalled;
if (!world.isRemote)
contraption.stalled = false;
for (MutablePair<BlockInfo, MovementContext> pair : contraption.actors) { for (MutablePair<BlockInfo, MovementContext> pair : contraption.actors) {
MovementContext context = pair.right; MovementContext context = pair.right;
BlockInfo blockInfo = pair.left; BlockInfo blockInfo = pair.left;
IHaveMovementBehavior actor = (IHaveMovementBehavior) blockInfo.state.getBlock(); MovementBehaviour actor = Contraption.getMovement(blockInfo.state);
Vec3d actorPosition = new Vec3d(blockInfo.pos); Vec3d actorPosition = new Vec3d(blockInfo.pos);
actorPosition = actorPosition.add(actor.getActiveAreaOffset(context)); actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch); actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch);
actorPosition = actorPosition.add(rotationOffset).add(posX, posY, posZ); actorPosition = actorPosition.add(rotationOffset).add(posX, posY, posZ);
Vec3d previousPosition = context.position; boolean newPosVisited = context.position == null;
BlockPos gridPosition = new BlockPos(actorPosition); BlockPos gridPosition = new BlockPos(actorPosition);
boolean newPosVisited = true;
if (previousPosition != null) { if (!stalledPreviously) {
context.motion = actorPosition.subtract(previousPosition); Vec3d previousPosition = context.position;
Vec3d relativeMotion = context.motion; if (previousPosition != null) {
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch); context.motion = actorPosition.subtract(previousPosition);
context.relativeMotion = relativeMotion; Vec3d relativeMotion = context.motion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition); relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition);
}
} }
context.rotation = rotationVec; context.rotation = rotationVec;
context.position = actorPosition; context.position = actorPosition;
if (actor.isActive(context)) { if (actor.isActive(context)) {
if (newPosVisited) if (newPosVisited && !context.stall)
actor.visitNewPosition(context, gridPosition); actor.visitNewPosition(context, gridPosition);
actor.tick(context); 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)); getShortestAngleDiff(this.pitch, pitch));
} }
@Override
public void notifyDataManagerChange(DataParameter<?> key) {
super.notifyDataManagerChange(key);
}
public void rotate(double roll, double yaw, double pitch) { public void rotate(double roll, double yaw, double pitch) {
// Collision and stuff // Collision and stuff
@ -242,12 +289,16 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override @Override
protected void registerData() { protected void registerData() {
this.dataManager.register(STALLED, false);
} }
@Override @Override
protected void readAdditional(CompoundNBT compound) { protected void readAdditional(CompoundNBT compound) {
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption")); contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
initialAngle = compound.getFloat("InitialAngle"); 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")) if (compound.contains("Controller"))
controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller")); controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller"));
prevYaw = initialAngle; prevYaw = initialAngle;
@ -256,12 +307,14 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public void attachToController() { public void attachToController() {
if (controllerPos != null && controllerTE == null) { if (controllerPos != null && (controllerTE == null || !controllerTE.isValid())) {
if (!world.isBlockPresent(controllerPos)) if (!world.isBlockPresent(controllerPos))
return; return;
TileEntity te = world.getTileEntity(controllerPos); TileEntity te = world.getTileEntity(controllerPos);
if (te == null || !(te instanceof IControlContraption)) if (te == null || !(te instanceof IControlContraption)) {
remove(); remove();
return;
}
IControlContraption controllerTE = (IControlContraption) te; IControlContraption controllerTE = (IControlContraption) te;
this.controllerTE = controllerTE; this.controllerTE = controllerTE;
controllerTE.attach(this); controllerTE.attach(this);
@ -272,6 +325,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected void writeAdditional(CompoundNBT compound) { protected void writeAdditional(CompoundNBT compound) {
compound.put("Contraption", getContraption().writeNBT()); compound.put("Contraption", getContraption().writeNBT());
compound.putFloat("InitialAngle", initialAngle); compound.putFloat("InitialAngle", initialAngle);
compound.put("CachedMotion", newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
if (controllerPos != null) if (controllerPos != null)
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos)); compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
} }
@ -303,4 +357,24 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return contraption; 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.PlacementSimulationWorld;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment; 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.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer; 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.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; 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.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.client.model.data.EmptyModelData; 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) { public static void render(World world, Contraption c, Consumer<SuperByteBuffer> transform, BufferBuilder buffer) {
SuperByteBuffer contraptionBuffer = CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c)); SuperByteBuffer contraptionBuffer = CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c));
transform.accept(contraptionBuffer); 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); renderActors(world, c, transform, buffer);
} }
@ -69,8 +69,7 @@ public class ContraptionRenderer {
context.world = world; context.world = world;
BlockInfo blockInfo = actor.getLeft(); BlockInfo blockInfo = actor.getLeft();
IHaveMovementBehavior block = (IHaveMovementBehavior) blockInfo.state.getBlock(); SuperByteBuffer render = Contraption.getMovement(blockInfo.state).renderInContraption(context);
SuperByteBuffer render = block.renderInContraption(context);
if (render == null) if (render == null)
continue; continue;
@ -80,8 +79,24 @@ public class ContraptionRenderer {
render.translate(posX, posY, posZ); render.translate(posX, posY, posZ);
transform.accept(render); 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); 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; 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.AllBlockTags;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -26,10 +29,10 @@ public class BearingContraption extends Contraption {
} }
@Override @Override
public void add(BlockPos pos, BlockInfo block) { public void add(BlockPos pos, Pair<BlockInfo, TileEntity> capture) {
if (AllBlockTags.WINDMILL_SAILS.matches(block.state)) if (AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state))
sailBlocks++; sailBlocks++;
super.add(pos, block); super.add(pos, capture);
} }
@Override @Override

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.contraptions.components.contraptions.bearing; package com.simibubi.create.modules.contraptions.components.contraptions.bearing;
import com.simibubi.create.AllTileEntities; 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.base.GeneratingKineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; import com.simibubi.create.modules.contraptions.components.contraptions.Contraption;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
@ -9,6 +10,8 @@ import com.simibubi.create.modules.contraptions.components.contraptions.IControl
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; 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.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -30,7 +33,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
public float getAddedStressCapacity() { public float getAddedStressCapacity() {
return isWindmill ? super.getAddedStressCapacity() : 0; return isWindmill ? super.getAddedStressCapacity() : 0;
} }
@Override @Override
public float getStressApplied() { public float getStressApplied() {
return isWindmill ? 0 : super.getStressApplied(); return isWindmill ? 0 : super.getStressApplied();
@ -90,6 +93,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
} }
public float getInterpolatedAngle(float partialTicks) { public float getInterpolatedAngle(float partialTicks) {
if (movedContraption != null && movedContraption.isStalled())
partialTicks = 0;
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed()); return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
} }
@ -100,7 +105,10 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
} }
public float getAngularSpeed() { public float getAngularSpeed() {
return getSpeed() * 3 / 10f; float speed = getSpeed() * 3 / 10f;
if (world.isRemote)
speed *= ServerSpeedProvider.get();
return speed;
} }
public void assembleConstruct() { public void assembleConstruct() {
@ -148,6 +156,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (!world.isRemote && assembleNextTick) { if (!world.isRemote && assembleNextTick) {
assembleNextTick = false; assembleNextTick = false;
if (running) { if (running) {
if (movedContraption != null)
movedContraption.getContraption().stop(world);
boolean canDisassemble = Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45; boolean canDisassemble = Math.abs(angle) < 45 || Math.abs(angle) > 7 * 45;
if (speed == 0 && (canDisassemble || movedContraption == null if (speed == 0 && (canDisassemble || movedContraption == null
|| movedContraption.getContraption().blocks.isEmpty())) { || movedContraption.getContraption().blocks.isEmpty())) {
@ -165,17 +175,21 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
if (!running) if (!running)
return; return;
float angularSpeed = getAngularSpeed(); if (!(movedContraption != null && movedContraption.isStalled())) {
float newAngle = angle + angularSpeed; float angularSpeed = getAngularSpeed();
angle = (float) (newAngle % 360); float newAngle = angle + angularSpeed;
angle = (float) (newAngle % 360);
}
applyRotation(); applyRotation();
} }
private void applyRotation() { private void applyRotation() {
if (movedContraption != null) { 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())); 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) { public void attach(ContraptionEntity contraption) {
if (contraption.getContraption() instanceof BearingContraption) { if (contraption.getContraption() instanceof BearingContraption) {
this.movedContraption = contraption; this.movedContraption = contraption;
markDirty();
BlockPos anchor = pos.offset(getBlockState().get(BlockStateProperties.FACING)); BlockPos anchor = pos.offset(getBlockState().get(BlockStateProperties.FACING));
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
if (!world.isRemote) 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))); superBuffer.rotateCentered(Axis.X, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing)));
if (facing.getAxis().isHorizontal()) if (facing.getAxis().isHorizontal())
superBuffer.rotateCentered(Axis.Y, AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite()))); 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), kineticRotationTransform(superBuffer, bearingTe, facing.getAxis(), (float) (interpolatedAngle / 180 * Math.PI),
getWorld()); getWorld());
superBuffer.translate(x, y, z).renderInto(buffer); superBuffer.translate(x, y, z).renderInto(buffer);

View file

@ -73,6 +73,8 @@ public class CartAssemblerBlock extends AbstractRailBlock {
return; return;
Contraption contraption = MountedContraption.assembleMinecart(world, pos, cart); Contraption contraption = MountedContraption.assembleMinecart(world, pos, cart);
if (contraption == null)
return;
ContraptionEntity entity = new ContraptionEntity(world, contraption, ContraptionEntity entity = new ContraptionEntity(world, contraption,
ContraptionEntity.yawFromMotion(cart.getMotion())); ContraptionEntity.yawFromMotion(cart.getMotion()));
entity.setPosition(pos.getX(), pos.getY(), pos.getZ()); 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 java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; 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.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.RailShape; import net.minecraft.state.properties.RailShape;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
@ -36,9 +39,9 @@ public class MountedContraption extends Contraption {
return null; return null;
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z; 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), AllBlocks.MINECART_ANCHOR.block.getDefaultState().with(BlockStateProperties.HORIZONTAL_AXIS, axis),
null)); null), null));
contraption.removeBlocksFromWorld(world, BlockPos.ZERO); contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
contraption.initActors(world); contraption.initActors(world);
@ -59,11 +62,13 @@ public class MountedContraption extends Contraption {
} }
@Override @Override
protected BlockInfo capture(World world, BlockPos pos) { protected Pair<BlockInfo, TileEntity> capture(World world, BlockPos pos) {
BlockInfo capture = super.capture(world, pos); Pair<BlockInfo, TileEntity> pair = super.capture(world, pos);
BlockInfo capture = pair.getKey();
if (AllBlocks.CART_ASSEMBLER.typeOf(capture.state)) if (AllBlocks.CART_ASSEMBLER.typeOf(capture.state))
return new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null); return Pair.of(new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null),
return capture; pair.getValue());
return pair;
} }
@Override @Override
@ -72,7 +77,7 @@ public class MountedContraption extends Contraption {
} }
@Override @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)); 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.AllBlocks;
import com.simibubi.create.AllTileEntities; 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.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption; import com.simibubi.create.modules.contraptions.components.contraptions.IControlContraption;
@ -105,6 +106,9 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
public void tick() { public void tick() {
super.tick(); super.tick();
if (movedContraption != null && movedContraption.isStalled())
return;
if (!world.isRemote && assembleNextTick) { if (!world.isRemote && assembleNextTick) {
assembleNextTick = false; assembleNextTick = false;
if (running) { if (running) {
@ -122,6 +126,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
return; return;
float movementSpeed = getMovementSpeed(); float movementSpeed = getMovementSpeed();
if (world.isRemote)
movementSpeed *= ServerSpeedProvider.get();
float newOffset = offset + movementSpeed; float newOffset = offset + movementSpeed;
if (movedContraption == null) if (movedContraption == null)
@ -146,7 +152,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ICo
if (movedContraption != null) { if (movedContraption != null) {
Vec3d constructOffset = getConstructOffset(0.5f); Vec3d constructOffset = getConstructOffset(0.5f);
Vec3d vec = constructOffset.add(new Vec3d(movedContraption.getContraption().getAnchor())); 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() { public float getMovementSpeed() {
Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING); Direction pistonDirection = getBlockState().get(BlockStateProperties.FACING);
int movementModifier = pistonDirection.getAxisDirection().getOffset() int movementModifier =
* (pistonDirection.getAxis() == Axis.Z ? -1 : 1); pistonDirection.getAxisDirection().getOffset() * (pistonDirection.getAxis() == Axis.Z ? -1 : 1);
return getSpeed() * -movementModifier / 512f; return getSpeed() * -movementModifier / 512f;
} }
public Vec3d getConstructOffset(float partialTicks) { public Vec3d getConstructOffset(float partialTicks) {
float interpolatedOffset = MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, float interpolatedOffset =
extensionLength); MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, extensionLength);
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset); 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.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.config.AllConfigs; 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.Contraption;
import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState;
@ -132,13 +135,13 @@ public class PistonContraption extends Contraption {
return true; return true;
} }
public void add(BlockPos pos, BlockInfo block) { @Override
// super.add(pos, block); public void add(BlockPos pos, Pair<BlockInfo, TileEntity> capture) {
super.add(pos.offset(orientation, -initialExtensionProgress), block); super.add(pos.offset(orientation, -initialExtensionProgress), capture);
} }
@Override @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) -> { super.disassemble(world, offset, yaw, pitch, (pos, state) -> {
BlockPos pistonPos = anchor.offset(orientation, -initialExtensionProgress - 1); BlockPos pistonPos = anchor.offset(orientation, -initialExtensionProgress - 1);
BlockState pistonState = world.getBlockState(pistonPos); BlockState pistonState = world.getBlockState(pistonPos);
@ -175,7 +178,7 @@ public class PistonContraption extends Contraption {
initialExtensionProgress = nbt.getInt("InitialLength"); initialExtensionProgress = nbt.getInt("InitialLength");
orientation = Direction.byIndex(nbt.getInt("Orientation")); orientation = Direction.byIndex(nbt.getInt("Orientation"));
if (nbt.contains("BoundsBack")) if (nbt.contains("BoundsBack"))
pistonCollisionBox = readAABB(nbt.getList("BoundsBack", 5)); pistonCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsBack", 5));
} }
@Override @Override
@ -183,7 +186,7 @@ public class PistonContraption extends Contraption {
CompoundNBT nbt = super.writeNBT(); CompoundNBT nbt = super.writeNBT();
if (pistonCollisionBox != null) { if (pistonCollisionBox != null) {
ListNBT bb = writeAABB(pistonCollisionBox); ListNBT bb = NBTHelper.writeAABB(pistonCollisionBox);
nbt.put("BoundsBack", bb); nbt.put("BoundsBack", bb);
} }
nbt.putInt("InitialLength", initialExtensionProgress); nbt.putInt("InitialLength", initialExtensionProgress);

View file

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

View file

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

View file

@ -39,12 +39,6 @@ public class EngineTileEntity extends SmartTileEntity {
return super.getRenderBoundingBox().grow(1.5f); return super.getRenderBoundingBox().grow(1.5f);
} }
@Override
public void initialize() {
super.initialize();
lazyTick();
}
@Override @Override
public void lazyTick() { public void lazyTick() {
super.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.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.contraptions.base.DirectionalAxisKineticBlock; 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.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -29,11 +31,11 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
public class SawBlock extends DirectionalAxisKineticBlock public class SawBlock extends DirectionalAxisKineticBlock implements IWithTileEntity<SawTileEntity>, IPortableBlock {
implements IWithTileEntity<SawTileEntity>, IHaveMovementBehavior {
public static final BooleanProperty RUNNING = BooleanProperty.create("running"); public static final BooleanProperty RUNNING = BooleanProperty.create("running");
public static DamageSource damageSourceSaw = new DamageSource("create.saw").setDamageBypassesArmor(); public static DamageSource damageSourceSaw = new DamageSource("create.saw").setDamageBypassesArmor();
public static MovementBehaviour MOVEMENT = new SawMovementBehaviour();
public SawBlock() { public SawBlock() {
super(Properties.from(Blocks.ANDESITE)); super(Properties.from(Blocks.ANDESITE));
@ -103,7 +105,7 @@ public class SawBlock extends DirectionalAxisKineticBlock
return PushReaction.PUSH_ONLY; return PushReaction.PUSH_ONLY;
} }
public boolean isHorizontal(BlockState state) { public static boolean isHorizontal(BlockState state) {
return state.get(FACING).getAxis().isHorizontal(); return state.get(FACING).getAxis().isHorizontal();
} }
@ -133,7 +135,11 @@ public class SawBlock extends DirectionalAxisKineticBlock
worldIn.removeTileEntity(pos); 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.AllBlocks;
import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.IHaveMovementBehavior; import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -16,15 +16,14 @@ import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.TickPriority;
import net.minecraft.world.World; 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 final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static MovementBehaviour MOVEMENT = new ContactMovementBehaviour();
public ContactBlock() { public ContactBlock() {
super(Properties.from(Blocks.ANDESITE)); super(Properties.from(Blocks.ANDESITE));
@ -102,33 +101,8 @@ public class ContactBlock extends ProperDirectionalBlock implements IHaveMovemen
} }
@Override @Override
public Vec3d getActiveAreaOffset(MovementContext context) { public MovementBehaviour getMovementBehaviour() {
return new Vec3d(context.state.get(FACING).getDirectionVec()).scale(.65f); return MOVEMENT;
}
@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;
} }
} }

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

View file

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

View file

@ -1,7 +1,6 @@
package com.simibubi.create.modules.curiosities.tools; package com.simibubi.create.modules.curiosities.tools;
import com.simibubi.create.foundation.advancement.AllCriterionTriggers; 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.block.render.CustomRenderedItemModel;
import com.simibubi.create.foundation.item.IHaveCustomItemModel; import com.simibubi.create.foundation.item.IHaveCustomItemModel;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;

View file

@ -37,19 +37,23 @@ public class TransposerTileEntity extends ExtractorTileEntity {
inserting = new InsertingBehaviour(this, inserting = new InsertingBehaviour(this,
Attachments.toward(() -> AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite())); Attachments.toward(() -> AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite()));
behaviours.add(inserting); behaviours.add(inserting);
applyFilteringCallbacks();
}
public void applyFilteringCallbacks() {
extracting.withAmountThreshold(this::amountToExtract).withAdditionalFilter(this::shouldExtract); extracting.withAmountThreshold(this::amountToExtract).withAdditionalFilter(this::shouldExtract);
} }
public void filterChanged(ItemStack stack) { public void filterChanged(ItemStack stack) {
} }
protected int amountToExtract(ItemStack stack) { public int amountToExtract(ItemStack stack) {
ItemStack tester = stack.copy(); ItemStack tester = stack.copy();
tester.setCount(64); tester.setCount(64);
return 64 - inserting.insert(tester, true).getCount(); return 64 - inserting.insert(tester, true).getCount();
} }
protected boolean shouldExtract(ItemStack stack) { public boolean shouldExtract(ItemStack stack) {
if (isTargetingBelt()) { if (isTargetingBelt()) {
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite(); Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite();
BlockPos targetPos = pos.offset(facing); BlockPos targetPos = pos.offset(facing);
@ -79,7 +83,7 @@ public class TransposerTileEntity extends ExtractorTileEntity {
} }
@Override @Override
protected void onExtract(ItemStack stack) { public void onExtract(ItemStack stack) {
if (isTargetingBelt()) { if (isTargetingBelt()) {
Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite(); Direction facing = AttachedLogisticalBlock.getBlockFacing(getBlockState()).getOpposite();
BlockPos targetPos = pos.offset(facing); 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.inventory.InventoryHelper;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
@ -39,13 +37,6 @@ public class SchematicannonBlock extends Block {
return new SchematicannonTileEntity(); 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 @Override
public boolean isSolid(BlockState state) { public boolean isSolid(BlockState state) {
return false; 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()) { if (!tileEntityIn.flyingBlocks.isEmpty()) {
for (SchematicannonTileEntity.LaunchedBlock block : tileEntityIn.flyingBlocks) { for (LaunchedBlock block : tileEntityIn.flyingBlocks) {
if (block.ticksRemaining == 0) if (block.ticksRemaining == 0)
continue; continue;

View file

@ -9,7 +9,8 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.config.AllConfigs; import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.config.CSchematics; 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.foundation.type.Cuboid;
import com.simibubi.create.modules.schematics.MaterialChecklist; import com.simibubi.create.modules.schematics.MaterialChecklist;
import com.simibubi.create.modules.schematics.SchematicWorld; 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.BlockStateProperties;
import net.minecraft.state.properties.DoubleBlockHalf; import net.minecraft.state.properties.DoubleBlockHalf;
import net.minecraft.state.properties.SlabType; import net.minecraft.state.properties.SlabType;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -42,7 +42,6 @@ import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents; import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.gen.feature.template.Template; 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.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; 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 NEIGHBOUR_CHECKING = 100;
public static final int MAX_ANCHOR_DISTANCE = 256; public static final int MAX_ANCHOR_DISTANCE = 256;
@ -105,63 +103,6 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Render // Render
public boolean firstRenderTick; 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() { public SchematicannonTileEntity() {
this(AllTileEntities.SCHEMATICANNON.type); this(AllTileEntities.SCHEMATICANNON.type);
} }
@ -179,9 +120,10 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
public SchematicannonTileEntity(TileEntityType<?> tileEntityTypeIn) { public SchematicannonTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn); super(tileEntityTypeIn);
setLazyTickRate(30);
attachedInventories = new LinkedList<>(); attachedInventories = new LinkedList<>();
flyingBlocks = new LinkedList<>(); flyingBlocks = new LinkedList<>();
inventory = new SchematicannonInventory(); inventory = new SchematicannonInventory(this);
statusMsg = "idle"; statusMsg = "idle";
state = State.STOPPED; state = State.STOPPED;
replaceMode = 2; replaceMode = 2;
@ -271,7 +213,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Always write to Server tile // Always write to Server tile
if (world == null || !world.isRemote) { if (world == null || !world.isRemote) {
flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
continue; continue;
} }
@ -284,7 +226,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
// Add new server side blocks // Add new server side blocks
if (i >= flyingBlocks.size()) { if (i >= flyingBlocks.size()) {
flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
continue; continue;
} }
@ -346,6 +288,8 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
@Override @Override
public void tick() { public void tick() {
super.tick();
if (neighbourCheckCooldown-- <= 0) { if (neighbourCheckCooldown-- <= 0) {
neighbourCheckCooldown = NEIGHBOUR_CHECKING; neighbourCheckCooldown = NEIGHBOUR_CHECKING;
findInventories(); findInventories();
@ -757,7 +701,7 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
protected void launchBlock(BlockPos target, BlockState state) { protected void launchBlock(BlockPos target, BlockState state) {
if (state.getBlock() != Blocks.AIR) if (state.getBlock() != Blocks.AIR)
blocksPlaced++; 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, world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_GENERIC_EXPLODE,
SoundCategory.BLOCKS, .1f, 1.1f); SoundCategory.BLOCKS, .1f, 1.1f);
} }
@ -817,4 +761,14 @@ public class SchematicannonTileEntity extends SyncedTileEntity implements ITicka
sendUpdate = true; 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.belt": "Mechanical Belt",
"block.create.crushing_wheel": "Crushing Wheel", "block.create.crushing_wheel": "Crushing Wheel",
"block.create.drill": "Mechanical Drill", "block.create.drill": "Mechanical Drill",
"block.create.portable_storage_interface": "Portable Storage Interface",
"block.create.harvester": "Mechanical Harvester", "block.create.harvester": "Mechanical Harvester",
"block.create.saw": "Mechanical Saw", "block.create.saw": "Mechanical Saw",
"block.create.water_wheel": "Water Wheel", "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", "parent": "block/block",
"textures": { "textures": {
"0": "create:block/brass_casing", "0": "create:block/brass_casing",
"1": "create:block/black_stained_glass", "1": "block/black_stained_glass",
"2": "create:item/goggles", "2": "create:item/goggles",
"particle": "create:block/brass_casing" "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"
}
]
}
]
}