Simulate and Translocate

- Adjusted Brass Tunnels once again to better deal with non-complete item transferrals
- Brass tunnels now always output to their sides first
- Thrown chromatic products are now gravity-less
- Sneaking on Ejectors bypasses them triggering
- Fixed ponder tag item listing
- Ejectors now trigger observers
- Fixed negative bottom pull distance in chutes
- Fixed smart chutes deleting non-stackable items
- Fixed chutes not able to output partial stacks
- Ejectors can now be paused with redstone
- Deferred ejector launches by one tick to 'unground' entities more consistently
This commit is contained in:
simibubi 2021-03-26 18:41:03 +01:00
parent 9c8d035694
commit 0afb29f9a6
10 changed files with 372 additions and 249 deletions

View file

@ -89,7 +89,7 @@ public class ChromaticCompoundItem extends Item {
if (y < 0 && y - yMotion < -10 && config.enableShadowSteelRecipe.get()) { if (y < 0 && y - yMotion < -10 && config.enableShadowSteelRecipe.get()) {
ItemStack newStack = AllItems.SHADOW_STEEL.asStack(); ItemStack newStack = AllItems.SHADOW_STEEL.asStack();
newStack.setCount(stack.getCount()); newStack.setCount(stack.getCount());
data.putBoolean("FromVoid", true); data.putBoolean("JustCreated", true);
entity.setItem(newStack); entity.setItem(newStack);
} }
@ -102,7 +102,7 @@ public class ChromaticCompoundItem extends Item {
ItemEntity newEntity = new ItemEntity(world, entity.getX(), entity.getY(), entity.getZ(), newStack); ItemEntity newEntity = new ItemEntity(world, entity.getX(), entity.getY(), entity.getZ(), newStack);
newEntity.setMotion(entity.getMotion()); newEntity.setMotion(entity.getMotion());
newEntity.getPersistentData() newEntity.getPersistentData()
.putBoolean("FromLight", true); .putBoolean("JustCreated", true);
itemData.remove("CollectingLight"); itemData.remove("CollectingLight");
world.addEntity(newEntity); world.addEntity(newEntity);
@ -119,10 +119,8 @@ public class ChromaticCompoundItem extends Item {
int entityZ = MathHelper.floor(entity.getZ()); int entityZ = MathHelper.floor(entity.getZ());
int localWorldHeight = world.getHeight(Heightmap.Type.WORLD_SURFACE, entityX, entityZ); int localWorldHeight = world.getHeight(Heightmap.Type.WORLD_SURFACE, entityX, entityZ);
BlockPos.Mutable testPos = new BlockPos.Mutable( BlockPos.Mutable testPos =
entityX, new BlockPos.Mutable(entityX, Math.min(MathHelper.floor(entity.getY()), localWorldHeight), entityZ);
Math.min(MathHelper.floor(entity.getY()), localWorldHeight),
entityZ);
while (testPos.getY() > 0) { while (testPos.getY() > 0) {
testPos.move(Direction.DOWN); testPos.move(Direction.DOWN);
@ -131,12 +129,14 @@ public class ChromaticCompoundItem extends Item {
break; break;
if (state.getBlock() == Blocks.BEACON) { if (state.getBlock() == Blocks.BEACON) {
TileEntity te = world.getTileEntity(testPos); TileEntity te = world.getTileEntity(testPos);
if (!(te instanceof BeaconTileEntity)) break; if (!(te instanceof BeaconTileEntity))
break;
BeaconTileEntity bte = (BeaconTileEntity) te; BeaconTileEntity bte = (BeaconTileEntity) te;
if (bte.getLevels() != 0 && !bte.beamSegments.isEmpty()) isOverBeacon = true; if (bte.getLevels() != 0 && !bte.beamSegments.isEmpty())
isOverBeacon = true;
break; break;
} }
@ -145,7 +145,7 @@ public class ChromaticCompoundItem extends Item {
if (isOverBeacon) { if (isOverBeacon) {
ItemStack newStack = AllItems.REFINED_RADIANCE.asStack(); ItemStack newStack = AllItems.REFINED_RADIANCE.asStack();
newStack.setCount(stack.getCount()); newStack.setCount(stack.getCount());
data.putBoolean("FromLight", true); data.putBoolean("JustCreated", true);
entity.setItem(newStack); entity.setItem(newStack);
return false; return false;

View file

@ -0,0 +1,67 @@
package com.simibubi.create.content.curiosities;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class NoGravMagicalDohickyItem extends Item {
public NoGravMagicalDohickyItem(Properties p_i48487_1_) {
super(p_i48487_1_);
}
@Override
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
World world = entity.world;
Vec3d pos = entity.getPositionVec();
CompoundNBT persistentData = entity.getPersistentData();
if (world.isRemote) {
if (world.rand.nextFloat() < getIdleParticleChance(entity)) {
Vec3d ppos = VecHelper.offsetRandomly(pos, world.rand, .5f);
world.addParticle(ParticleTypes.END_ROD, ppos.x, pos.y, ppos.z, 0, -.1f, 0);
}
if (entity.isSilent() && !persistentData.getBoolean("PlayEffects")) {
Vec3d basemotion = new Vec3d(0, 1, 0);
world.addParticle(ParticleTypes.FLASH, pos.x, pos.y, pos.z, 0, 0, 0);
for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(basemotion, world.rand, 1);
world.addParticle(ParticleTypes.WITCH, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
}
persistentData.putBoolean("PlayEffects", true);
}
return false;
}
entity.setNoGravity(true);
if (!persistentData.contains("JustCreated"))
return false;
onCreated(entity, persistentData);
return false;
}
protected float getIdleParticleChance(ItemEntity entity) {
return MathHelper.clamp(entity.getItem()
.getCount() - 10, 5, 100) / 64f;
}
protected void onCreated(ItemEntity entity, CompoundNBT persistentData) {
entity.lifespan = 6000;
persistentData.remove("JustCreated");
// just a flag to tell the client to play an effect
entity.setSilent(true);
}
}

View file

@ -1,59 +1,25 @@
package com.simibubi.create.content.curiosities; package com.simibubi.create.content.curiosities;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.particles.ParticleTypes; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class RefinedRadianceItem extends Item { public class RefinedRadianceItem extends NoGravMagicalDohickyItem {
public RefinedRadianceItem(Properties properties) { public RefinedRadianceItem(Properties properties) {
super(properties); super(properties);
} }
@Override @Override
public boolean hasEffect(ItemStack stack) { public boolean hasEffect(ItemStack stack) {
return true; return true;
} }
@Override @Override
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) { protected void onCreated(ItemEntity entity, CompoundNBT persistentData) {
World world = entity.world; super.onCreated(entity, persistentData);
Vec3d pos = entity.getPositionVec(); entity.setMotion(entity.getMotion()
.add(0, .15f, 0));
if (world.isRemote && entity.hasNoGravity()) {
if (world.rand.nextFloat() < MathHelper.clamp(entity.getItem().getCount() - 10, 1, 100) / 64f) {
Vec3d ppos = VecHelper.offsetRandomly(pos, world.rand, .5f);
world.addParticle(ParticleTypes.END_ROD, ppos.x, pos.y, ppos.z, 0, -.1f, 0);
}
if (!entity.getPersistentData().contains("ClientAnimationPlayed")) {
Vec3d basemotion = new Vec3d(0, 1, 0);
world.addParticle(ParticleTypes.FLASH, pos.x, pos.y, pos.z, 0, 0, 0);
for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(basemotion, world.rand, 1);
world.addParticle(ParticleTypes.WITCH, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
}
entity.getPersistentData().putBoolean("ClientAnimationPlayed", true);
}
return false;
}
if (!entity.getPersistentData().contains("FromLight"))
return false;
entity.lifespan = 6000;
entity.setNoGravity(true);
entity.setMotion(entity.getMotion().add(0, .15f, 0));
entity.getPersistentData().remove("FromLight");
return false;
} }
} }

View file

@ -1,56 +1,26 @@
package com.simibubi.create.content.curiosities; package com.simibubi.create.content.curiosities;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.Item; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.ItemStack;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class ShadowSteelItem extends Item { public class ShadowSteelItem extends NoGravMagicalDohickyItem {
public ShadowSteelItem(Properties properties) { public ShadowSteelItem(Properties properties) {
super(properties); super(properties);
} }
@Override @Override
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) { protected void onCreated(ItemEntity entity, CompoundNBT persistentData) {
World world = entity.world; super.onCreated(entity, persistentData);
Vec3d pos = entity.getPositionVec();
if (world.isRemote && entity.hasNoGravity()) {
if (world.rand.nextFloat() < MathHelper.clamp(entity.getItem().getCount() - 10,
Math.min(entity.getMotion().y * 20, 20), 100) / 64f) {
Vec3d ppos = VecHelper.offsetRandomly(pos, world.rand, .5f);
world.addParticle(ParticleTypes.END_ROD, ppos.x, pos.y, ppos.z, 0, -.1f, 0);
}
if (!entity.getPersistentData().contains("ClientAnimationPlayed")) {
Vec3d basemotion = new Vec3d(0, 1, 0);
world.addParticle(ParticleTypes.FLASH, pos.x, pos.y, pos.z, 0, 0, 0);
for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(basemotion, world.rand, 1);
world.addParticle(ParticleTypes.WITCH, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
world.addParticle(ParticleTypes.END_ROD, pos.x, pos.y, pos.z, motion.x, motion.y, motion.z);
}
entity.getPersistentData().putBoolean("ClientAnimationPlayed", true);
}
return false;
}
if (!entity.getPersistentData().contains("FromVoid"))
return false;
entity.setNoGravity(true);
float yMotion = (entity.fallDistance + 3) / 50f; float yMotion = (entity.fallDistance + 3) / 50f;
entity.setMotion(0, yMotion, 0); entity.setMotion(0, yMotion, 0);
entity.lifespan = 6000; }
entity.getPersistentData().remove("FromVoid");
return false; @Override
protected float getIdleParticleChance(ItemEntity entity) {
return (float) (MathHelper.clamp(entity.getItem()
.getCount() - 10, MathHelper.clamp(entity.getMotion().y * 20, 5, 20), 100) / 64f);
} }
} }

View file

@ -2,7 +2,10 @@ package com.simibubi.create.content.logistics.block.belts.tunnel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
@ -188,12 +191,17 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
} }
private static Random rand = new Random(); private static Random rand = new Random();
private static Map<Pair<BrassTunnelTileEntity, Direction>, ItemStack> distributed = new IdentityHashMap<>();
private static Set<Pair<BrassTunnelTileEntity, Direction>> full = new HashSet<>();
private void distribute(List<Pair<BrassTunnelTileEntity, Direction>> validTargets) { private void distribute(List<Pair<BrassTunnelTileEntity, Direction>> validTargets) {
int amountTargets = validTargets.size(); int amountTargets = validTargets.size();
if (amountTargets == 0) if (amountTargets == 0)
return; return;
distributed.clear();
full.clear();
int indexStart = previousOutputIndex % amountTargets; int indexStart = previousOutputIndex % amountTargets;
SelectionMode mode = selectionMode.get(); SelectionMode mode = selectionMode.get();
boolean force = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.FORCED_SPLIT; boolean force = mode == SelectionMode.FORCED_ROUND_ROBIN || mode == SelectionMode.FORCED_SPLIT;
@ -204,55 +212,94 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE) if (mode == SelectionMode.PREFER_NEAREST || mode == SelectionMode.SYNCHRONIZE)
indexStart = 0; indexStart = 0;
ItemStack toDistribute = null; ItemStack toDistribute = stackToDistribute.copy();
int leftovers = 0; for (boolean distributeAgain : Iterate.trueAndFalse) {
int remainingOutputs = amountTargets; ItemStack toDistributeThisCycle = null;
int remainingOutputs = amountTargets;
int leftovers = 0;
for (boolean simulate : Iterate.trueAndFalse) { for (boolean simulate : Iterate.trueAndFalse) {
if (remainingOutputs == 0) if (remainingOutputs == 0)
return; break;
leftovers = 0;
int index = indexStart;
int stackSize = stackToDistribute.getCount();
int splitStackSize = stackSize / remainingOutputs;
int splitRemainder = stackSize % remainingOutputs;
int visited = 0;
toDistribute = stackToDistribute.copy(); leftovers = 0;
if (!(force || split) && simulate) int index = indexStart;
continue; int stackSize = toDistribute.getCount();
int splitStackSize = stackSize / remainingOutputs;
while (visited < amountTargets) { int splitRemainder = stackSize % remainingOutputs;
Pair<BrassTunnelTileEntity, Direction> pair = validTargets.get(index); int visited = 0;
BrassTunnelTileEntity tunnel = pair.getKey();
Direction side = pair.getValue();
index = (index + 1) % amountTargets;
visited++;
int count = split ? splitStackSize + (splitRemainder > 0 ? 1 : 0) : stackSize; toDistributeThisCycle = toDistribute.copy();
ItemStack toOutput = ItemHandlerHelper.copyStackWithSize(toDistribute, count); if (!(force || split) && simulate)
ItemStack remainder = insertIntoTunnel(tunnel, side, toOutput, simulate);
if (remainder == null || remainder.getCount() == count) {
if (force)
return;
if (split && simulate)
remainingOutputs--;
continue; continue;
}
leftovers += remainder.getCount(); while (visited < amountTargets) {
toDistribute.shrink(count); Pair<BrassTunnelTileEntity, Direction> pair = validTargets.get(index);
if (toDistribute.isEmpty()) BrassTunnelTileEntity tunnel = pair.getKey();
break; Direction side = pair.getValue();
splitRemainder--; index = (index + 1) % amountTargets;
if (!split) visited++;
break;
if (full.contains(pair)) {
if (split && simulate)
remainingOutputs--;
continue;
}
int count = split ? splitStackSize + (splitRemainder > 0 ? 1 : 0) : stackSize;
ItemStack toOutput = ItemHandlerHelper.copyStackWithSize(toDistributeThisCycle, count);
// Grow by 1 to determine if target is full even after a successful transfer
boolean testWithIncreasedCount = distributed.containsKey(pair);
int increasedCount = testWithIncreasedCount ? distributed.get(pair)
.getCount() : 0;
if (testWithIncreasedCount)
toOutput.grow(increasedCount);
ItemStack remainder = insertIntoTunnel(tunnel, side, toOutput, true);
if (remainder == null || remainder.getCount() == (testWithIncreasedCount ? count + 1 : count)) {
if (force)
return;
if (split && simulate)
remainingOutputs--;
if (!simulate)
full.add(pair);
continue;
} else if (!remainder.isEmpty() && !simulate) {
full.add(pair);
}
if (!simulate) {
toOutput.shrink(remainder.getCount());
distributed.put(pair, toOutput);
}
leftovers += remainder.getCount();
toDistributeThisCycle.shrink(count);
if (toDistributeThisCycle.isEmpty())
break;
splitRemainder--;
if (!split)
break;
}
} }
toDistribute.setCount(toDistributeThisCycle.getCount() + leftovers);
if (leftovers == 0 && distributeAgain)
break;
if (!split)
break;
} }
stackToDistribute = ItemHandlerHelper.copyStackWithSize(stackToDistribute, toDistribute.getCount() + leftovers); int failedTransferrals = 0;
for (Entry<Pair<BrassTunnelTileEntity, Direction>, ItemStack> entry : distributed.entrySet()) {
Pair<BrassTunnelTileEntity, Direction> pair = entry.getKey();
failedTransferrals += insertIntoTunnel(pair.getKey(), pair.getValue(), entry.getValue(), false).getCount();
}
toDistribute.grow(failedTransferrals);
stackToDistribute = ItemHandlerHelper.copyStackWithSize(stackToDistribute, toDistribute.getCount());
previousOutputIndex++; previousOutputIndex++;
previousOutputIndex %= amountTargets; previousOutputIndex %= amountTargets;
notifyUpdate(); notifyUpdate();
@ -418,25 +465,34 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
if (!AllBlocks.BRASS_TUNNEL.has(blockState)) if (!AllBlocks.BRASS_TUNNEL.has(blockState))
return; return;
for (Direction direction : Iterate.horizontalDirections) { boolean prioritizeSides = tunnelTE == this;
if (direction == movementFacing && below.getSpeed() == 0)
for (boolean sidePass : Iterate.trueAndFalse) {
if (!prioritizeSides && sidePass)
continue; continue;
if (direction == movementFacing.getOpposite()) for (Direction direction : Iterate.horizontalDirections) {
continue; if (direction == movementFacing && below.getSpeed() == 0)
if (tunnelTE.sides.contains(direction)) { continue;
BlockPos offset = tunnelTE.pos.down() if (prioritizeSides && sidePass == (direction.getAxis() == movementFacing.getAxis()))
.offset(direction); continue;
DirectBeltInputBehaviour inputBehaviour = if (direction == movementFacing.getOpposite())
TileEntityBehaviour.get(world, offset, DirectBeltInputBehaviour.TYPE); continue;
if (inputBehaviour == null) { if (tunnelTE.sides.contains(direction)) {
if (direction == movementFacing) BlockPos offset = tunnelTE.pos.down()
if (!Block.hasSolidSide(world.getBlockState(offset), world, offset, direction.getOpposite())) .offset(direction);
validOutputs.add(Pair.of(tunnelTE, direction)); DirectBeltInputBehaviour inputBehaviour =
TileEntityBehaviour.get(world, offset, DirectBeltInputBehaviour.TYPE);
if (inputBehaviour == null) {
if (direction == movementFacing)
if (!Block.hasSolidSide(world.getBlockState(offset), world, offset,
direction.getOpposite()))
validOutputs.add(Pair.of(tunnelTE, direction));
continue;
}
if (inputBehaviour.canInsertFromSide(direction))
validOutputs.add(Pair.of(tunnelTE, direction));
continue; continue;
} }
if (inputBehaviour.canInsertFromSide(direction))
validOutputs.add(Pair.of(tunnelTE, direction));
continue;
} }
} }
} }

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.block.chute;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
@ -61,7 +62,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
*/ */
public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInformation { // , IAirCurrentSource { public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInformation { // , IAirCurrentSource {
// public AirCurrent airCurrent; // public AirCurrent airCurrent;
float pull; float pull;
float push; float push;
@ -92,7 +93,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
capAbove = LazyOptional.empty(); capAbove = LazyOptional.empty();
capBelow = LazyOptional.empty(); capBelow = LazyOptional.empty();
bottomPullDistance = 0; bottomPullDistance = 0;
// airCurrent = new AirCurrent(this); // airCurrent = new AirCurrent(this);
updateAirFlow = true; updateAirFlow = true;
} }
@ -178,7 +179,7 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
private void updateAirFlow(float itemSpeed) { private void updateAirFlow(float itemSpeed) {
updateAirFlow = false; updateAirFlow = false;
// airCurrent.rebuild(); // airCurrent.rebuild();
if (itemSpeed > 0 && world != null && !world.isRemote) { if (itemSpeed > 0 && world != null && !world.isRemote) {
float speed = pull - push; float speed = pull - push;
beltBelow = null; beltBelow = null;
@ -208,14 +209,14 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
beltBelowOffset = i - 1; beltBelowOffset = i - 1;
break; break;
} }
this.bottomPullDistance = flowLimit; this.bottomPullDistance = Math.max(0, flowLimit);
} }
sendData(); sendData();
} }
private void findEntities(float itemSpeed) { private void findEntities(float itemSpeed) {
// if (getSpeed() != 0) // if (getSpeed() != 0)
// airCurrent.findEntities(); // airCurrent.findEntities();
if (bottomPullDistance <= 0 && !getItem().isEmpty() || itemSpeed <= 0 || world == null || world.isRemote) if (bottomPullDistance <= 0 && !getItem().isEmpty() || itemSpeed <= 0 || world == null || world.isRemote)
return; return;
if (!canCollectItemsFromBelow()) if (!canCollectItemsFromBelow())
@ -267,8 +268,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
} }
extractFromBelt(itemSpeed); extractFromBelt(itemSpeed);
// if (getSpeed() != 0) // if (getSpeed() != 0)
// airCurrent.tick(); // airCurrent.tick();
} }
public void blockBelowChanged() { public void blockBelowChanged() {
@ -323,29 +324,40 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
private void handleInputFromAbove() { private void handleInputFromAbove() {
if (!capAbove.isPresent()) if (!capAbove.isPresent())
capAbove = grabCapability(Direction.UP); capAbove = grabCapability(Direction.UP);
if (capAbove.isPresent()) { if (!capAbove.isPresent())
int count = getExtractionAmount(); return;
if (count == 0)
item = int count = getExtractionAmount();
ItemHelper.extract(capAbove.orElse(null), this::canAcceptItem, ExtractionCountMode.UPTO, 16, false); IItemHandler inv = capAbove.orElse(null);
else Predicate<ItemStack> canAccept = this::canAcceptItem;
item = ItemHelper.extract(capAbove.orElse(null), this::canAcceptItem, ExtractionCountMode.EXACTLY, if (count == 0) {
count, false); item = ItemHelper.extract(inv, canAccept, ExtractionCountMode.UPTO, 16, false);
return;
} }
if (!ItemHelper.extract(inv, canAccept, ExtractionCountMode.EXACTLY, count, true)
.isEmpty())
item = ItemHelper.extract(inv, canAccept, ExtractionCountMode.EXACTLY, count, false);
} }
private void handleInputFromBelow() { private void handleInputFromBelow() {
if (!capBelow.isPresent()) if (!capBelow.isPresent())
capBelow = grabCapability(Direction.DOWN); capBelow = grabCapability(Direction.DOWN);
if (capBelow.isPresent()) { if (!capBelow.isPresent())
int count = getExtractionAmount(); return;
if (count == 0)
item = int count = getExtractionAmount();
ItemHelper.extract(capBelow.orElse(null), this::canAcceptItem, ExtractionCountMode.UPTO, 16, false); IItemHandler inv = capBelow.orElse(null);
else Predicate<ItemStack> canAccept = this::canAcceptItem;
item = ItemHelper.extract(capBelow.orElse(null), this::canAcceptItem, ExtractionCountMode.EXACTLY,
count, false); if (count == 0) {
item = ItemHelper.extract(inv, canAccept, ExtractionCountMode.UPTO, 16, false);
return;
} }
if (!ItemHelper.extract(inv, canAccept, ExtractionCountMode.EXACTLY, count, true)
.isEmpty())
item = ItemHelper.extract(inv, canAccept, ExtractionCountMode.EXACTLY, count, false);
} }
private boolean handleDownwardOutput(boolean simulate) { private boolean handleDownwardOutput(boolean simulate) {
@ -359,9 +371,10 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
capBelow = grabCapability(Direction.DOWN); capBelow = grabCapability(Direction.DOWN);
if (capBelow.isPresent()) { if (capBelow.isPresent()) {
ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate); ItemStack remainder = ItemHandlerHelper.insertItemStacked(capBelow.orElse(null), item, simulate);
ItemStack held = getItem();
if (!simulate) if (!simulate)
setItem(remainder); setItem(remainder);
if (remainder.isEmpty()) if (remainder.getCount() != held.getCount())
return true; return true;
if (direction == Direction.DOWN) if (direction == Direction.DOWN)
return false; return false;
@ -409,10 +422,11 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
if (!capAbove.isPresent()) if (!capAbove.isPresent())
capAbove = grabCapability(Direction.UP); capAbove = grabCapability(Direction.UP);
if (capAbove.isPresent()) { if (capAbove.isPresent()) {
int countBefore = item.getCount();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate); ItemStack remainder = ItemHandlerHelper.insertItemStacked(capAbove.orElse(null), item, simulate);
if (!simulate) if (!simulate)
setItem(ItemStack.EMPTY); item = remainder;
return remainder.isEmpty(); return countBefore != remainder.getCount();
} }
} }
@ -521,8 +535,8 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
super.read(compound, clientPacket); super.read(compound, clientPacket);
// if (clientPacket) // if (clientPacket)
// airCurrent.rebuild(); // airCurrent.rebuild();
if (hasWorld() && world != null && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) { if (hasWorld() && world != null && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) {
if (world.rand.nextInt(3) != 0) if (world.rand.nextInt(3) != 0)
@ -718,47 +732,47 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
return item; return item;
} }
// @Override // @Override
// @Nullable // @Nullable
// public AirCurrent getAirCurrent() { // public AirCurrent getAirCurrent() {
// return airCurrent; // return airCurrent;
// } // }
// //
// @Nullable // @Nullable
// @Override // @Override
// public World getAirCurrentWorld() { // public World getAirCurrentWorld() {
// return world; // return world;
// } // }
// //
// @Override // @Override
// public BlockPos getAirCurrentPos() { // public BlockPos getAirCurrentPos() {
// return pos; // return pos;
// } // }
// //
// @Override // @Override
// public float getSpeed() { // public float getSpeed() {
// if (getBlockState().get(ChuteBlock.SHAPE) == Shape.NORMAL && getBlockState().get(ChuteBlock.FACING) != Direction.DOWN) // if (getBlockState().get(ChuteBlock.SHAPE) == Shape.NORMAL && getBlockState().get(ChuteBlock.FACING) != Direction.DOWN)
// return 0; // return 0;
// return pull + push; // return pull + push;
// } // }
// //
// @Override // @Override
// @Nullable // @Nullable
// public Direction getAirFlowDirection() { // public Direction getAirFlowDirection() {
// float speed = getSpeed(); // float speed = getSpeed();
// if (speed == 0) // if (speed == 0)
// return null; // return null;
// return speed > 0 ? Direction.UP : Direction.DOWN; // return speed > 0 ? Direction.UP : Direction.DOWN;
// } // }
// //
// @Override // @Override
// public boolean isSourceRemoved() { // public boolean isSourceRemoved() {
// return removed; // return removed;
// } // }
// //
// @Override // @Override
// public Direction getAirflowOriginSide() { // public Direction getAirflowOriginSide() {
// return world != null && !(world.getTileEntity(pos.down()) instanceof IAirCurrentSource) // return world != null && !(world.getTileEntity(pos.down()) instanceof IAirCurrentSource)
// && getBlockState().get(ChuteBlock.FACING) == Direction.DOWN ? Direction.DOWN : Direction.UP; // && getBlockState().get(ChuteBlock.FACING) == Direction.DOWN ? Direction.DOWN : Direction.UP;
// } // }
} }

View file

@ -12,6 +12,7 @@ import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
@ -49,10 +50,16 @@ public class EjectorBlock extends HorizontalKineticBlock implements ITE<EjectorT
.orElse(super.getSlipperiness(state, world, pos, entity)); .orElse(super.getSlipperiness(state, world, pos, entity));
} }
@Override
public void neighborChanged(BlockState state, World world, BlockPos pos, Block p_220069_4_,
BlockPos p_220069_5_, boolean p_220069_6_) {
withTileEntityDo(world, pos, EjectorTileEntity::updateSignal);
}
@Override @Override
public void onFallenUpon(World p_180658_1_, BlockPos p_180658_2_, Entity p_180658_3_, float p_180658_4_) { public void onFallenUpon(World p_180658_1_, BlockPos p_180658_2_, Entity p_180658_3_, float p_180658_4_) {
Optional<EjectorTileEntity> tileEntityOptional = getTileEntityOptional(p_180658_1_, p_180658_2_); Optional<EjectorTileEntity> tileEntityOptional = getTileEntityOptional(p_180658_1_, p_180658_2_);
if (tileEntityOptional.isPresent()) { if (tileEntityOptional.isPresent() && !p_180658_3_.bypassesLandingEffects()) {
p_180658_3_.handleFallDamage(p_180658_4_, 0.0F); p_180658_3_.handleFallDamage(p_180658_4_, 0.0F);
return; return;
} }
@ -67,6 +74,8 @@ public class EjectorBlock extends HorizontalKineticBlock implements ITE<EjectorT
return; return;
if (!entityIn.isAlive()) if (!entityIn.isAlive())
return; return;
if (entityIn.bypassesLandingEffects())
return;
if (entityIn instanceof ItemEntity) { if (entityIn instanceof ItemEntity) {
SharedDepotBlockMethods.onLanded(worldIn, entityIn); SharedDepotBlockMethods.onLanded(worldIn, entityIn);
return; return;
@ -79,6 +88,8 @@ public class EjectorBlock extends HorizontalKineticBlock implements ITE<EjectorT
EjectorTileEntity ejectorTileEntity = teProvider.get(); EjectorTileEntity ejectorTileEntity = teProvider.get();
if (ejectorTileEntity.getState() == State.RETRACTING) if (ejectorTileEntity.getState() == State.RETRACTING)
return; return;
if (ejectorTileEntity.powered)
return;
if (ejectorTileEntity.launcher.getHorizontalDistance() == 0) if (ejectorTileEntity.launcher.getHorizontalDistance() == 0)
return; return;
@ -97,7 +108,7 @@ public class EjectorBlock extends HorizontalKineticBlock implements ITE<EjectorT
} }
} }
ejectorTileEntity.launchAll(); ejectorTileEntity.activate();
ejectorTileEntity.notifyUpdate(); ejectorTileEntity.notifyUpdate();
if (entityIn.world.isRemote) if (entityIn.world.isRemote)
AllPackets.channel.sendToServer(new EjectorTriggerPacket(ejectorTileEntity.getPos())); AllPackets.channel.sendToServer(new EjectorTriggerPacket(ejectorTileEntity.getPos()));

View file

@ -58,6 +58,8 @@ public class EjectorTileEntity extends KineticTileEntity {
DepotBehaviour depotBehaviour; DepotBehaviour depotBehaviour;
EntityLauncher launcher; EntityLauncher launcher;
LerpedFloat lidProgress; LerpedFloat lidProgress;
boolean powered;
boolean launch;
State state; State state;
public enum State { public enum State {
@ -71,6 +73,7 @@ public class EjectorTileEntity extends KineticTileEntity {
.startWithValue(1); .startWithValue(1);
state = State.RETRACTING; state = State.RETRACTING;
launchedItems = new ArrayList<>(); launchedItems = new ArrayList<>();
powered = false;
} }
@Override @Override
@ -92,10 +95,24 @@ public class EjectorTileEntity extends KineticTileEntity {
depotBehaviour.addSubBehaviours(behaviours); depotBehaviour.addSubBehaviours(behaviours);
} }
public void launchAll() { @Override
if (state != State.CHARGED && !(world.isRemote && state == State.LAUNCHING)) public void initialize() {
return; super.initialize();
updateSignal();
}
public void activate() {
launch = true;
nudgeEntities();
}
protected boolean cannotLaunch() {
return state != State.CHARGED && !(world.isRemote && state == State.LAUNCHING);
}
public void activateDeferred() {
if (cannotLaunch())
return;
Direction facing = getFacing(); Direction facing = getFacing();
List<Entity> entities = List<Entity> entities =
world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos).grow(-1 / 16f, 0, -1 / 16f)); world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos).grow(-1 / 16f, 0, -1 / 16f));
@ -135,12 +152,11 @@ public class EjectorTileEntity extends KineticTileEntity {
AllPackets.channel.sendToServer(new EjectorElytraPacket(pos)); AllPackets.channel.sendToServer(new EjectorElytraPacket(pos));
} }
lidProgress.chase(1, .8f, Chaser.EXP);
state = State.LAUNCHING;
if (!world.isRemote) { if (!world.isRemote) {
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_CLOSE, SoundCategory.BLOCKS, .5f, 1f); lidProgress.chase(1, .8f, Chaser.EXP);
world.playSound(null, pos, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, .125f, 1.4f); state = State.LAUNCHING;
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_CLOSE, SoundCategory.BLOCKS, .35f, 1f);
world.playSound(null, pos, SoundEvents.BLOCK_CHEST_OPEN, SoundCategory.BLOCKS, .1f, 1.4f);
} }
} }
@ -187,6 +203,9 @@ public class EjectorTileEntity extends KineticTileEntity {
return; return;
} }
if (!world.isRemote)
world.markAndNotifyBlock(pos, world.getChunkAt(pos), getBlockState(), getBlockState(), 0);
if (depotBehaviour.heldItem != null) { if (depotBehaviour.heldItem != null) {
launchedItems.add(IntAttached.withZero(heldItemStack)); launchedItems.add(IntAttached.withZero(heldItemStack));
depotBehaviour.removeHeldItem(); depotBehaviour.removeHeldItem();
@ -218,9 +237,13 @@ public class EjectorTileEntity extends KineticTileEntity {
boolean doLogic = !world.isRemote || isVirtual(); boolean doLogic = !world.isRemote || isVirtual();
State prevState = state; State prevState = state;
float maxTime = Math.max(3, (float) launcher.getTotalFlyingTicks()); float maxTime = Math.max(3, (float) launcher.getTotalFlyingTicks());
if (launch) {
launch = false;
activateDeferred();
}
for (Iterator<IntAttached<ItemStack>> iterator = launchedItems.iterator(); iterator.hasNext();) { for (Iterator<IntAttached<ItemStack>> iterator = launchedItems.iterator(); iterator.hasNext();) {
IntAttached<ItemStack> intAttached = iterator.next(); IntAttached<ItemStack> intAttached = iterator.next();
if (intAttached.exceeds((int) maxTime)) { if (intAttached.exceeds((int) maxTime)) {
@ -241,11 +264,19 @@ public class EjectorTileEntity extends KineticTileEntity {
if (state == State.CHARGED) { if (state == State.CHARGED) {
lidProgress.setValue(0); lidProgress.setValue(0);
lidProgress.updateChaseSpeed(0);
if (doLogic) if (doLogic)
ejectIfTriggered(); ejectIfTriggered();
} }
if (state == State.RETRACTING) { if (state == State.RETRACTING) {
lidProgress.updateChaseSpeed(0);
if (lidProgress.getValue() == 0 && doLogic) {
state = State.CHARGED;
lidProgress.setValue(0);
sendData();
}
float value = MathHelper.clamp(lidProgress.getValue() - getWindUpSpeed(), 0, 1); float value = MathHelper.clamp(lidProgress.getValue() - getWindUpSpeed(), 0, 1);
lidProgress.setValue(value); lidProgress.setValue(value);
@ -255,24 +286,22 @@ public class EjectorTileEntity extends KineticTileEntity {
if (((int) world.getGameTime()) % soundRate == 0 && doLogic) if (((int) world.getGameTime()) % soundRate == 0 && doLogic)
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_BUTTON_CLICK_OFF, SoundCategory.BLOCKS, volume, world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_BUTTON_CLICK_OFF, SoundCategory.BLOCKS, volume,
pitch); pitch);
if (lidProgress.getValue() == 0 && doLogic) {
state = State.CHARGED;
lidProgress.setValue(0);
List<Entity> entities =
world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos).grow(-1 / 16f, 0, -1 / 16f));
for (Entity entity : entities)
if (!(entity instanceof PlayerEntity))
entity.setPosition(entity.getX(), entity.getY() + volume, entity.getZ());
}
} }
if (state != prevState) if (state != prevState)
notifyUpdate(); notifyUpdate();
} }
protected void nudgeEntities() {
for (Entity entity : world.getEntitiesWithinAABB(Entity.class,
new AxisAlignedBB(pos).grow(-1 / 16f, 0, -1 / 16f)))
if (!(entity instanceof PlayerEntity))
entity.setPosition(entity.getX(), entity.getY() + .125f, entity.getZ());
}
protected void ejectIfTriggered() { protected void ejectIfTriggered() {
if (powered)
return;
int presentStackSize = depotBehaviour.getPresentStackSize(); int presentStackSize = depotBehaviour.getPresentStackSize();
if (presentStackSize == 0) if (presentStackSize == 0)
return; return;
@ -280,11 +309,11 @@ public class EjectorTileEntity extends KineticTileEntity {
return; return;
Direction funnelFacing = getFacing().getOpposite(); Direction funnelFacing = getFacing().getOpposite();
ItemStack held = depotBehaviour.getHeldItemStack();
if (AbstractFunnelBlock.getFunnelFacing(world.getBlockState(pos.up())) == funnelFacing) { if (AbstractFunnelBlock.getFunnelFacing(world.getBlockState(pos.up())) == funnelFacing) {
DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE); DirectBeltInputBehaviour directOutput = getBehaviour(DirectBeltInputBehaviour.TYPE);
if (depotBehaviour.heldItem != null) { if (depotBehaviour.heldItem != null) {
ItemStack tryFunnel = ItemStack tryFunnel = directOutput.tryExportingToBeltFunnel(held, funnelFacing, true);
directOutput.tryExportingToBeltFunnel(depotBehaviour.getHeldItemStack(), funnelFacing, true);
if (tryFunnel == null || !tryFunnel.isEmpty()) if (tryFunnel == null || !tryFunnel.isEmpty())
return; return;
} }
@ -294,11 +323,11 @@ public class EjectorTileEntity extends KineticTileEntity {
// Do not eject if target cannot accept held item // Do not eject if target cannot accept held item
if (targetOpenInv != null && depotBehaviour.heldItem != null if (targetOpenInv != null && depotBehaviour.heldItem != null
&& targetOpenInv.handleInsertion(depotBehaviour.getHeldItemStack(), Direction.UP, true) && targetOpenInv.handleInsertion(held, Direction.UP, true)
.isItemEqual(depotBehaviour.getHeldItemStack())) .getCount() == held.getCount())
return; return;
launchAll(); activate();
notifyUpdate(); notifyUpdate();
} }
@ -368,6 +397,7 @@ public class EjectorTileEntity extends KineticTileEntity {
super.write(compound, clientPacket); super.write(compound, clientPacket);
compound.putInt("HorizontalDistance", launcher.getHorizontalDistance()); compound.putInt("HorizontalDistance", launcher.getHorizontalDistance());
compound.putInt("VerticalDistance", launcher.getVerticalDistance()); compound.putInt("VerticalDistance", launcher.getVerticalDistance());
compound.putBoolean("Powered", powered);
NBTHelper.writeEnum(compound, "State", state); NBTHelper.writeEnum(compound, "State", state);
compound.put("Lid", lidProgress.writeNBT()); compound.put("Lid", lidProgress.writeNBT());
compound.put("LaunchedItems", compound.put("LaunchedItems",
@ -386,12 +416,21 @@ public class EjectorTileEntity extends KineticTileEntity {
launcher.clamp(AllConfigs.SERVER.kinetics.maxEjectorDistance.get()); launcher.clamp(AllConfigs.SERVER.kinetics.maxEjectorDistance.get());
} }
powered = compound.getBoolean("Powered");
state = NBTHelper.readEnum(compound, "State", State.class); state = NBTHelper.readEnum(compound, "State", State.class);
lidProgress.readNBT(compound.getCompound("Lid"), clientPacket); lidProgress.readNBT(compound.getCompound("Lid"), clientPacket);
launchedItems = NBTHelper.readCompoundList(compound.getList("LaunchedItems", NBT.TAG_COMPOUND), launchedItems = NBTHelper.readCompoundList(compound.getList("LaunchedItems", NBT.TAG_COMPOUND),
nbt -> IntAttached.read(nbt, ItemStack::read)); nbt -> IntAttached.read(nbt, ItemStack::read));
} }
public void updateSignal() {
boolean shoudPower = world.isBlockPowered(pos);
if (shoudPower == powered)
return;
powered = shoudPower;
sendData();
}
public void setTarget(int horizontalDistance, int verticalDistance) { public void setTarget(int horizontalDistance, int verticalDistance) {
launcher.set(Math.max(1, horizontalDistance), verticalDistance); launcher.set(Math.max(1, horizontalDistance), verticalDistance);
if (horizontalDistance == 0 && verticalDistance == 0) { if (horizontalDistance == 0 && verticalDistance == 0) {

View file

@ -23,7 +23,7 @@ public class EjectorTriggerPacket extends TileEntityConfigurationPacket<EjectorT
@Override @Override
protected void applySettings(EjectorTileEntity te) { protected void applySettings(EjectorTileEntity te) {
te.launchAll(); te.activate();
} }
} }

View file

@ -63,7 +63,7 @@ public class PonderTagScreen extends NavigatableSimiScreen {
.stream() .stream()
.filter(rl -> tag.getMainItem() .filter(rl -> tag.getMainItem()
.isEmpty() .isEmpty()
|| tag.getMainItem() || !tag.getMainItem()
.getItem() .getItem()
.getRegistryName() .getRegistryName()
.equals(rl)) .equals(rl))