Logistics' final stretch, Part I

- Brass tunnels once again have the ability to synchronize inputs among a chain
- Mechanical arms now have a range limitation
- Mechanical arms now wait with initialization until their area is fully loaded
- Chutes no longer ignore the direction of an attached fans air flow
- Chutes now render particles indicating their movement direction
- Chutes can now pull items up from belts or off the ground
- Fixed item model of shadow casing
- Fixed invisible quads under funnels when no casing is applied to the belt
- Belt mounted funnels can now be perpendicular to the belt theyre on
- Funnels can now transpose items like a hopper when facing down
This commit is contained in:
simibubi 2020-09-19 15:19:22 +02:00
parent f58a7c8482
commit 990d80412e
59 changed files with 864 additions and 250 deletions

View file

@ -350,16 +350,16 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
c87674f2935327f78657f1bb44b3b10b6697a548 assets/create/lang/en_ud.json
0e38385f3de32bfc0f5d3d90dfa635469e953e43 assets/create/lang/en_us.json
cb59266eb110493f41cd8754915e2c2626063742 assets/create/lang/unfinished/de_de.json
9f1f8ebf3683613729f0c4d62d12d3146cfdb634 assets/create/lang/unfinished/fr_fr.json
a6d24acb90e85ed13a5bd36a4e95750319a01de5 assets/create/lang/unfinished/it_it.json
5dbd2b38becc4e985cc926bab5c58e8c7dfaf7e7 assets/create/lang/unfinished/ja_jp.json
4065e282b5860497090e86b3bdf2773f9888f502 assets/create/lang/unfinished/ko_kr.json
e1baa1589c53467ca2f610c3f0cc51c861afdcff assets/create/lang/unfinished/nl_nl.json
8590ef541ece9eae76135b3e93c53798b3d37aac assets/create/lang/unfinished/pt_br.json
7b67a7b85631c83f6803eb717bced55d0efb76b7 assets/create/lang/unfinished/ru_ru.json
29a47e6bc1f85467af17f97d30e2e0100bea99ea assets/create/lang/unfinished/zh_cn.json
62a4c9e5454fd6e899495c95d6fddd020d472bc7 assets/create/lang/en_us.json
42081320880e3248cc1e7e667d38bb3be682790a assets/create/lang/unfinished/de_de.json
8fc3d8467436b5dd9221b0ed72b1a64bf83d0767 assets/create/lang/unfinished/fr_fr.json
a5125e0ca8bb93c7c4f11d49a80a155a7ea14b16 assets/create/lang/unfinished/it_it.json
b173b6500f8a675e266864310ab8e205721dbe12 assets/create/lang/unfinished/ja_jp.json
1af8e96a3129f8aac458b75eff69378a0cc9dd7d assets/create/lang/unfinished/ko_kr.json
343a4455ca0f29b2ae6ac439030c0dfde0e4c59b assets/create/lang/unfinished/nl_nl.json
d7bd8d85e3b8def1b4fe72da0a43845d1bb61c1c assets/create/lang/unfinished/pt_br.json
6e7fdb53ae3121e5575021bb224d1bfbe257c38b assets/create/lang/unfinished/ru_ru.json
1a3e1309d92024445dae821d25168dab74ff5cdd assets/create/lang/unfinished/zh_cn.json
846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json
1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json

View file

@ -836,6 +836,10 @@
"create.tooltip.generationSpeed": "Generates at %1$s %2$s",
"create.tooltip.analogStrength": "Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "Take items from %1$s",
"create.mechanical_arm.deposit_to": "Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "%1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "Round Robin",
@ -848,6 +852,7 @@
"create.tunnel.selection_mode.forced_round_robin": "Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "Prefer Nearest",
"create.tunnel.selection_mode.randomize": "Randomize",
"create.tunnel.selection_mode.synchronize": "Synchronize Inputs",
"create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 800",
"_": "Missing Localizations: 804",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s",
"create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 424",
"_": "Missing Localizations: 428",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "Génère à %1$s %2$s",
"create.tooltip.analogStrength": "Force analogique: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 408",
"_": "Missing Localizations: 412",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "Genera %1$s %2$s",
"create.tooltip.analogStrength": "Forza Analogica: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 403",
"_": "Missing Localizations: 407",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "%1$s %2$sを生成",
"create.tooltip.analogStrength": "アナログ強度: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 408",
"_": "Missing Localizations: 412",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "%1$s %2$s만큼 발전함",
"create.tooltip.analogStrength": "레드스톤 출력: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 738",
"_": "Missing Localizations: 742",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s",
"create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 807",
"_": "Missing Localizations: 811",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s",
"create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 801",
"_": "Missing Localizations: 805",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "UNLOCALIZED: Generates at %1$s %2$s",
"create.tooltip.analogStrength": "UNLOCALIZED: Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 88",
"_": "Missing Localizations: 92",
"_": "->------------------------] Game Elements [------------------------<-",
@ -837,6 +837,10 @@
"create.tooltip.generationSpeed": "产生 %1$s %2$s",
"create.tooltip.analogStrength": "调节强度: %1$s/15",
"create.mechanical_arm.extract_from": "UNLOCALIZED: Take items from %1$s",
"create.mechanical_arm.deposit_to": "UNLOCALIZED: Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "UNLOCALIZED: %1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "UNLOCALIZED: When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "UNLOCALIZED: Round Robin",
@ -849,6 +853,7 @@
"create.tunnel.selection_mode.forced_round_robin": "UNLOCALIZED: Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "UNLOCALIZED: Prefer Nearest",
"create.tunnel.selection_mode.randomize": "UNLOCALIZED: Randomize",
"create.tunnel.selection_mode.synchronize": "UNLOCALIZED: Synchronize Inputs",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",

View file

@ -3,6 +3,7 @@ package com.simibubi.create;
import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.particle.AirFlowParticleData;
import com.simibubi.create.content.contraptions.particle.AirParticleData;
import com.simibubi.create.content.contraptions.particle.CubeParticle;
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
import com.simibubi.create.content.contraptions.particle.HeaterParticleData;
@ -26,6 +27,7 @@ public enum AllParticleTypes {
ROTATION_INDICATOR(RotationIndicatorParticleData::new),
AIR_FLOW(AirFlowParticleData::new),
AIR(AirParticleData::new),
HEATER_PARTICLE(HeaterParticleData::new),
CUBE(CubeParticleData::dummy, () -> CubeParticle.Factory::new)

View file

@ -1,7 +1,7 @@
package com.simibubi.create;
import com.simibubi.create.foundation.command.ChunkUtil;
import net.minecraftforge.common.MinecraftForge;
import java.util.Random;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -15,6 +15,7 @@ import com.simibubi.create.content.palettes.PalettesItemGroup;
import com.simibubi.create.content.schematics.ServerSchematicLoader;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.command.ChunkUtil;
import com.simibubi.create.foundation.command.ServerLagger;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.data.CreateRegistrate;
@ -34,6 +35,7 @@ import net.minecraft.particles.ParticleType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
@ -62,6 +64,7 @@ public class Create {
public static TorquePropagator torquePropagator;
public static ServerLagger lagger;
public static ChunkUtil chunkUtil;
public static Random random;
private static final NonNullLazyValue<CreateRegistrate> registrate = CreateRegistrate.lazy(ID);
@ -87,6 +90,7 @@ public class Create {
modEventBus.addListener(EventPriority.LOWEST, this::gatherData);
AllConfigs.register();
random = new Random();
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> CreateClient.addClientListeners(modEventBus));
}

View file

@ -111,7 +111,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
public void blockChanged() {
removeBehaviour(InvManipulationBehaviour.TYPE);
inserting = new InvManipulationBehaviour(this, this::getTargetFace);
putBehaviour(inserting);
attachBehaviourLate(inserting);
}
public BlockFace getTargetFace(World world, BlockPos pos, BlockState state) {

View file

@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.components.deployer;
import java.util.Iterator;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import net.minecraft.item.ItemStack;
@ -132,7 +131,7 @@ public class DeployerItemHandler implements IItemHandlerModifiable {
@Override
public boolean isItemValid(int slot, ItemStack stack) {
FilteringBehaviour filteringBehaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE);
FilteringBehaviour filteringBehaviour = te.getBehaviour(FilteringBehaviour.TYPE);
return filteringBehaviour == null || filteringBehaviour.test(stack);
}

View file

@ -159,59 +159,17 @@ public class AirCurrent {
return;
}
World world = source.getWorld();
BlockPos start = source.getPos();
direction = source.getBlockState()
.get(BlockStateProperties.FACING);
pushing = source.getAirFlowDirection() == direction;
Vec3d directionVec = new Vec3d(direction.getDirectionVec());
Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec);
// 4 Rays test for holes in the shapes blocking the flow
float offsetDistance = .25f;
Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance),
planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance),
planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance),
planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), };
maxDistance = source.getMaxDistance();
float limitedDistance = 0;
// Determine the distance of the air flow
Outer: for (int i = 1; i < maxDistance; i++) {
BlockPos currentPos = start.offset(direction, i);
if (!world.isBlockPresent(currentPos))
break;
BlockState state = world.getBlockState(currentPos);
if (shouldAlwaysPass(state))
continue;
VoxelShape voxelshape = state.getCollisionShape(world, currentPos, ISelectionContext.dummy());
if (voxelshape.isEmpty())
continue;
if (voxelshape == VoxelShapes.fullCube()) {
maxDistance = i - 1;
break;
}
for (Vec3d offset : offsets) {
Vec3d rayStart = VecHelper.getCenterOf(currentPos)
.subtract(directionVec.scale(.5f + 1 / 32f))
.add(offset);
Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f));
BlockRayTraceResult blockraytraceresult =
world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, state);
if (blockraytraceresult == null)
continue Outer;
double distance = i - 1 + blockraytraceresult.getHitVec()
.distanceTo(rayStart);
if (limitedDistance < distance)
limitedDistance = (float) distance;
}
maxDistance = limitedDistance;
break;
}
World world = source.getWorld();
BlockPos start = source.getPos();
float max = this.maxDistance;
Direction facing = direction;
Vec3d directionVec = new Vec3d(facing.getDirectionVec());
maxDistance = getFlowLimit(world, start, max, facing);
// Determine segments with transported fluids/gases
AirCurrentSegment currentSegment = new AirCurrentSegment();
@ -257,6 +215,57 @@ public class AirCurrent {
findAffectedHandlers();
}
public static float getFlowLimit(World world, BlockPos start, float max, Direction facing) {
Vec3d directionVec = new Vec3d(facing.getDirectionVec());
Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec);
// 4 Rays test for holes in the shapes blocking the flow
float offsetDistance = .25f;
Vec3d[] offsets = new Vec3d[] { planeVec.mul(offsetDistance, offsetDistance, offsetDistance),
planeVec.mul(-offsetDistance, -offsetDistance, offsetDistance),
planeVec.mul(offsetDistance, -offsetDistance, -offsetDistance),
planeVec.mul(-offsetDistance, offsetDistance, -offsetDistance), };
float limitedDistance = 0;
// Determine the distance of the air flow
Outer: for (int i = 1; i <= max; i++) {
BlockPos currentPos = start.offset(facing, i);
if (!world.isBlockPresent(currentPos))
break;
BlockState state = world.getBlockState(currentPos);
if (shouldAlwaysPass(state))
continue;
VoxelShape voxelshape = state.getCollisionShape(world, currentPos, ISelectionContext.dummy());
if (voxelshape.isEmpty())
continue;
if (voxelshape == VoxelShapes.fullCube()) {
max = i - 1;
break;
}
for (Vec3d offset : offsets) {
Vec3d rayStart = VecHelper.getCenterOf(currentPos)
.subtract(directionVec.scale(.5f + 1 / 32f))
.add(offset);
Vec3d rayEnd = rayStart.add(directionVec.scale(1 + 1 / 32f));
BlockRayTraceResult blockraytraceresult =
world.rayTraceBlocks(rayStart, rayEnd, currentPos, voxelshape, state);
if (blockraytraceresult == null)
continue Outer;
double distance = i - 1 + blockraytraceresult.getHitVec()
.distanceTo(rayStart);
if (limitedDistance < distance)
limitedDistance = (float) distance;
}
max = limitedDistance;
break;
}
return max;
}
public void findEntities() {
caughtEntities.clear();
caughtEntities = source.getWorld()

View file

@ -31,7 +31,7 @@ public class FluidPipeAttachmentBehaviour extends TileEntityBehaviour {
}
public boolean isPipeConnectedTowards(BlockState state, Direction direction) {
FluidPipeBehaviour fluidPipeBehaviour = TileEntityBehaviour.get(tileEntity, FluidPipeBehaviour.TYPE);
FluidPipeBehaviour fluidPipeBehaviour = tileEntity.getBehaviour(FluidPipeBehaviour.TYPE);
if (fluidPipeBehaviour == null)
return false;
return fluidPipeBehaviour.isConnectedTo(state, direction);

View file

@ -23,7 +23,7 @@ public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer<Stra
@Override
protected void renderSafe(StraightPipeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
FluidPipeBehaviour pipe = TileEntityBehaviour.get(te, FluidPipeBehaviour.TYPE);
FluidPipeBehaviour pipe = te.getBehaviour(FluidPipeBehaviour.TYPE);
if (pipe == null)
return;
FluidStack fluidStack = pipe.getFluid();

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.particle;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity;
import com.simibubi.create.content.logistics.InWorldProcessing;
import com.simibubi.create.foundation.utility.ColorHelper;
@ -32,7 +33,7 @@ public class AirFlowParticle extends SimpleAnimatedParticle {
this.maxAge = 40;
canCollide = false;
selectSprite(7);
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .25f);
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, Create.random, .25f);
this.setPosition(posX + offset.x, posY + offset.y, posZ + offset.z);
this.prevPosX = posX;
this.prevPosY = posY;

View file

@ -0,0 +1,104 @@
package com.simibubi.create.content.contraptions.particle;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.particle.IAnimatedSprite;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.particle.IParticleRenderType;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.SimpleAnimatedParticle;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.util.Direction.Axis;
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 AirParticle extends SimpleAnimatedParticle {
private float originX, originY, originZ;
private float targetX, targetY, targetZ;
private float drag;
private float twirlRadius, twirlAngleOffset;
private Axis twirlAxis;
protected AirParticle(World world, AirParticleData data, double x, double y, double z, double dx, double dy,
double dz, IAnimatedSprite sprite) {
super(world, x, y, z, sprite, world.rand.nextFloat() * .5f);
particleScale *= 0.75F;
canCollide = false;
setPosition(posX, posY, posZ);
originX = (float) (prevPosX = posX);
originY = (float) (prevPosY = posY);
originZ = (float) (prevPosZ = posZ);
targetX = (float) (x + dx);
targetY = (float) (y + dy);
targetZ = (float) (z + dz);
drag = data.drag;
twirlRadius = Create.random.nextFloat() / 6;
twirlAngleOffset = Create.random.nextFloat() * 360;
twirlAxis = Create.random.nextBoolean() ? Axis.X : Axis.Z;
// speed in m/ticks
maxAge = Math.min((int) (new Vec3d(dx, dy, dz).length() / data.speed), 60);
selectSprite(7);
setAlphaF(.25f);
}
public IParticleRenderType getRenderType() {
return IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT;
}
@Override
public void tick() {
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
if (this.age++ >= this.maxAge) {
this.setExpired();
return;
}
float progress = (float) Math.pow(((float) age) / maxAge, drag);
float angle = (progress * 2 * 360 + twirlAngleOffset) % 360;
Vec3d twirl = VecHelper.rotate(new Vec3d(0, twirlRadius, 0), angle, twirlAxis);
float x = (float) (MathHelper.lerp(progress, originX, targetX) + twirl.x);
float y = (float) (MathHelper.lerp(progress, originY, targetY) + twirl.y);
float z = (float) (MathHelper.lerp(progress, originZ, targetZ) + twirl.z);
motionX = x - posX;
motionY = y - posY;
motionZ = z - posZ;
selectSpriteWithAge(field_217584_C);
this.move(this.motionX, this.motionY, this.motionZ);
}
public int getBrightnessForRender(float partialTick) {
BlockPos blockpos = new BlockPos(this.posX, this.posY, this.posZ);
return this.world.isBlockPresent(blockpos) ? WorldRenderer.getLightmapCoordinates(world, blockpos) : 0;
}
private void selectSprite(int index) {
setSprite(field_217584_C.get(index, 8));
}
public static class Factory implements IParticleFactory<AirParticleData> {
private final IAnimatedSprite spriteSet;
public Factory(IAnimatedSprite animatedSprite) {
this.spriteSet = animatedSprite;
}
public Particle makeParticle(AirParticleData data, World worldIn, double x, double y, double z, double xSpeed,
double ySpeed, double zSpeed) {
return new AirParticle(worldIn, data, x, y, z, xSpeed, ySpeed, zSpeed, this.spriteSet);
}
}
}

View file

@ -0,0 +1,73 @@
package com.simibubi.create.content.contraptions.particle;
import java.util.Locale;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.simibubi.create.AllParticleTypes;
import net.minecraft.client.particle.ParticleManager.IParticleMetaFactory;
import net.minecraft.network.PacketBuffer;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class AirParticleData implements IParticleData, ICustomParticle<AirParticleData> {
public static final IParticleData.IDeserializer<AirParticleData> DESERIALIZER =
new IParticleData.IDeserializer<AirParticleData>() {
public AirParticleData deserialize(ParticleType<AirParticleData> particleTypeIn, StringReader reader)
throws CommandSyntaxException {
reader.expect(' ');
float drag = reader.readFloat();
reader.expect(' ');
float speed = reader.readFloat();
return new AirParticleData(drag, speed);
}
public AirParticleData read(ParticleType<AirParticleData> particleTypeIn, PacketBuffer buffer) {
return new AirParticleData(buffer.readFloat(), buffer.readFloat());
}
};
float drag;
float speed;
public AirParticleData(float drag, float speed) {
this.drag = drag;
this.speed = speed;
}
public AirParticleData() {
this(0, 0);
}
@Override
public ParticleType<?> getType() {
return AllParticleTypes.AIR.get();
}
@Override
public void write(PacketBuffer buffer) {
buffer.writeFloat(drag);
buffer.writeFloat(speed);
}
@Override
public String getParameters() {
return String.format(Locale.ROOT, "%s %f %f", AllParticleTypes.AIR.parameter(), drag, speed);
}
@Override
public IDeserializer<AirParticleData> getDeserializer() {
return DESERIALIZER;
}
@Override
@OnlyIn(Dist.CLIENT)
public IParticleMetaFactory<AirParticleData> getFactory() {
return AirParticle.Factory::new;
}
}

View file

@ -1,8 +1,11 @@
package com.simibubi.create.content.contraptions.particle;
import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.particle.IParticleRenderType;
import net.minecraft.client.particle.Particle;
@ -15,7 +18,6 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
public class CubeParticle extends Particle {

View file

@ -1,5 +1,7 @@
package com.simibubi.create.content.contraptions.particle;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.particle.IAnimatedSprite;
import net.minecraft.client.particle.IParticleFactory;
@ -9,8 +11,6 @@ import net.minecraft.client.particle.SimpleAnimatedParticle;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class HeaterParticle extends SimpleAnimatedParticle {

View file

@ -360,9 +360,11 @@ public class BeltTileEntity extends KineticTileEntity {
private void applyToAllItems(float maxDistanceFromCenter,
Function<TransportedItemStack, TransportedResult> processFunction) {
BeltTileEntity controller = getControllerTE();
if (controller != null)
controller.getInventory()
.applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction);
if (controller == null)
return;
BeltInventory inventory = controller.getInventory();
if (inventory != null)
inventory.applyToEachWithin(index + .5f, maxDistanceFromCenter, processFunction);
}
private Vec3d getWorldPositionOf(TransportedItemStack transported) {

View file

@ -3,13 +3,13 @@ package com.simibubi.create.content.contraptions.relays.belt.transport;
import com.simibubi.create.content.contraptions.relays.belt.BeltHelper;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InvManipulationBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
@ -31,36 +31,38 @@ public class BeltFunnelInteractionHandler {
BlockState funnelState = world.getBlockState(funnelPos);
if (!(funnelState.getBlock() instanceof BeltFunnelBlock))
continue;
if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) != beltInventory.belt.getMovementFacing()
.getOpposite())
Direction funnelFacing = funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING);
Direction movementFacing = beltInventory.belt.getMovementFacing();
boolean blocking = funnelFacing == movementFacing.getOpposite();
if (funnelFacing == movementFacing)
continue;
currentItem.beltPosition = segment + .5f;
if (world.isRemote)
return true;
return blocking;
if (funnelState.get(BeltFunnelBlock.PUSHING))
return true;
return blocking;
if (funnelState.has(BeltFunnelBlock.POWERED) && funnelState.get(BeltFunnelBlock.POWERED))
return true;
return blocking;
TileEntity te = world.getTileEntity(funnelPos);
if (!(te instanceof FunnelTileEntity))
return true;
FunnelTileEntity funnelTE = (FunnelTileEntity) te;
InvManipulationBehaviour inserting = TileEntityBehaviour.get(funnelTE, InvManipulationBehaviour.TYPE);
FilteringBehaviour filtering = TileEntityBehaviour.get(funnelTE, FilteringBehaviour.TYPE);
InvManipulationBehaviour inserting = funnelTE.getBehaviour(InvManipulationBehaviour.TYPE);
FilteringBehaviour filtering = funnelTE.getBehaviour(FilteringBehaviour.TYPE);
if (inserting == null)
return true;
return blocking;
if (filtering != null && !filtering.test(currentItem.stack))
return true;
return blocking;
ItemStack before = currentItem.stack.copy();
ItemStack remainder = inserting.insert(before);
if (before.equals(remainder, false))
return true;
return blocking;
funnelTE.flap(true);
currentItem.stack = remainder;

View file

@ -37,8 +37,7 @@ public class BeltTunnelInteractionHandler {
if (nextTunnel instanceof BrassTunnelTileEntity) {
BrassTunnelTileEntity brassTunnel = (BrassTunnelTileEntity) nextTunnel;
if (brassTunnel.hasDistributionBehaviour()) {
if (!brassTunnel.getStackToDistribute()
.isEmpty())
if (!brassTunnel.canTakeItems())
return true;
if (onServer) {
brassTunnel.setStackToDistribute(current.stack);

View file

@ -168,10 +168,14 @@ public class BeltTunnelBlock extends Block implements ITE<BeltTunnelTileEntity>,
Direction fw = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
BlockState blockState1 = reader.getBlockState(pos.offset(fw));
BlockState blockState2 = reader.getBlockState(pos.offset(fw.getOpposite()));
boolean funnel1 = blockState1.getBlock() instanceof BeltFunnelBlock
&& blockState1.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED
&& blockState1.get(BeltFunnelBlock.HORIZONTAL_FACING) == fw.getOpposite();
boolean funnel2 = blockState2.getBlock() instanceof BeltFunnelBlock
&& blockState2.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED
&& blockState2.get(BeltFunnelBlock.HORIZONTAL_FACING) == fw;
boolean valid1 = blockState1.getBlock() instanceof BeltTunnelBlock || funnel1;
boolean valid2 = blockState2.getBlock() instanceof BeltTunnelBlock || funnel2;
boolean canHaveWindow = valid1 && valid2 && !(funnel1 && funnel2);

View file

@ -130,7 +130,8 @@ public class BeltTunnelTileEntity extends SmartTileEntity {
BlockState funnelState = world.getBlockState(getPos().offset(direction));
if (funnelState.getBlock() instanceof BeltFunnelBlock)
if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite())
if (funnelState.get(BeltFunnelBlock.SHAPE) == BeltFunnelBlock.Shape.EXTENDED
&& funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite())
continue;
flaps.put(direction, new InterpolatedChasingValue().start(.25f)

View file

@ -31,7 +31,7 @@ public class BrassTunnelItemHandler implements IItemHandler {
return beltCapability.orElse(null).insertItem(slot, stack, simulate);
}
if (!te.stackToDistribute.isEmpty())
if (!te.canTakeItems())
return stack;
if (!simulate)
te.setStackToDistribute(stack);

View file

@ -1,8 +1,10 @@
package com.simibubi.create.content.logistics.block.belts.tunnel;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.annotation.Nullable;
@ -58,6 +60,9 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
int distributionDistanceRight;
int previousOutputIndex;
private boolean syncedOutputActive;
private Set<BrassTunnelTileEntity> syncSet;
protected ScrollOptionBehaviour<SelectionMode> selectionMode;
private LazyOptional<IItemHandler> beltCapability;
private LazyOptional<IItemHandler> tunnelCapability;
@ -65,10 +70,12 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
public BrassTunnelTileEntity(TileEntityType<? extends BeltTunnelTileEntity> type) {
super(type);
distributionTargets = new ArrayList<>();
syncSet = new HashSet<>();
stackToDistribute = ItemStack.EMPTY;
beltCapability = LazyOptional.empty();
tunnelCapability = LazyOptional.of(() -> new BrassTunnelItemHandler(this));
previousOutputIndex = 0;
syncedOutputActive = false;
}
@Override
@ -100,7 +107,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
distributionProgress--;
if (beltBelow == null || beltBelow.getSpeed() == 0)
return;
if (stackToDistribute.isEmpty())
if (stackToDistribute.isEmpty() && !syncedOutputActive)
return;
if (world.isRemote)
return;
@ -109,7 +116,28 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
distributionTargets.clear();
distributionDistanceLeft = 0;
distributionDistanceRight = 0;
for (Pair<BrassTunnelTileEntity, Direction> pair : gatherValidOutputs()) {
syncSet.clear();
List<Pair<BrassTunnelTileEntity, Direction>> validOutputs = gatherValidOutputs();
if (selectionMode.get() == SelectionMode.SYNCHRONIZE) {
boolean allEmpty = true;
boolean allFull = true;
for (BrassTunnelTileEntity te : syncSet) {
boolean hasStack = !te.stackToDistribute.isEmpty();
allEmpty &= !hasStack;
allFull &= hasStack;
}
final boolean notifySyncedOut = !allEmpty;
if (allFull || allEmpty)
syncSet.forEach(te -> te.syncedOutputActive = notifySyncedOut);
}
if (validOutputs == null)
return;
if (stackToDistribute.isEmpty())
return;
for (Pair<BrassTunnelTileEntity, Direction> pair : validOutputs) {
BrassTunnelTileEntity tunnel = pair.getKey();
Direction output = pair.getValue();
if (insertIntoTunnel(tunnel, output, stackToDistribute, true) == null)
@ -125,8 +153,10 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
if (distributionTargets.isEmpty())
return;
if (selectionMode.get() != SelectionMode.SYNCHRONIZE || syncedOutputActive) {
distributionProgress = 10;
sendData();
}
return;
}
@ -162,7 +192,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
if (mode == SelectionMode.RANDOMIZE)
indexStart = rand.nextInt(amountTargets);
if (mode == SelectionMode.PREFER_NEAREST)
if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE)
indexStart = 0;
ItemStack toDistribute = null;
@ -290,7 +320,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
public void initialize() {
if (filtering == null) {
filtering = createSidedFilter();
putBehaviour(filtering);
attachBehaviourLate(filtering);
}
super.initialize();
}
@ -322,22 +352,29 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
private List<Pair<BrassTunnelTileEntity, Direction>> gatherValidOutputs() {
List<Pair<BrassTunnelTileEntity, Direction>> validOutputs = new ArrayList<>();
boolean synchronize = selectionMode.get() == SelectionMode.SYNCHRONIZE;
addValidOutputsOf(this, validOutputs);
for (boolean left : Iterate.trueAndFalse) {
BrassTunnelTileEntity adjacent = this;
while (adjacent != null) {
if (!world.isAreaLoaded(adjacent.getPos(), 1))
return null;
adjacent = adjacent.getAdjacent(left);
if (adjacent != null)
if (adjacent == null)
continue;
addValidOutputsOf(adjacent, validOutputs);
}
}
if (!syncedOutputActive && synchronize)
return null;
return validOutputs;
}
private void addValidOutputsOf(BrassTunnelTileEntity tunnelTE,
List<Pair<BrassTunnelTileEntity, Direction>> validOutputs) {
syncSet.add(tunnelTE);
BeltTileEntity below = BeltHelper.getSegmentTE(world, tunnelTE.pos.down());
if (below == null)
return;
@ -400,6 +437,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
@Override
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("SyncedOutput", syncedOutputActive);
compound.putBoolean("ConnectedLeft", connectedLeft);
compound.putBoolean("ConnectedRight", connectedRight);
@ -424,6 +462,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
boolean wasConnectedLeft = connectedLeft;
boolean wasConnectedRight = connectedRight;
syncedOutputActive = compound.getBoolean("SyncedOutput");
connectedLeft = compound.getBoolean("ConnectedLeft");
connectedRight = compound.getBoolean("ConnectedRight");
stackToDistribute = ItemStack.read(compound.getCompound("StackToDistribute"));
@ -549,6 +588,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
FORCED_ROUND_ROBIN(AllIcons.I_TUNNEL_FORCED_ROUND_ROBIN),
PREFER_NEAREST(AllIcons.I_TUNNEL_PREFER_NEAREST),
RANDOMIZE(AllIcons.I_TUNNEL_RANDOMIZE),
SYNCHRONIZE(AllIcons.I_TUNNEL_SYNCHRONIZE),
;
@ -571,4 +611,8 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
}
}
public boolean canTakeItems() {
return stackToDistribute.isEmpty() && !syncedOutputActive;
}
}

View file

@ -147,6 +147,13 @@ public class ChuteBlock extends Block implements IWrenchable, ITE<ChuteTileEntit
return updateDiagonalState(state, above, world, pos);
}
@Override
public void neighborChanged(BlockState p_220069_1_, World world, BlockPos pos, Block p_220069_4_,
BlockPos neighbourPos, boolean p_220069_6_) {
if (pos.down().equals(neighbourPos))
withTileEntityDo(world, pos, ChuteTileEntity::blockBelowChanged);
}
@Override
public boolean isValidPosition(BlockState state, IWorldReader world, BlockPos pos) {
BlockState above = world.getBlockState(pos.up());

View file

@ -27,7 +27,8 @@ public class ChuteRenderer extends SafeTileEntityRenderer<ChuteTileEntity> {
BlockState blockState = te.getBlockState();
if (blockState.get(ChuteBlock.FACING) != Direction.DOWN)
return;
if (blockState.get(ChuteBlock.SHAPE) != Shape.WINDOW)
if (blockState.get(ChuteBlock.SHAPE) != Shape.WINDOW
&& (te.bottomPullDistance == 0 || te.itemPosition.get(partialTicks) > .5f))
return;
ItemRenderer itemRenderer = Minecraft.getInstance()

View file

@ -7,18 +7,25 @@ import javax.annotation.Nullable;
import com.google.common.base.Predicates;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.fan.AirCurrent;
import com.simibubi.create.content.contraptions.components.fan.EncasedFanBlock;
import com.simibubi.create.content.contraptions.components.fan.EncasedFanTileEntity;
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.contraptions.particle.AirParticleData;
import com.simibubi.create.content.logistics.block.chute.ChuteBlock.Shape;
import com.simibubi.create.content.logistics.block.funnel.BrassFunnelBlock;
import com.simibubi.create.content.logistics.block.funnel.FunnelBlock;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.widgets.InterpolatedValue;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.TransportedItemStackHandlerBehaviour.TransportedResult;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
@ -33,6 +40,7 @@ import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
@ -54,6 +62,13 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
LazyOptional<IItemHandler> lazyHandler;
boolean canPickUpItems;
float bottomPullDistance;
int airCurrentUpdateCooldown;
int entitySearchCooldown;
boolean updateAirFlow;
TransportedItemStackHandlerBehaviour beltBelow;
float beltBelowOffset;
LazyOptional<IItemHandler> capAbove;
LazyOptional<IItemHandler> capBelow;
@ -66,6 +81,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
canPickUpItems = false;
capAbove = LazyOptional.empty();
capBelow = LazyOptional.empty();
bottomPullDistance = 0;
updateAirFlow = true;
}
@Override
@ -94,14 +111,25 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
@Override
public void initialize() {
super.initialize();
onAdded();
}
@Override
public AxisAlignedBB getRenderBoundingBox() {
return new AxisAlignedBB(pos).expand(0, -3, 0);
}
@Override
public void tick() {
super.tick();
canPickUpItems = canDirectlyInsert();
float itemMotion = getItemMotion();
if (itemMotion != 0 && world.isRemote)
spawnParticles(itemMotion);
if (itemMotion > 0)
tickAirStreamFromBelow(itemMotion);
if (item.isEmpty()) {
if (itemMotion < 0)
@ -138,6 +166,127 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
itemPosition.set(nextOffset);
}
private void tickAirStreamFromBelow(float itemSpeed) {
if (world.isRemote)
return;
if (airCurrentUpdateCooldown-- <= 0) {
airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get();
updateAirFlow = true;
}
if (bottomPullDistance > 0 && getItem().isEmpty() && entitySearchCooldown-- <= 0) {
entitySearchCooldown = 5;
Vec3d center = VecHelper.getCenterOf(pos);
AxisAlignedBB searchArea =
new AxisAlignedBB(center.add(0, -bottomPullDistance - 0.5, 0), center.add(0, -0.5, 0)).grow(.45f);
for (ItemEntity itemEntity : world.getEntitiesWithinAABB(ItemEntity.class, searchArea)) {
setItem(itemEntity.getItem()
.copy(),
(float) (itemEntity.getBoundingBox()
.getCenter().y - pos.getY()));
itemEntity.remove();
break;
}
}
if (getItem().isEmpty() && beltBelow != null) {
beltBelow.handleCenteredProcessingOnAllItems(.5f, ts -> {
if (getItem().isEmpty()) {
setItem(ts.stack.copy(), -beltBelowOffset);
return TransportedResult.removeItem();
}
return TransportedResult.doNothing();
});
}
if (!updateAirFlow)
return;
float speed = pull - push;
float flowLimit = 0;
updateAirFlow = false;
beltBelow = null;
float maxPullDistance;
if (speed >= 128)
maxPullDistance = 3;
else if (speed >= 64)
maxPullDistance = 2;
else if (speed >= 32)
maxPullDistance = 1;
else
maxPullDistance = MathHelper.lerp(speed / 32, 0, 1);
if (AllBlocks.CHUTE.has(world.getBlockState(pos.down())))
maxPullDistance = 0;
flowLimit = maxPullDistance;
if (flowLimit > 0)
flowLimit = AirCurrent.getFlowLimit(world, pos, maxPullDistance, Direction.DOWN);
for (int i = 1; i <= flowLimit + 1; i++) {
TransportedItemStackHandlerBehaviour behaviour =
TileEntityBehaviour.get(world, pos.down(i), TransportedItemStackHandlerBehaviour.TYPE);
if (behaviour == null)
continue;
beltBelow = behaviour;
beltBelowOffset = i - 1;
break;
}
if (bottomPullDistance == flowLimit)
return;
this.bottomPullDistance = flowLimit;
sendData();
}
public void blockBelowChanged() {
updateAirFlow = true;
}
private void spawnParticles(float itemMotion) {
BlockState blockState = getBlockState();
boolean up = itemMotion > 0;
float absMotion = up ? itemMotion : -itemMotion;
if (blockState == null || !(blockState.getBlock() instanceof ChuteBlock))
return;
if (push == 0 && pull == 0)
return;
if (up
&& (blockState.get(ChuteBlock.FACING) == Direction.DOWN
|| blockState.get(ChuteBlock.SHAPE) == Shape.INTERSECTION)
&& BlockHelper.noCollisionInSpace(world, pos.up()))
spawnAirFlow(1, 2, absMotion, .5f);
if (blockState.get(ChuteBlock.FACING) != Direction.DOWN)
return;
if (blockState.get(ChuteBlock.SHAPE) == Shape.WINDOW)
spawnAirFlow(up ? 0 : 1, up ? 1 : 0, absMotion, 1);
if (!up && BlockHelper.noCollisionInSpace(world, pos.down()))
spawnAirFlow(0, -1, absMotion, .5f);
if (up && bottomPullDistance > 0) {
spawnAirFlow(-bottomPullDistance, 0, absMotion, 2);
spawnAirFlow(-bottomPullDistance, 0, absMotion, 2);
}
}
private void spawnAirFlow(float verticalStart, float verticalEnd, float motion, float drag) {
AirParticleData airParticleData = new AirParticleData(drag, motion);
Vec3d origin = new Vec3d(pos);
float xOff = Create.random.nextFloat() * .5f + .25f;
float zOff = Create.random.nextFloat() * .5f + .25f;
Vec3d v = origin.add(xOff, verticalStart, zOff);
Vec3d d = origin.add(xOff, verticalEnd, zOff)
.subtract(v);
if (Create.random.nextFloat() < 2 * motion)
world.addOptionalParticle(airParticleData, v.x, v.y, v.z, d.x, d.y, d.z);
}
private void handleInputFromAbove() {
if (!capAbove.isPresent())
capAbove = grabCapability(Direction.UP);
@ -314,6 +463,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
compound.putFloat("ItemPosition", itemPosition.value);
compound.putFloat("Pull", pull);
compound.putFloat("Push", push);
compound.putFloat("BottomAirFlowDistance", bottomPullDistance);
super.write(compound, clientPacket);
}
@ -324,6 +474,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition");
pull = compound.getFloat("Pull");
push = compound.getFloat("Push");
bottomPullDistance = compound.getFloat("BottomAirFlowDistance");
super.read(compound, clientPacket);
if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) {
@ -339,11 +490,11 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
public float getItemMotion() {
// Chutes per second
final float fanSpeedModifier = 1 / 64f;
final float maxUpwardItemSpeed = 20f;
final float maxItemSpeed = 20f;
final float gravity = 4f;
float upwardMotion = (push + pull) * fanSpeedModifier;
return (upwardMotion == 0 ? -gravity : MathHelper.clamp(upwardMotion, 0, maxUpwardItemSpeed)) / 20f;
float motion = (push + pull) * fanSpeedModifier;
return (MathHelper.clamp(motion, -maxItemSpeed, maxItemSpeed) + (motion <= 0 ? -gravity : 0)) / 20f;
}
public void onRemoved(BlockState chuteState) {
@ -374,6 +525,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
if (pull == totalPull)
return;
pull = totalPull;
updateAirFlow = true;
sendData();
ChuteTileEntity targetChute = getTargetChute(getBlockState());
if (targetChute != null)
@ -384,6 +536,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
float totalPush = calculatePush(branchCount);
if (push == totalPush)
return;
updateAirFlow = true;
push = totalPush;
sendData();
propagatePush();
@ -401,7 +554,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
TileEntity te = world.getTileEntity(pos.up());
if (te instanceof EncasedFanTileEntity && !te.isRemoved()) {
EncasedFanTileEntity fan = (EncasedFanTileEntity) te;
return Math.abs(fan.getSpeed());
return fan.getSpeed();
}
}
@ -421,7 +574,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
TileEntity te = world.getTileEntity(pos.down());
if (te instanceof EncasedFanTileEntity && !te.isRemoved()) {
EncasedFanTileEntity fan = (EncasedFanTileEntity) te;
return Math.abs(fan.getSpeed());
return fan.getSpeed();
}
}

View file

@ -98,10 +98,7 @@ public class DepotRenderer extends SafeTileEntityRenderer<DepotTileEntity> {
ms.push();
msr.rotateY(angle);
if (!blockItem && !renderUpright) {
ms.translate(0, -.09375, 0);
msr.rotateX(90);
}
if (renderUpright) {
Entity renderViewEntity = Minecraft.getInstance().renderViewEntity;
if (renderViewEntity != null) {
@ -111,7 +108,7 @@ public class DepotRenderer extends SafeTileEntityRenderer<DepotTileEntity> {
float yRot = (float) MathHelper.atan2(diff.z, -diff.x);
ms.multiply(Vector3f.POSITIVE_Y.getRadialQuaternion((float) (yRot - Math.PI / 2)));
}
ms.translate(0, 3 / 32d, 1/16f);
ms.translate(0, 3 / 32d, 1 / 16f);
}
for (int i = 0; i <= count; i++) {
@ -119,6 +116,10 @@ public class DepotRenderer extends SafeTileEntityRenderer<DepotTileEntity> {
if (blockItem)
ms.translate(r.nextFloat() * .0625f * i, 0, r.nextFloat() * .0625f * i);
ms.scale(.5f, .5f, .5f);
if (!blockItem && !renderUpright) {
ms.translate(0, -3 / 16f, 0);
msr.rotateX(90);
}
itemRenderer.renderItem(itemStack, TransformType.FIXED, light, overlay, ms, buffer);
ms.pop();

View file

@ -33,6 +33,7 @@ public class DepotTileEntity extends SmartTileEntity {
DepotItemHandler itemHandler;
LazyOptional<DepotItemHandler> lazyItemHandler;
private TransportedItemStackHandlerBehaviour transportedHandler;
public DepotTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
@ -75,9 +76,8 @@ public class DepotTileEntity extends SmartTileEntity {
boolean wasLocked = heldItem.locked;
ItemStack previousItem = heldItem.stack;
TransportedItemStackHandlerBehaviour handler = getBehaviour(TransportedItemStackHandlerBehaviour.TYPE);
ProcessingResult result = wasLocked ? processingBehaviour.handleHeldItem(heldItem, handler)
: processingBehaviour.handleReceivedItem(heldItem, handler);
ProcessingResult result = wasLocked ? processingBehaviour.handleHeldItem(heldItem, transportedHandler)
: processingBehaviour.handleReceivedItem(heldItem, transportedHandler);
if (result == ProcessingResult.REMOVE) {
heldItem = null;
sendData();
@ -116,8 +116,9 @@ public class DepotTileEntity extends SmartTileEntity {
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new DirectBeltInputBehaviour(this).setInsertionHandler(this::tryInsertingFromSide));
behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
.withStackPlacement(this::getWorldPositionOf));
transportedHandler = new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
.withStackPlacement(this::getWorldPositionOf);
behaviours.add(transportedHandler);
}
public ItemStack getHeldItemStack() {

View file

@ -101,16 +101,19 @@ public abstract class BeltFunnelBlock extends HorizontalInteractionFunnelBlock {
return false;
if (!BeltBlock.canTransport(stateBelow))
return false;
if (stateBelow.get(BeltBlock.HORIZONTAL_FACING)
.getAxis() != state.get(HORIZONTAL_FACING)
.getAxis())
return false;
return true;
}
public static BlockState updateShape(BlockState state, IBlockReader world, BlockPos pos) {
state = state.with(SHAPE, Shape.RETRACTED);
BlockState neighbour = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING)));
Direction horizontalFacing = state.get(HORIZONTAL_FACING);
BlockState below = world.getBlockState(pos.down());
if (below.getBlock() instanceof BeltBlock && below.get(BeltBlock.HORIZONTAL_FACING)
.getAxis() != horizontalFacing.getAxis())
return state;
BlockState neighbour = world.getBlockState(pos.offset(horizontalFacing));
if (canConnectTo(state, neighbour))
return state.with(SHAPE, Shape.EXTENDED);
return state;

View file

@ -1,10 +1,13 @@
package com.simibubi.create.content.logistics.block.funnel;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock.Shape;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
@ -26,16 +29,19 @@ public class FunnelTileEntity extends SmartTileEntity {
private FilteringBehaviour filtering;
private InvManipulationBehaviour invManipulation;
private InvManipulationBehaviour autoExtractor;
private int extractionCooldown;
int sendFlap;
InterpolatedChasingValue flap;
static enum Mode {
INVALID, PAUSED, COLLECT, BELT
INVALID, PAUSED, COLLECT, PUSHING_TO_BELT, TAKING_FROM_BELT, HOPPER
}
public FunnelTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
extractionCooldown = 0;
flap = new InterpolatedChasingValue().start(.25f)
.target(0)
.withSpeed(.05f);
@ -47,8 +53,12 @@ public class FunnelTileEntity extends SmartTileEntity {
return Mode.INVALID;
if (state.has(BlockStateProperties.POWERED) && state.get(BlockStateProperties.POWERED))
return Mode.PAUSED;
if (state.getBlock() instanceof BeltFunnelBlock)
return Mode.BELT;
if (FunnelBlock.getFunnelFacing(state) == Direction.UP && autoExtractor.hasInventory())
return Mode.HOPPER;
if (state.getBlock() instanceof BeltFunnelBlock) {
boolean pushing = state.get(BeltFunnelBlock.PUSHING);
return pushing ? Mode.PUSHING_TO_BELT : Mode.TAKING_FROM_BELT;
}
return Mode.COLLECT;
}
@ -57,20 +67,52 @@ public class FunnelTileEntity extends SmartTileEntity {
super.tick();
flap.tick();
Mode mode = determineCurrentMode();
if (mode == Mode.BELT)
tickAsBeltFunnel();
if (world.isRemote)
return;
// Redstone resets the extraction cooldown
if (mode == Mode.PAUSED)
extractionCooldown = 0;
if (mode == Mode.TAKING_FROM_BELT)
tickAsPullingBeltFunnel();
if (extractionCooldown > 0) {
extractionCooldown--;
return;
}
public void tickAsBeltFunnel() {
BlockState blockState = getBlockState();
Direction facing = blockState.get(BeltFunnelBlock.HORIZONTAL_FACING);
if (world.isRemote)
if (mode == Mode.PUSHING_TO_BELT)
activateExtractingBeltFunnel();
if (mode == Mode.HOPPER)
activateHopper();
}
private void activateHopper() {
if (!invManipulation.hasInventory())
return;
int amountToExtract = autoExtractor.getAmountFromFilter();
if (!filtering.isActive())
amountToExtract = 1;
Predicate<ItemStack> filter = s -> !filtering.isActive() || filtering.test(s);
Function<ItemStack, Integer> amountThreshold = s -> s.getMaxStackSize() - invManipulation.simulate()
.insert(s)
.getCount();
if (amountToExtract != -1 && !invManipulation.simulate()
.insert(autoExtractor.simulate()
.extract(amountToExtract, filter))
.isEmpty())
return;
Boolean pushing = blockState.get(BeltFunnelBlock.PUSHING);
if (!pushing) {
ItemStack stack = autoExtractor.extract(amountToExtract, filter, amountThreshold);
if (stack.isEmpty())
return;
invManipulation.insert(stack);
startCooldown();
}
private void tickAsPullingBeltFunnel() {
// Belts handle insertion from their side
if (AllBlocks.BELT.has(world.getBlockState(pos.down())))
return;
@ -79,23 +121,33 @@ public class FunnelTileEntity extends SmartTileEntity {
if (handler == null)
return;
handler.handleCenteredProcessingOnAllItems(1 / 32f, this::collectFromHandler);
return;
}
private void activateExtractingBeltFunnel() {
BlockState blockState = getBlockState();
Direction facing = blockState.get(BeltFunnelBlock.HORIZONTAL_FACING);
DirectBeltInputBehaviour inputBehaviour =
TileEntityBehaviour.get(world, pos.down(), DirectBeltInputBehaviour.TYPE);
if (inputBehaviour == null)
return;
if (!inputBehaviour.canInsertFromSide(facing))
return;
ItemStack stack = invManipulation.extract(invManipulation.getAmountFromFilter(),
s -> inputBehaviour.handleInsertion(s, facing, true)
int amountToExtract = invManipulation.getAmountFromFilter();
if (!filtering.isActive())
amountToExtract = 1;
ItemStack stack = invManipulation.extract(amountToExtract, s -> inputBehaviour.handleInsertion(s, facing, true)
.isEmpty());
if (stack.isEmpty())
return;
flap(false);
inputBehaviour.handleInsertion(stack, facing, false);
startCooldown();
}
private int startCooldown() {
return extractionCooldown = AllConfigs.SERVER.logistics.defaultExtractionTimer.get();
}
private TransportedResult collectFromHandler(TransportedItemStack stack) {
@ -120,18 +172,27 @@ public class FunnelTileEntity extends SmartTileEntity {
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
invManipulation = new InvManipulationBehaviour(this, InterfaceProvider.oppositeOfBlockFacing());
behaviours.add(invManipulation);
autoExtractor = InvManipulationBehaviour.forExtraction(this, InterfaceProvider.towardBlockFacing());
behaviours.add(autoExtractor);
filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning()).showCountWhen(() -> {
BlockState blockState = getBlockState();
return blockState.getBlock() instanceof HorizontalInteractionFunnelBlock
&& blockState.get(HorizontalInteractionFunnelBlock.PUSHING);
});
filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning());
filtering.showCountWhen(this::supportsAmountOnFilter);
filtering.onlyActiveWhen(this::supportsFiltering);
behaviours.add(filtering);
behaviours.add(new DirectBeltInputBehaviour(this).onlyInsertWhen(this::supportsDirectBeltInput)
.setInsertionHandler(this::handleDirectBeltInput));
}
private boolean supportsAmountOnFilter() {
BlockState blockState = getBlockState();
boolean pushingToBelt = blockState.getBlock() instanceof HorizontalInteractionFunnelBlock
&& blockState.get(HorizontalInteractionFunnelBlock.PUSHING);
boolean hopper = FunnelBlock.getFunnelFacing(blockState) == Direction.UP && invManipulation.hasInventory()
&& autoExtractor.hasInventory();
return pushingToBelt || hopper;
}
private boolean supportsDirectBeltInput(Direction side) {
BlockState blockState = getBlockState();
if (blockState == null)
@ -171,6 +232,7 @@ public class FunnelTileEntity extends SmartTileEntity {
@Override
protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound, clientPacket);
compound.putInt("TransferCooldown", extractionCooldown);
if (clientPacket && sendFlap != 0) {
compound.putInt("Flap", sendFlap);
sendFlap = 0;
@ -180,6 +242,7 @@ public class FunnelTileEntity extends SmartTileEntity {
@Override
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
extractionCooldown = compound.getInt("TransferCooldown");
if (clientPacket && compound.contains("Flap")) {
int direction = compound.getInt("Flap");
flap.set(direction);

View file

@ -10,6 +10,7 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
@ -21,6 +22,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
@ -55,6 +59,17 @@ public class ArmInteractionPointHandler {
}
selected.cycleMode();
PlayerEntity player = event.getPlayer();
if (player != null) {
String key = selected.mode == Mode.DEPOSIT ? "mechanical_arm.deposit_to" : "mechanical_arm.extract_from";
TextFormatting colour = selected.mode == Mode.DEPOSIT ? TextFormatting.GOLD : TextFormatting.AQUA;
String translatedBlock = new TranslationTextComponent(selected.state.getBlock()
.getTranslationKey()).getFormattedText();
player.sendStatusMessage(
new StringTextComponent(colour + Lang.translate(key, TextFormatting.WHITE + translatedBlock + colour)),
true);
}
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
}
@ -75,6 +90,20 @@ public class ArmInteractionPointHandler {
public static void flushSettings(BlockPos pos) {
if (currentItem == null)
return;
int removed = 0;
for (Iterator<ArmInteractionPoint> iterator = currentSelection.iterator(); iterator.hasNext();) {
ArmInteractionPoint point = iterator.next();
if (point.pos.withinDistance(pos, ArmTileEntity.getRange()))
continue;
iterator.remove();
removed++;
}
if (removed > 0)
Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(
TextFormatting.RED + Lang.translate("mechanical_arm.points_outside_range", removed)), true);
AllPackets.channel.sendToServer(new ArmPlacementPacket(currentSelection, pos));
currentSelection.clear();
currentItem = null;

View file

@ -9,6 +9,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Jukebox;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.widgets.InterpolatedAngle;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
@ -328,6 +329,8 @@ public class ArmTileEntity extends KineticTileEntity {
protected void initInteractionPoints() {
if (!updateInteractionPoints || interactionPointTag == null)
return;
if (!world.isAreaLoaded(pos, getRange() + 1))
return;
inputs.clear();
outputs.clear();
for (INBT inbt : interactionPointTag) {
@ -348,6 +351,10 @@ public class ArmTileEntity extends KineticTileEntity {
public void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound, clientPacket);
if (updateInteractionPoints) {
compound.put("InteractionPoints", interactionPointTag);
} else {
ListNBT pointsNBT = new ListNBT();
inputs.stream()
.map(ArmInteractionPoint::serialize)
@ -355,9 +362,10 @@ public class ArmTileEntity extends KineticTileEntity {
outputs.stream()
.map(ArmInteractionPoint::serialize)
.forEach(pointsNBT::add);
compound.put("InteractionPoints", pointsNBT);
}
NBTHelper.writeEnum(compound, "Phase", phase);
compound.put("InteractionPoints", pointsNBT);
compound.put("HeldItem", heldItem.serializeNBT());
compound.putInt("TargetPointIndex", chasedPointIndex);
compound.putFloat("MovementProgress", chasedPointProgress);
@ -395,6 +403,10 @@ public class ArmTileEntity extends KineticTileEntity {
}
}
public static int getRange() {
return AllConfigs.SERVER.logistics.mechanicalArmRange.get();
}
private class SelectionModeValueBox extends CenteredSideValueBoxTransform {
public SelectionModeValueBox() {

View file

@ -93,7 +93,7 @@ public class RedstoneLinkTileEntity extends SmartTileEntity {
removeBehaviour(LinkBehaviour.TYPE);
createLink();
link.copyItemsFrom(prevlink);
putBehaviour(link);
attachBehaviourLate(link);
}
if (transmitter)

View file

@ -2,9 +2,9 @@ package com.simibubi.create.foundation.config;
public class CLogistics extends ConfigBase {
public ConfigInt extractorDelay = i(20, 10, "extractorDelay", Comments.extractorDelay);
public ConfigInt extractorInventoryScanDelay = i(40, 10, "extractorInventoryScanDelay", Comments.extractorInventoryScanDelay);
public ConfigInt extractorAmount = i(16, 1, 64, "extractorAmount", Comments.extractorAmount);
public ConfigInt defaultExtractionLimit = i(64, 1, 64, "defaultExtractionLimit", Comments.defaultExtractionLimit);
public ConfigInt defaultExtractionTimer = i(8, 1, "defaultExtractionTimer", Comments.defaultExtractionTimer);
public ConfigInt mechanicalArmRange = i(5, 1, "mechanicalArmRange", Comments.mechanicalArmRange);
public ConfigInt linkRange = i(128, 1, "linkRange", Comments.linkRange);
@Override
@ -13,10 +13,12 @@ public class CLogistics extends ConfigBase {
}
private static class Comments {
static String extractorDelay = "The amount of game ticks an Extractor waits after pulling an item successfully.";
static String extractorInventoryScanDelay = "The amount of game ticks an Extractor waits before checking again if the attached inventory contains items to extract.";
static String extractorAmount = "The amount of items an extractor pulls at a time without an applied filter.";
static String defaultExtractionLimit =
"The maximum amount of items a funnel pulls at a time without an applied filter.";
static String defaultExtractionTimer =
"The amount of ticks a funnel waits between item transferrals, when it is not re-activated by redstone.";
static String linkRange = "Maximum possible range in blocks of redstone link connections.";
static String mechanicalArmRange = "Maximum distance in blocks a Mechanical Arm can reach across.";
}
}

View file

@ -83,6 +83,7 @@ public class AllIcons {
I_TUNNEL_FORCED_ROUND_ROBIN = next(),
I_TUNNEL_PREFER_NEAREST = next(),
I_TUNNEL_RANDOMIZE = next(),
I_TUNNEL_SYNCHRONIZE = next(),
I_TOOL_MOVE_XZ = newRow(),
I_TOOL_MOVE_Y = next(),

View file

@ -134,7 +134,7 @@ public class ItemHelper {
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, boolean simulate) {
return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.extractorAmount.get(),
return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.defaultExtractionLimit.get(),
simulate);
}
@ -207,7 +207,7 @@ public class ItemHelper {
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test,
Function<ItemStack, Integer> amountFunction, boolean simulate) {
ItemStack extracting = ItemStack.EMPTY;
int maxExtractionCount = AllConfigs.SERVER.logistics.extractorAmount.get();
int maxExtractionCount = AllConfigs.SERVER.logistics.defaultExtractionLimit.get();
for (int slot = 0; slot < inv.getSlots(); slot++) {
if (extracting.isEmpty()) {

View file

@ -99,7 +99,6 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
.forEach(tb -> tb.read(compound, clientPacket));
}
/**
* Hook only these in future subclasses of STE
*/
@ -126,13 +125,10 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
behaviours.values()
.forEach(tb -> {
if (!tb.isPaused())
action.accept(tb);
});
.forEach(action);
}
protected void putBehaviour(TileEntityBehaviour behaviour) {
protected void attachBehaviourLate(TileEntityBehaviour behaviour) {
behaviours.put(behaviour.getType(), behaviour);
behaviour.initialize();
}
@ -144,7 +140,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
}
@SuppressWarnings("unchecked")
protected <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) {
public <T extends TileEntityBehaviour> T getBehaviour(BehaviourType<T> type) {
if (behaviours.containsKey(type))
return (T) behaviours.get(type);
return null;

View file

@ -13,13 +13,11 @@ import net.minecraft.world.World;
public abstract class TileEntityBehaviour {
public SmartTileEntity tileEntity;
private boolean paused;
private int lazyTickRate;
private int lazyTickCounter;
public TileEntityBehaviour(SmartTileEntity te) {
tileEntity = te;
paused = false;
setLazyTickRate(10);
}
@ -61,10 +59,6 @@ public abstract class TileEntityBehaviour {
}
public boolean isPaused() {
return paused;
}
public void setLazyTickRate(int slowTickRate) {
this.lazyTickRate = slowTickRate;
this.lazyTickCounter = slowTickRate;
@ -74,10 +68,6 @@ public abstract class TileEntityBehaviour {
}
public void setPaused(boolean paused) {
this.paused = paused;
}
public BlockPos getPos() {
return tileEntity.getPos();
}

View file

@ -2,7 +2,6 @@ package com.simibubi.create.foundation.tileEntity.behaviour.filtering;
import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
@ -32,7 +31,7 @@ public class FilteringCountUpdatePacket extends TileEntityConfigurationPacket<Sm
@Override
protected void applySettings(SmartTileEntity te) {
FilteringBehaviour behaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE);
FilteringBehaviour behaviour = te.getBehaviour(FilteringBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.forceClientState = true;

View file

@ -87,7 +87,7 @@ public class FilteringRenderer {
if (tileEntityIn == null || tileEntityIn.isRemoved())
return;
FilteringBehaviour behaviour = TileEntityBehaviour.get(tileEntityIn, FilteringBehaviour.TYPE);
FilteringBehaviour behaviour = tileEntityIn.getBehaviour(FilteringBehaviour.TYPE);
if (behaviour == null)
return;
if (!behaviour.isActive())

View file

@ -25,13 +25,33 @@ import net.minecraftforge.items.ItemHandlerHelper;
public class InvManipulationBehaviour extends TileEntityBehaviour {
public static BehaviourType<InvManipulationBehaviour> TYPE = new BehaviourType<>();
private InterfaceProvider target;
private LazyOptional<IItemHandler> targetCapability;
private boolean simulateNext;
// Extra types available for multibehaviour
public static BehaviourType<InvManipulationBehaviour>
TYPE = new BehaviourType<>(), EXTRACT = new BehaviourType<>(), INSERT = new BehaviourType<>();
protected InterfaceProvider target;
protected LazyOptional<IItemHandler> targetCapability;
protected boolean simulateNext;
private BehaviourType<InvManipulationBehaviour> behaviourType;
public static InvManipulationBehaviour forExtraction(SmartTileEntity te, InterfaceProvider target) {
return new InvManipulationBehaviour(EXTRACT, te, target);
}
public static InvManipulationBehaviour forInsertion(SmartTileEntity te, InterfaceProvider target) {
return new InvManipulationBehaviour(INSERT, te, target);
}
public InvManipulationBehaviour(SmartTileEntity te, InterfaceProvider target) {
this(TYPE, te, target);
}
private InvManipulationBehaviour(BehaviourType<InvManipulationBehaviour> type, SmartTileEntity te,
InterfaceProvider target) {
super(te);
behaviourType = type;
setLazyTickRate(40);
this.target = target;
this.targetCapability = LazyOptional.empty();
@ -94,7 +114,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
protected Predicate<ItemStack> getFilterTest(Predicate<ItemStack> customFilter) {
Predicate<ItemStack> test = customFilter;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE);
if (filter != null)
test = customFilter.and(filter::test);
return test;
@ -119,7 +139,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
public int getAmountFromFilter() {
int amount = -1;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
FilteringBehaviour filter = tileEntity.getBehaviour(FilteringBehaviour.TYPE);
if (filter != null && !filter.anyAmount())
amount = filter.getAmount();
return amount;
@ -146,7 +166,7 @@ public class InvManipulationBehaviour extends TileEntityBehaviour {
@Override
public BehaviourType<?> getType() {
return TYPE;
return behaviourType;
}
@FunctionalInterface

View file

@ -57,12 +57,12 @@ public class LinkRenderer {
}
}
public static void renderOnTileEntity(SmartTileEntity tileEntityIn, float partialTicks, MatrixStack ms,
public static void renderOnTileEntity(SmartTileEntity te, float partialTicks, MatrixStack ms,
IRenderTypeBuffer buffer, int light, int overlay) {
if (tileEntityIn == null || tileEntityIn.isRemoved())
if (te == null || te.isRemoved())
return;
LinkBehaviour behaviour = TileEntityBehaviour.get(tileEntityIn, LinkBehaviour.TYPE);
LinkBehaviour behaviour = te.getBehaviour(LinkBehaviour.TYPE);
if (behaviour == null)
return;
@ -71,7 +71,7 @@ public class LinkRenderer {
ItemStack stack = first ? behaviour.frequencyFirst.getStack() : behaviour.frequencyLast.getStack();
ms.push();
transform.transform(tileEntityIn.getBlockState(), ms);
transform.transform(te.getBlockState(), ms);
ValueBoxRenderer.renderItemIntoValueBox(stack, ms, buffer, light, overlay);
ms.pop();
}

View file

@ -45,8 +45,8 @@ public class ScrollValueHandler {
if (scrolling instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) {
BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) scrolling;
for (SmartTileEntity smartTileEntity : bulkScrolling.getBulk()) {
ScrollValueBehaviour other = TileEntityBehaviour.get(smartTileEntity, ScrollValueBehaviour.TYPE);
for (SmartTileEntity te : bulkScrolling.getBulk()) {
ScrollValueBehaviour other = te.getBehaviour(ScrollValueBehaviour.TYPE);
if (other != null)
applyTo(delta, other);
}

View file

@ -35,15 +35,14 @@ public class ScrollValueRenderer {
ScrollValueBehaviour behaviour = TileEntityBehaviour.get(world, pos, ScrollValueBehaviour.TYPE);
if (behaviour == null)
return;
if (behaviour.needsWrench
&& !AllItems.WRENCH.isIn(Minecraft.getInstance().player.getHeldItemMainhand()))
if (behaviour.needsWrench && !AllItems.WRENCH.isIn(Minecraft.getInstance().player.getHeldItemMainhand()))
return;
boolean highlight = behaviour.testHit(target.getHitVec());
if (behaviour instanceof BulkScrollValueBehaviour && AllKeys.ctrlDown()) {
BulkScrollValueBehaviour bulkScrolling = (BulkScrollValueBehaviour) behaviour;
for (SmartTileEntity smartTileEntity : bulkScrolling.getBulk()) {
ScrollValueBehaviour other = TileEntityBehaviour.get(smartTileEntity, ScrollValueBehaviour.TYPE);
ScrollValueBehaviour other = smartTileEntity.getBehaviour(ScrollValueBehaviour.TYPE);
if (other != null)
addBox(world, smartTileEntity.getPos(), face, other, highlight);
}

View file

@ -2,7 +2,6 @@ package com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue;
import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
@ -32,7 +31,7 @@ public class ScrollValueUpdatePacket extends TileEntityConfigurationPacket<Smart
@Override
protected void applySettings(SmartTileEntity te) {
ScrollValueBehaviour behaviour = TileEntityBehaviour.get(te, ScrollValueBehaviour.TYPE);
ScrollValueBehaviour behaviour = te.getBehaviour(ScrollValueBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.setValue(value);

View file

@ -16,10 +16,12 @@ import net.minecraft.item.ItemStack;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.SlabType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.GameRules;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
@ -65,25 +67,25 @@ public class BlockHelper {
}
public static BlockState setZeroAge(BlockState blockState) {
if(blockState.has(BlockStateProperties.AGE_0_1))
if (blockState.has(BlockStateProperties.AGE_0_1))
return blockState.with(BlockStateProperties.AGE_0_1, 0);
if(blockState.has(BlockStateProperties.AGE_0_2))
if (blockState.has(BlockStateProperties.AGE_0_2))
return blockState.with(BlockStateProperties.AGE_0_2, 0);
if(blockState.has(BlockStateProperties.AGE_0_3))
if (blockState.has(BlockStateProperties.AGE_0_3))
return blockState.with(BlockStateProperties.AGE_0_3, 0);
if(blockState.has(BlockStateProperties.AGE_0_5))
if (blockState.has(BlockStateProperties.AGE_0_5))
return blockState.with(BlockStateProperties.AGE_0_5, 0);
if(blockState.has(BlockStateProperties.AGE_0_7))
if (blockState.has(BlockStateProperties.AGE_0_7))
return blockState.with(BlockStateProperties.AGE_0_7, 0);
if(blockState.has(BlockStateProperties.AGE_0_15))
if (blockState.has(BlockStateProperties.AGE_0_15))
return blockState.with(BlockStateProperties.AGE_0_15, 0);
if(blockState.has(BlockStateProperties.AGE_0_25))
if (blockState.has(BlockStateProperties.AGE_0_25))
return blockState.with(BlockStateProperties.AGE_0_25, 0);
if(blockState.has(BlockStateProperties.HONEY_LEVEL))
if (blockState.has(BlockStateProperties.HONEY_LEVEL))
return blockState.with(BlockStateProperties.HONEY_LEVEL, 0);
if(blockState.has(BlockStateProperties.HATCH_0_2))
if (blockState.has(BlockStateProperties.HATCH_0_2))
return blockState.with(BlockStateProperties.HATCH_0_2, 0);
if(blockState.has(BlockStateProperties.STAGE_0_1))
if (blockState.has(BlockStateProperties.STAGE_0_1))
return blockState.with(BlockStateProperties.STAGE_0_1, 0);
return blockState;
}
@ -98,10 +100,10 @@ public class BlockHelper {
if (needsTwo)
amount *= 2;
if(block.has(BlockStateProperties.EGGS_1_4))
if (block.has(BlockStateProperties.EGGS_1_4))
amount *= block.get(BlockStateProperties.EGGS_1_4);
if(block.has(BlockStateProperties.PICKLES_1_4))
if (block.has(BlockStateProperties.PICKLES_1_4))
amount *= block.get(BlockStateProperties.PICKLES_1_4);
{
@ -172,4 +174,13 @@ public class BlockHelper {
world.setBlockState(pos, ifluidstate.getBlockState());
}
public static boolean isSolidWall(IBlockReader reader, BlockPos fromPos, Direction toDirection) {
return Block.hasSolidSide(reader.getBlockState(fromPos.offset(toDirection)), reader,
fromPos.offset(toDirection), toDirection.getOpposite());
}
public static boolean noCollisionInSpace(IBlockReader reader, BlockPos pos) {
return reader.getBlockState(pos).getCollisionShape(reader, pos).isEmpty();
}
}

View file

@ -343,6 +343,10 @@
"create.tooltip.analogStrength": "Analog Strength: %1$s/15",
"create.mechanical_arm.extract_from": "Take items from %1$s",
"create.mechanical_arm.deposit_to": "Deposit items to %1$s",
"create.mechanical_arm.points_outside_range": "%1$s selected interaction point(s) removed due to range limitations.",
"create.logistics.when_multiple_outputs_available": "When Multiple Outputs Available",
"create.mechanical_arm.selection_mode.round_robin": "Round Robin",
@ -355,6 +359,7 @@
"create.tunnel.selection_mode.forced_round_robin": "Forced Round Robin",
"create.tunnel.selection_mode.prefer_nearest": "Prefer Nearest",
"create.tunnel.selection_mode.randomize": "Randomize",
"create.tunnel.selection_mode.synchronize": "Synchronize Inputs",
"create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "This is a sample overlay",

View file

@ -19,7 +19,8 @@
"north": {"uv": [0, 8, 1, 9.5], "texture": "#7"},
"east": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"},
"south": {"uv": [15, 8, 16, 9.5], "texture": "#7"},
"west": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"}
"west": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"},
"down": {"uv": [14, 10, 16, 16], "texture": "#particle"}
}
},
{
@ -31,7 +32,8 @@
"north": {"uv": [7, 8, 8, 9.5], "texture": "#7"},
"east": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"},
"south": {"uv": [8, 7.5, 9, 9], "texture": "#7"},
"west": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"}
"west": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"},
"down": {"uv": [0, 10, 2, 16], "texture": "#particle"}
}
},
{
@ -80,7 +82,8 @@
"faces": {
"north": {"uv": [0, 9.5, 0.5, 10.5], "texture": "#7"},
"east": {"uv": [5, 15, 8, 16], "texture": "#7"},
"west": {"uv": [5, 15, 8, 16], "texture": "#7"}
"west": {"uv": [5, 15, 8, 16], "texture": "#7"},
"down": {"uv": [0, 0, 1, 6], "texture": "#particle"}
}
},
{
@ -91,7 +94,8 @@
"faces": {
"north": {"uv": [7.5, 9.5, 8, 10.5], "texture": "#7"},
"east": {"uv": [8, 15, 5, 16], "texture": "#7"},
"west": {"uv": [8, 15, 5, 16], "texture": "#7"}
"west": {"uv": [8, 15, 5, 16], "texture": "#7"},
"down": {"uv": [0, 0, 1, 6], "texture": "#particle"}
}
},
{
@ -165,7 +169,8 @@
"faces": {
"east": {"uv": [0, 14.5, 5, 16], "texture": "#7"},
"south": {"uv": [7.5, 14.5, 8, 16], "texture": "#7"},
"up": {"uv": [0, 14.5, 5.5, 15], "rotation": 270, "texture": "#7"}
"up": {"uv": [0, 14.5, 5.5, 15], "rotation": 270, "texture": "#7"},
"down": {"uv": [0, 0, 1, 10], "texture": "#particle"}
}
},
{
@ -176,7 +181,8 @@
"faces": {
"south": {"uv": [0, 14.5, 0.5, 16], "texture": "#7"},
"west": {"uv": [5, 14.5, 0, 16], "texture": "#7"},
"up": {"uv": [0, 15, 5.5, 14.5], "rotation": 270, "texture": "#7"}
"up": {"uv": [0, 15, 5.5, 14.5], "rotation": 270, "texture": "#7"},
"down": {"uv": [0, 0, 1, 10], "texture": "#particle"}
}
}
],

View file

@ -19,7 +19,8 @@
"north": {"uv": [0, 8, 1, 9.5], "texture": "#7"},
"east": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"},
"south": {"uv": [15, 8, 16, 9.5], "texture": "#7"},
"west": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"}
"west": {"uv": [13, 0, 16, 6], "rotation": 90, "texture": "#2"},
"down": {"uv": [14, 10, 16, 16], "texture": "#particle"}
}
},
{
@ -31,7 +32,8 @@
"north": {"uv": [7, 8, 8, 9.5], "texture": "#7"},
"east": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"},
"south": {"uv": [8, 7.5, 9, 9], "texture": "#7"},
"west": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"}
"west": {"uv": [13, 6, 16, 0], "rotation": 90, "texture": "#2"},
"down": {"uv": [0, 10, 2, 16], "texture": "#particle"}
}
},
{
@ -90,7 +92,8 @@
"faces": {
"north": {"uv": [0, 9.5, 0.5, 10.5], "texture": "#7"},
"east": {"uv": [5, 15, 8, 16], "texture": "#7"},
"west": {"uv": [5, 15, 8, 16], "texture": "#7"}
"west": {"uv": [5, 15, 8, 16], "texture": "#7"},
"down": {"uv": [0, 0, 1, 6], "texture": "#particle"}
}
},
{
@ -101,7 +104,8 @@
"faces": {
"north": {"uv": [7.5, 9.5, 8, 10.5], "texture": "#7"},
"east": {"uv": [8, 15, 5, 16], "texture": "#7"},
"west": {"uv": [8, 15, 5, 16], "texture": "#7"}
"west": {"uv": [8, 15, 5, 16], "texture": "#7"},
"down": {"uv": [0, 0, 1, 6], "texture": "#particle"}
}
},
{
@ -149,7 +153,9 @@
"faces": {
"east": {"uv": [0, 14.5, 1, 16], "texture": "#7"},
"south": {"uv": [7.5, 14.5, 8, 16], "texture": "#7"},
"up": {"uv": [0, 14.5, 5.5, 15], "rotation": 270, "texture": "#7"}
"west": {"uv": [7, 14.5, 8, 16], "texture": "#7"},
"up": {"uv": [0, 14.5, 5.5, 15], "rotation": 270, "texture": "#7"},
"down": {"uv": [0, 0, 1, 2], "texture": "#particle"}
}
},
{
@ -158,9 +164,11 @@
"to": [1, -2, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 6]},
"faces": {
"east": {"uv": [8, 14.5, 7, 16], "texture": "#7"},
"south": {"uv": [0, 14.5, 0.5, 16], "texture": "#7"},
"west": {"uv": [1, 14.5, 0, 16], "texture": "#7"},
"up": {"uv": [0, 15, 5.5, 14.5], "rotation": 270, "texture": "#7"}
"up": {"uv": [0, 15, 5.5, 14.5], "rotation": 270, "texture": "#7"},
"down": {"uv": [0, 0, 1, 2], "texture": "#particle"}
}
},
{

View file

@ -0,0 +1,12 @@
{
"textures": [
"minecraft:generic_7",
"minecraft:generic_6",
"minecraft:generic_5",
"minecraft:generic_4",
"minecraft:generic_3",
"minecraft:generic_2",
"minecraft:generic_1",
"minecraft:generic_0"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB