Reworked the Belt Observer

- Belt observers now have four modes with different useful behaviours #83
- Fixed belt actors not syncing when items are not held in place but replaced
- Upward facing deployers can now act as item displays
- Fixed deployer fake players persisting after disassembling a portable contraption
- Creepers no longer take revenge on Deployers by default
This commit is contained in:
simibubi 2020-02-13 18:35:14 +01:00
parent 7dd29e9ffd
commit 6537214403
46 changed files with 454 additions and 82 deletions

View file

@ -6,6 +6,8 @@ public class CKinetics extends ConfigBase {
public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage); public ConfigInt crushingDamage = i(4, 0, "crushingDamage", Comments.crushingDamage);
public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed); public ConfigInt maxMotorSpeed = i(256, 64, "maxMotorSpeed", Comments.rpm, Comments.maxMotorSpeed);
public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed); public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed);
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
public ConfigGroup fan = group(0, "encasedFan", "Encased Fan"); public ConfigGroup fan = group(0, "encasedFan", "Encased Fan");
public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance); public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance);
@ -24,7 +26,8 @@ public class CKinetics extends ConfigBase {
public ConfigGroup state = group(0, "stats", Comments.stats); public ConfigGroup state = group(0, "stats", Comments.stats);
public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed); public ConfigFloat mediumSpeed = f(30, 0, 4096, "mediumSpeed", Comments.rpm, Comments.mediumSpeed);
public ConfigFloat fastSpeed = f(100, 0, 65535, "fastSpeed", Comments.rpm, Comments.fastSpeed); public ConfigFloat fastSpeed = f(100, 0, 65535, "fastSpeed", Comments.rpm, Comments.fastSpeed);
public ConfigFloat mediumStressImpact = f(8, 0, 4096, "mediumStressImpact", Comments.su, Comments.mediumStressImpact); public ConfigFloat mediumStressImpact =
f(8, 0, 4096, "mediumStressImpact", Comments.su, Comments.mediumStressImpact);
public ConfigFloat highStressImpact = f(32, 0, 65535, "highStressImpact", Comments.su, Comments.highStressImpact); public ConfigFloat highStressImpact = f(32, 0, 65535, "highStressImpact", Comments.su, Comments.highStressImpact);
public ConfigFloat mediumCapacity = f(128, 0, 4096, "mediumCapacity", Comments.su, Comments.mediumCapacity); public ConfigFloat mediumCapacity = f(128, 0, 4096, "mediumCapacity", Comments.su, Comments.mediumCapacity);
public ConfigFloat highCapacity = f(512, 0, 65535, "highCapacity", Comments.su, Comments.highCapacity); public ConfigFloat highCapacity = f(512, 0, 65535, "highCapacity", Comments.su, Comments.highCapacity);
@ -61,6 +64,11 @@ public class CKinetics extends ConfigBase {
static String mediumCapacity = "Minimum added Capacity by sources to be considered 'medium'"; static String mediumCapacity = "Minimum added Capacity by sources to be considered 'medium'";
static String highCapacity = "Minimum added Capacity by sources to be considered 'high'"; static String highCapacity = "Minimum added Capacity by sources to be considered 'high'";
static String stress = "Fine tune the kinetic stats of individual components"; static String stress = "Fine tune the kinetic stats of individual components";
static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them.";
}
public static enum DeployerAggroSetting {
ALL, CREEPERS, NONE
} }
} }

View file

@ -10,6 +10,7 @@ import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.Builder; import net.minecraftforge.common.ForgeConfigSpec.Builder;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import net.minecraftforge.common.ForgeConfigSpec.DoubleValue; import net.minecraftforge.common.ForgeConfigSpec.DoubleValue;
import net.minecraftforge.common.ForgeConfigSpec.EnumValue;
import net.minecraftforge.common.ForgeConfigSpec.IntValue; import net.minecraftforge.common.ForgeConfigSpec.IntValue;
public abstract class ConfigBase { public abstract class ConfigBase {
@ -62,6 +63,10 @@ public abstract class ConfigBase {
return i(current, min, Integer.MAX_VALUE, name, comment); return i(current, min, Integer.MAX_VALUE, name, comment);
} }
protected <T extends Enum<T>> ConfigEnum<T> e(T defaultValue, String name, String... comment) {
return new ConfigEnum<>(name, defaultValue, comment);
}
protected ConfigGroup group(int depth, String name, String... comment) { protected ConfigGroup group(int depth, String name, String... comment) {
return new ConfigGroup(name, depth, comment); return new ConfigGroup(name, depth, comment);
} }
@ -154,6 +159,14 @@ public abstract class ConfigBase {
} }
} }
public class ConfigEnum<T extends Enum<T>> extends CValue<T, EnumValue<T>> {
public ConfigEnum(String name, T defaultValue, String[] comment) {
super(name, builder -> builder.defineEnum(name, defaultValue), comment);
}
}
public class ConfigFloat extends CValue<Double, DoubleValue> { public class ConfigFloat extends CValue<Double, DoubleValue> {
public ConfigFloat(String name, float current, float min, float max, String... comment) { public ConfigFloat(String name, float current, float min, float max, String... comment) {

View file

@ -6,12 +6,17 @@ import java.util.UUID;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.config.CKinetics;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MobEntity;
import net.minecraft.entity.Pose; import net.minecraft.entity.Pose;
import net.minecraft.entity.monster.CreeperEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -32,6 +37,7 @@ import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.EntityEvent; import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingExperienceDropEvent; import net.minecraftforge.event.entity.living.LivingExperienceDropEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@ -107,6 +113,30 @@ public class DeployerFakePlayer extends FakePlayer {
event.setCanceled(true); event.setCanceled(true);
} }
@SubscribeEvent
public static void entitiesDontRetaliate(LivingSetAttackTargetEvent event) {
if (!(event.getTarget() instanceof DeployerFakePlayer))
return;
LivingEntity entityLiving = event.getEntityLiving();
if (!(entityLiving instanceof MobEntity))
return;
MobEntity mob = (MobEntity) entityLiving;
CKinetics.DeployerAggroSetting setting = AllConfigs.SERVER.kinetics.ignoreDeployerAttacks.get();
switch (setting) {
case ALL:
mob.setAttackTarget(null);
break;
case CREEPERS:
if (mob instanceof CreeperEntity)
mob.setAttackTarget(null);
break;
case NONE:
default:
}
}
private static class FakePlayNetHandler extends ServerPlayNetHandler { private static class FakePlayNetHandler extends ServerPlayNetHandler {
public FakePlayNetHandler(MinecraftServer server, ServerPlayerEntity playerIn) { public FakePlayNetHandler(MinecraftServer server, ServerPlayerEntity playerIn) {
super(server, NETWORK_MANAGER, playerIn); super(server, NETWORK_MANAGER, playerIn);

View file

@ -91,6 +91,10 @@ public class DeployerMovementBehaviour extends MovementBehaviour {
if (context.world.isRemote) if (context.world.isRemote)
return; return;
tryDisposeOfEverything(context); tryDisposeOfEverything(context);
DeployerFakePlayer player = getPlayer(context);
if (player == null)
return;
player.remove();
} }
private void tryGrabbingItem(MovementContext context) { private void tryGrabbingItem(MovementContext context) {

View file

@ -13,6 +13,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.behaviour.filtering.FilteringRenderer; import com.simibubi.create.foundation.behaviour.filtering.FilteringRenderer;
import com.simibubi.create.foundation.block.SafeTileEntityRenderer; import com.simibubi.create.foundation.block.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.TessellatorHelper; import com.simibubi.create.foundation.utility.TessellatorHelper;
@ -62,22 +63,37 @@ public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerT
float yRot = AngleHelper.horizontalAngle(facing) + 180; float yRot = AngleHelper.horizontalAngle(facing) + 180;
float zRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; float zRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0;
boolean displayMode = facing == Direction.UP && te.speed == 0 && !punching;
GlStateManager.rotatef(yRot, 0, 1, 0); GlStateManager.rotatef(yRot, 0, 1, 0);
GlStateManager.rotatef(zRot, 1, 0, 0); if (!displayMode) {
GlStateManager.translated(0, 0, -11 / 16f); GlStateManager.rotatef(zRot, 1, 0, 0);
GlStateManager.translated(0, 0, -11 / 16f);
}
if (punching) if (punching)
GlStateManager.translatef(0, 1 / 8f, -1 / 16f); GlStateManager.translatef(0, 1 / 8f, -1 / 16f);
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
boolean isBlockItem =
(te.heldItem.getItem() instanceof BlockItem) && itemRenderer.getModelWithOverrides(te.heldItem).isGui3d();
float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f;
GlStateManager.scaled(scale, scale, scale);
TransformType transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED;
itemRenderer.renderItem(te.heldItem, transform);
TransformType transform = TransformType.NONE;
boolean isBlockItem = (te.heldItem.getItem() instanceof BlockItem)
&& itemRenderer.getModelWithOverrides(te.heldItem).isGui3d();
if (displayMode) {
float scale = isBlockItem ? 1.25f : 1;
GlStateManager.translated(0, isBlockItem ? 9 / 16f : 11 / 16f, 0);
GlStateManager.scaled(scale, scale, scale);
transform = TransformType.GROUND;
GlStateManager.rotatef(AnimationTickHolder.getRenderTick(), 0, 1, 0);
} else {
float scale = punching ? .75f : isBlockItem ? .75f - 1 / 64f : .5f;
GlStateManager.scaled(scale, scale, scale);
transform = punching ? TransformType.THIRD_PERSON_RIGHT_HAND : TransformType.FIXED;
}
itemRenderer.renderItem(te.heldItem, transform);
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }

View file

@ -137,12 +137,15 @@ public class BeltInventory {
if (beltSegment == null) if (beltSegment == null)
break; break;
for (BeltAttachmentState attachmentState : beltSegment.attachmentTracker.attachments) { for (BeltAttachmentState attachmentState : beltSegment.attachmentTracker.attachments) {
ItemStack stackBefore = current.stack.copy();
if (attachmentState.attachment.startProcessingItem(beltSegment, current, attachmentState)) { if (attachmentState.attachment.startProcessingItem(beltSegment, current, attachmentState)) {
current.beltPosition = segment + .5f + (beltMovementPositive ? 1 / 64f : -1 / 64f); current.beltPosition = segment + .5f + (beltMovementPositive ? 1 / 64f : -1 / 64f);
current.locked = true; current.locked = true;
belt.sendData(); belt.sendData();
continue Items; continue Items;
} }
if (!stackBefore.equals(current.stack, true))
belt.sendData();
} }
} }
} }

View file

@ -290,6 +290,12 @@ public class BeltTileEntity extends KineticTileEntity {
} }
public BeltInventory getInventory() { public BeltInventory getInventory() {
if (!isController()) {
BeltTileEntity controllerTE = getControllerTE();
if (controllerTE != null)
return controllerTE.getInventory();
return null;
}
if (inventory == null) if (inventory == null)
inventory = new BeltInventory(this); inventory = new BeltInventory(this);
return inventory; return inventory;

View file

@ -8,7 +8,9 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.IWrenchable;
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState; import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment; import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock; import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
@ -22,22 +24,33 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.BooleanProperty; import net.minecraft.state.BooleanProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
public class BeltObserverBlock extends HorizontalBlock public class BeltObserverBlock extends HorizontalBlock
implements IWithTileEntity<BeltObserverTileEntity>, IBeltAttachment { implements IWithTileEntity<BeltObserverTileEntity>, IBeltAttachment, IWrenchable {
public static BooleanProperty POWERED = BlockStateProperties.POWERED; public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static BooleanProperty BELT = BooleanProperty.create("belt"); public static final BooleanProperty BELT = BooleanProperty.create("belt");
public static final EnumProperty<Mode> MODE = EnumProperty.create("mode", Mode.class);
public BeltObserverBlock() { public BeltObserverBlock() {
super(Properties.from(Blocks.ANDESITE)); super(Properties.from(Blocks.ANDESITE));
@ -64,7 +77,7 @@ public class BeltObserverBlock extends HorizontalBlock
@Override @Override
protected void fillStateContainer(Builder<Block, BlockState> builder) { protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(POWERED, HORIZONTAL_FACING, BELT); builder.add(POWERED, HORIZONTAL_FACING, BELT, MODE);
super.fillStateContainer(builder); super.fillStateContainer(builder);
} }
@ -167,52 +180,93 @@ public class BeltObserverBlock extends HorizontalBlock
@Override @Override
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) { public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
state.processingDuration = 0; World world = te.getWorld();
FilteringBehaviour behaviour = TileEntityBehaviour.get(te.getWorld(), state.attachmentPos, BlockState blockState = world.getBlockState(state.attachmentPos);
FilteringBehaviour.TYPE); if (blockState.get(MODE) == Mode.DETECT)
if (behaviour != null) { return false;
if (!behaviour.test(transported.stack)) {
state.processingDuration = -1; FilteringBehaviour behaviour =
return false; TileEntityBehaviour.get(te.getWorld(), state.attachmentPos, FilteringBehaviour.TYPE);
if (behaviour != null && !behaviour.test(transported.stack))
return false;
world.setBlockState(state.attachmentPos, blockState.with(POWERED, true));
world.notifyNeighborsOfStateChange(state.attachmentPos, this);
withTileEntityDo(world, state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
Mode mode = blockState.get(MODE);
if (mode == Mode.EJECT || mode == Mode.SPLIT) {
ItemStack copy = transported.stack.copy();
ItemStack toEject = mode == Mode.EJECT ? transported.stack : copy.split(transported.stack.getCount() / 2);
if (!toEject.isEmpty()) {
if (!eject(world, toEject, state.attachmentPos, blockState.get(HORIZONTAL_FACING)))
return true;
transported.stack = mode == Mode.EJECT ? ItemStack.EMPTY : copy;
} }
} }
return false;
}
@Override
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
World world = te.getWorld(); World world = te.getWorld();
BlockState blockState = world.getBlockState(state.attachmentPos); BlockState blockState = world.getBlockState(state.attachmentPos);
if (state.processingDuration == 0) { withTileEntityDo(world, state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
world.setBlockState(state.attachmentPos, blockState.with(POWERED, true));
world.getPendingBlockTicks().scheduleTick(state.attachmentPos, this, 6); Mode mode = blockState.get(MODE);
world.notifyNeighborsOfStateChange(state.attachmentPos, this); if (mode == Mode.EJECT || mode == Mode.SPLIT) {
return true; ItemStack copy = transported.stack.copy();
ItemStack toEject = mode == Mode.EJECT ? transported.stack : copy.split(transported.stack.getCount() / 2);
if (!eject(world, toEject, state.attachmentPos, blockState.get(HORIZONTAL_FACING)))
return true;
transported.stack = mode == Mode.EJECT ? ItemStack.EMPTY : copy;
} }
return false; return false;
} }
private boolean eject(World world, ItemStack stack, BlockPos observerPos, Direction facing) {
BlockPos potentialBeltPos = observerPos.offset(facing, 2);
TileEntity tileEntity = world.getTileEntity(potentialBeltPos);
if (tileEntity instanceof BeltTileEntity) {
BeltTileEntity belt = (BeltTileEntity) tileEntity;
return belt.tryInsertingFromSide(facing, stack, false);
}
boolean empty = world.getBlockState(potentialBeltPos).getCollisionShape(world, potentialBeltPos).isEmpty();
float yOffset = empty ? 0 : .5f;
AxisAlignedBB bb = new AxisAlignedBB(empty ? potentialBeltPos : potentialBeltPos.up());
if (!world.getEntitiesWithinAABBExcludingEntity(null, bb).isEmpty())
return false;
Vec3d motion = new Vec3d(facing.getDirectionVec()).scale(1 / 16f);
Vec3d entityPos = VecHelper.getCenterOf(potentialBeltPos).add(0, yOffset + .25f, 0).subtract(motion);
ItemEntity entity = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, stack);
entity.setMotion(motion);
entity.setPickupDelay(5);
world.playSound(null, observerPos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, .1f);
world.addEntity(entity);
return true;
}
@Override @Override
public boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) { public boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
if (te.getWorld().isRemote) if (te.getWorld().isRemote)
return false; return false;
if (state.processingEntity != entity) {
state.processingEntity = entity;
state.processingDuration = 0;
}
if (entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos())) > .5f) if (entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos())) > .5f)
return false; return false;
if (state.processingDuration == -1) {
return false;
}
World world = te.getWorld(); World world = te.getWorld();
BlockState blockState = world.getBlockState(state.attachmentPos); BlockState blockState = world.getBlockState(state.attachmentPos);
if (blockState.get(POWERED)) if (blockState.get(POWERED))
return false; return false;
state.processingDuration = -1;
world.setBlockState(state.attachmentPos, blockState.with(POWERED, true)); world.setBlockState(state.attachmentPos, blockState.with(POWERED, true));
world.getPendingBlockTicks().scheduleTick(state.attachmentPos, this, 6);
world.notifyNeighborsOfStateChange(state.attachmentPos, this); world.notifyNeighborsOfStateChange(state.attachmentPos, this);
withTileEntityDo(te.getWorld(), state.attachmentPos, BeltObserverTileEntity::resetTurnOffCooldown);
return false; return false;
} }
@ -222,4 +276,23 @@ public class BeltObserverBlock extends HorizontalBlock
worldIn.notifyNeighborsOfStateChange(pos, this); worldIn.notifyNeighborsOfStateChange(pos, this);
} }
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
World world = context.getWorld();
if (!world.isRemote) {
world.setBlockState(context.getPos(), state.with(POWERED, false).cycle(MODE), 3);
world.notifyNeighborsOfStateChange(context.getPos(), this);
}
return ActionResultType.SUCCESS;
}
public enum Mode implements IStringSerializable {
DETECT, PULSE, EJECT, SPLIT;
@Override
public String getName() {
return Lang.asId(name());
}
}
} }

View file

@ -9,8 +9,12 @@ import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour.SlotPositioning; import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour.SlotPositioning;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.belts.BeltObserverBlock.Mode;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -18,9 +22,65 @@ public class BeltObserverTileEntity extends SmartTileEntity {
private static FilteringBehaviour.SlotPositioning slots; private static FilteringBehaviour.SlotPositioning slots;
private FilteringBehaviour filtering; private FilteringBehaviour filtering;
public int turnOffTicks = 0;
public BeltObserverTileEntity() { public BeltObserverTileEntity() {
super(AllTileEntities.ENTITY_DETECTOR.type); super(AllTileEntities.ENTITY_DETECTOR.type);
setLazyTickRate(20);
}
@Override
public void tick() {
super.tick();
if (turnOffTicks > 0) {
turnOffTicks--;
if (turnOffTicks == 0)
world.getPendingBlockTicks().scheduleTick(pos, getBlockState().getBlock(), 1);
}
if (!isActive())
return;
if (getBlockState().get(BeltObserverBlock.MODE) != Mode.DETECT)
return;
TileEntity tileEntity =
world.getTileEntity(pos.offset(getBlockState().get(BeltObserverBlock.HORIZONTAL_FACING)));
if (!(tileEntity instanceof BeltTileEntity))
return;
BeltTileEntity belt = (BeltTileEntity) tileEntity;
BeltTileEntity controllerTE = belt.getControllerTE();
if (controllerTE == null)
return;
controllerTE.getInventory().forEachWithin(belt.index + .5f, .45f, stack -> {
if (filtering.test(stack.stack) && turnOffTicks != 6) {
world.setBlockState(pos, getBlockState().with(BeltObserverBlock.POWERED, true));
world.notifyNeighborsOfStateChange(pos, getBlockState().getBlock());
resetTurnOffCooldown();
}
return null;
});
}
private boolean isActive() {
return getBlockState().get(BeltObserverBlock.BELT);
}
public void resetTurnOffCooldown() {
turnOffTicks = 6;
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.putInt("TurnOff", turnOffTicks);
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
turnOffTicks = compound.getInt("TurnOff");
super.read(compound);
} }
@Override @Override

View file

@ -1,23 +1,86 @@
{ {
"variants": { "variants": {
"powered=false,belt=false,facing=south": { "model": "create:block/entity_detector", "y": 0 }, "mode=detect,powered=false,belt=false,facing=south": { "model": "create:block/belt_observer/detect", "y": 0 },
"powered=false,belt=false,facing=east": { "model": "create:block/entity_detector", "y": 270 }, "mode=detect,powered=false,belt=false,facing=east": { "model": "create:block/belt_observer/detect", "y": 270 },
"powered=false,belt=false,facing=north": { "model": "create:block/entity_detector", "y": 180 }, "mode=detect,powered=false,belt=false,facing=north": { "model": "create:block/belt_observer/detect", "y": 180 },
"powered=false,belt=false,facing=west": { "model": "create:block/entity_detector", "y": 90 }, "mode=detect,powered=false,belt=false,facing=west": { "model": "create:block/belt_observer/detect", "y": 90 },
"powered=true,belt=false,facing=south": { "model": "create:block/entity_detector_powered", "y": 0 }, "mode=detect,powered=true,belt=false,facing=south": { "model": "create:block/belt_observer/detect_powered", "y": 0 },
"powered=true,belt=false,facing=east": { "model": "create:block/entity_detector_powered", "y": 270 }, "mode=detect,powered=true,belt=false,facing=east": { "model": "create:block/belt_observer/detect_powered", "y": 270 },
"powered=true,belt=false,facing=north": { "model": "create:block/entity_detector_powered", "y": 180 }, "mode=detect,powered=true,belt=false,facing=north": { "model": "create:block/belt_observer/detect_powered", "y": 180 },
"powered=true,belt=false,facing=west": { "model": "create:block/entity_detector_powered", "y": 90 }, "mode=detect,powered=true,belt=false,facing=west": { "model": "create:block/belt_observer/detect_powered", "y": 90 },
"powered=false,belt=true,facing=south": { "model": "create:block/entity_detector_with_belt", "y": 0 }, "mode=detect,powered=false,belt=true,facing=south": { "model": "create:block/belt_observer/detect_belt", "y": 0 },
"powered=false,belt=true,facing=east": { "model": "create:block/entity_detector_with_belt", "y": 270 }, "mode=detect,powered=false,belt=true,facing=east": { "model": "create:block/belt_observer/detect_belt", "y": 270 },
"powered=false,belt=true,facing=north": { "model": "create:block/entity_detector_with_belt", "y": 180 }, "mode=detect,powered=false,belt=true,facing=north": { "model": "create:block/belt_observer/detect_belt", "y": 180 },
"powered=false,belt=true,facing=west": { "model": "create:block/entity_detector_with_belt", "y": 90 }, "mode=detect,powered=false,belt=true,facing=west": { "model": "create:block/belt_observer/detect_belt", "y": 90 },
"powered=true,belt=true,facing=south": { "model": "create:block/entity_detector_with_belt_powered", "y": 0 }, "mode=detect,powered=true,belt=true,facing=south": { "model": "create:block/belt_observer/detect_belt_powered", "y": 0 },
"powered=true,belt=true,facing=east": { "model": "create:block/entity_detector_with_belt_powered", "y": 270 }, "mode=detect,powered=true,belt=true,facing=east": { "model": "create:block/belt_observer/detect_belt_powered", "y": 270 },
"powered=true,belt=true,facing=north": { "model": "create:block/entity_detector_with_belt_powered", "y": 180 }, "mode=detect,powered=true,belt=true,facing=north": { "model": "create:block/belt_observer/detect_belt_powered", "y": 180 },
"powered=true,belt=true,facing=west": { "model": "create:block/entity_detector_with_belt_powered", "y": 90 } "mode=detect,powered=true,belt=true,facing=west": { "model": "create:block/belt_observer/detect_belt_powered", "y": 90 },
"mode=pulse,powered=false,belt=false,facing=south": { "model": "create:block/belt_observer/pulse", "y": 0 },
"mode=pulse,powered=false,belt=false,facing=east": { "model": "create:block/belt_observer/pulse", "y": 270 },
"mode=pulse,powered=false,belt=false,facing=north": { "model": "create:block/belt_observer/pulse", "y": 180 },
"mode=pulse,powered=false,belt=false,facing=west": { "model": "create:block/belt_observer/pulse", "y": 90 },
"mode=pulse,powered=true,belt=false,facing=south": { "model": "create:block/belt_observer/pulse_powered", "y": 0 },
"mode=pulse,powered=true,belt=false,facing=east": { "model": "create:block/belt_observer/pulse_powered", "y": 270 },
"mode=pulse,powered=true,belt=false,facing=north": { "model": "create:block/belt_observer/pulse_powered", "y": 180 },
"mode=pulse,powered=true,belt=false,facing=west": { "model": "create:block/belt_observer/pulse_powered", "y": 90 },
"mode=pulse,powered=false,belt=true,facing=south": { "model": "create:block/belt_observer/pulse_belt", "y": 0 },
"mode=pulse,powered=false,belt=true,facing=east": { "model": "create:block/belt_observer/pulse_belt", "y": 270 },
"mode=pulse,powered=false,belt=true,facing=north": { "model": "create:block/belt_observer/pulse_belt", "y": 180 },
"mode=pulse,powered=false,belt=true,facing=west": { "model": "create:block/belt_observer/pulse_belt", "y": 90 },
"mode=pulse,powered=true,belt=true,facing=south": { "model": "create:block/belt_observer/pulse_belt_powered", "y": 0 },
"mode=pulse,powered=true,belt=true,facing=east": { "model": "create:block/belt_observer/pulse_belt_powered", "y": 270 },
"mode=pulse,powered=true,belt=true,facing=north": { "model": "create:block/belt_observer/pulse_belt_powered", "y": 180 },
"mode=pulse,powered=true,belt=true,facing=west": { "model": "create:block/belt_observer/pulse_belt_powered", "y": 90 },
"mode=eject,powered=false,belt=false,facing=south": { "model": "create:block/belt_observer/eject", "y": 0 },
"mode=eject,powered=false,belt=false,facing=east": { "model": "create:block/belt_observer/eject", "y": 270 },
"mode=eject,powered=false,belt=false,facing=north": { "model": "create:block/belt_observer/eject", "y": 180 },
"mode=eject,powered=false,belt=false,facing=west": { "model": "create:block/belt_observer/eject", "y": 90 },
"mode=eject,powered=true,belt=false,facing=south": { "model": "create:block/belt_observer/eject_powered", "y": 0 },
"mode=eject,powered=true,belt=false,facing=east": { "model": "create:block/belt_observer/eject_powered", "y": 270 },
"mode=eject,powered=true,belt=false,facing=north": { "model": "create:block/belt_observer/eject_powered", "y": 180 },
"mode=eject,powered=true,belt=false,facing=west": { "model": "create:block/belt_observer/eject_powered", "y": 90 },
"mode=eject,powered=false,belt=true,facing=south": { "model": "create:block/belt_observer/eject_belt", "y": 0 },
"mode=eject,powered=false,belt=true,facing=east": { "model": "create:block/belt_observer/eject_belt", "y": 270 },
"mode=eject,powered=false,belt=true,facing=north": { "model": "create:block/belt_observer/eject_belt", "y": 180 },
"mode=eject,powered=false,belt=true,facing=west": { "model": "create:block/belt_observer/eject_belt", "y": 90 },
"mode=eject,powered=true,belt=true,facing=south": { "model": "create:block/belt_observer/eject_belt_powered", "y": 0 },
"mode=eject,powered=true,belt=true,facing=east": { "model": "create:block/belt_observer/eject_belt_powered", "y": 270 },
"mode=eject,powered=true,belt=true,facing=north": { "model": "create:block/belt_observer/eject_belt_powered", "y": 180 },
"mode=eject,powered=true,belt=true,facing=west": { "model": "create:block/belt_observer/eject_belt_powered", "y": 90 },
"mode=split,powered=false,belt=false,facing=south": { "model": "create:block/belt_observer/split", "y": 0 },
"mode=split,powered=false,belt=false,facing=east": { "model": "create:block/belt_observer/split", "y": 270 },
"mode=split,powered=false,belt=false,facing=north": { "model": "create:block/belt_observer/split", "y": 180 },
"mode=split,powered=false,belt=false,facing=west": { "model": "create:block/belt_observer/split", "y": 90 },
"mode=split,powered=true,belt=false,facing=south": { "model": "create:block/belt_observer/split_powered", "y": 0 },
"mode=split,powered=true,belt=false,facing=east": { "model": "create:block/belt_observer/split_powered", "y": 270 },
"mode=split,powered=true,belt=false,facing=north": { "model": "create:block/belt_observer/split_powered", "y": 180 },
"mode=split,powered=true,belt=false,facing=west": { "model": "create:block/belt_observer/split_powered", "y": 90 },
"mode=split,powered=false,belt=true,facing=south": { "model": "create:block/belt_observer/split_belt", "y": 0 },
"mode=split,powered=false,belt=true,facing=east": { "model": "create:block/belt_observer/split_belt", "y": 270 },
"mode=split,powered=false,belt=true,facing=north": { "model": "create:block/belt_observer/split_belt", "y": 180 },
"mode=split,powered=false,belt=true,facing=west": { "model": "create:block/belt_observer/split_belt", "y": 90 },
"mode=split,powered=true,belt=true,facing=south": { "model": "create:block/belt_observer/split_belt_powered", "y": 0 },
"mode=split,powered=true,belt=true,facing=east": { "model": "create:block/belt_observer/split_belt_powered", "y": 270 },
"mode=split,powered=true,belt=true,facing=north": { "model": "create:block/belt_observer/split_belt_powered", "y": 180 },
"mode=split,powered=true,belt=true,facing=west": { "model": "create:block/belt_observer/split_belt_powered", "y": 90 }
} }
} }

View file

@ -953,11 +953,15 @@
"block.create.brass_casing.tooltip.behaviour1": "_Reinforces_ _belts_ with a brass foundation. Reinforced Belts can support _Belt_ _Tunnels_ aswell as _Extractors,_ _Funnels_ and _Transposers_ interacting with the belt from the sides and below.", "block.create.brass_casing.tooltip.behaviour1": "_Reinforces_ _belts_ with a brass foundation. Reinforced Belts can support _Belt_ _Tunnels_ aswell as _Extractors,_ _Funnels_ and _Transposers_ interacting with the belt from the sides and below.",
"block.create.entity_detector.tooltip": "BELT OBSERVER", "block.create.entity_detector.tooltip": "BELT OBSERVER",
"block.create.entity_detector.tooltip.summary": "Detects items passing by on a _Mechanical_ _Belt_ in front of it. Works well with a _Piston_ on top, pushing certain items off.", "block.create.entity_detector.tooltip.summary": "Detects items and entities passing by on a _Mechanical_ _Belt_ in front of it. Use a _Wrench_ to cycle its behaviour. Non-items will always be handled in detect mode regarless of the setting.",
"block.create.entity_detector.tooltip.condition1": "When item matches Filter", "block.create.entity_detector.tooltip.condition1": "Detect Mode",
"block.create.entity_detector.tooltip.behaviour1": "Provides a short _Redstone_ _pulse_ to all sides. An Empty Filter matches all passing items.", "block.create.entity_detector.tooltip.behaviour1": "Provides redstone _while_ a _matching_ _item_ _is_ in the observed belt segment.",
"block.create.entity_detector.tooltip.control1": "R-Click on Filter Space", "block.create.entity_detector.tooltip.condition2": "Pulse Mode",
"block.create.entity_detector.tooltip.action1": "Assigns currently _held_ _stack_ as the _Filter._ Observer will react to this item type only.", "block.create.entity_detector.tooltip.behaviour2": "Emits a _pulse_ when a _matching_ _item_ _passes_ the center of the observed belt segment.",
"block.create.entity_detector.tooltip.condition3": "Eject Mode",
"block.create.entity_detector.tooltip.behaviour3": "_Ejects_ _matching_ _items_ off the side. If the target belt or space is _occupied,_ the item will be _held_ _in_ _place._",
"block.create.entity_detector.tooltip.condition4": "Split Mode",
"block.create.entity_detector.tooltip.behaviour4": "_Splits_ a _matching_ _item_ _stack_ and _ejects_ _half_ of it off the side.",
"block.create.pulse_repeater.tooltip": "PULSE REPEATER", "block.create.pulse_repeater.tooltip": "PULSE REPEATER",
"block.create.pulse_repeater.tooltip.summary": "A simple circuit for cutting passing redstone signals to a length of _1_ _tick._", "block.create.pulse_repeater.tooltip.summary": "A simple circuit for cutting passing redstone signals to a length of _1_ _tick._",

View file

@ -4,9 +4,9 @@
"textures": { "textures": {
"brass_casing": "create:block/brass_casing", "brass_casing": "create:block/brass_casing",
"extractor": "create:block/extractor", "extractor": "create:block/extractor",
"particle": "create:block/entity_detector_off", "particle": "#texture",
"entity_detector_off": "create:block/entity_detector_off", "entity_detector_off": "#texture",
"entity_detector_front": "create:block/entity_detector_front" "entity_detector_front": "create:block/belt_observer_front"
}, },
"elements": [ "elements": [
{ {

View file

@ -4,9 +4,9 @@
"textures": { "textures": {
"3": "create:block/extractor", "3": "create:block/extractor",
"brass_casing": "create:block/brass_casing", "brass_casing": "create:block/brass_casing",
"particle": "create:block/entity_detector_off", "particle": "#texture",
"entity_detector_off": "create:block/entity_detector_off", "entity_detector_off": "#texture",
"entity_detector_front": "create:block/entity_detector_front" "entity_detector_front": "create:block/belt_observer_front"
}, },
"elements": [ "elements": [
{ {

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt",
"textures": {
"3": "create:block/extractor_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base",
"textures": {
"extractor": "create:block/extractor_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base",
"textures": {
"texture": "create:block/belt_observer_detect"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt",
"textures": {
"texture": "create:block/belt_observer_detect"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt_powered",
"textures": {
"texture": "create:block/belt_observer_detect_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_powered",
"textures": {
"texture": "create:block/belt_observer_detect_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base",
"textures": {
"texture": "create:block/belt_observer_eject"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt",
"textures": {
"texture": "create:block/belt_observer_eject"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt_powered",
"textures": {
"texture": "create:block/belt_observer_eject_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_powered",
"textures": {
"texture": "create:block/belt_observer_eject_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base",
"textures": {
"texture": "create:block/belt_observer_pulse"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt",
"textures": {
"texture": "create:block/belt_observer_pulse"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt_powered",
"textures": {
"texture": "create:block/belt_observer_pulse_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_powered",
"textures": {
"texture": "create:block/belt_observer_pulse_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base",
"textures": {
"texture": "create:block/belt_observer_split"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt",
"textures": {
"texture": "create:block/belt_observer_split"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_belt_powered",
"textures": {
"texture": "create:block/belt_observer_split_powered"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/belt_observer/base_powered",
"textures": {
"texture": "create:block/belt_observer_split_powered"
}
}

View file

@ -1,8 +0,0 @@
{
"parent": "create:block/entity_detector",
"textures": {
"extractor": "create:block/extractor_powered",
"entity_detector_off": "create:block/entity_detector_on",
"particle": "create:block/entity_detector_on"
}
}

View file

@ -1,8 +0,0 @@
{
"parent": "create:block/entity_detector_with_belt",
"textures": {
"3": "create:block/extractor_powered",
"entity_detector_off": "create:block/entity_detector_on",
"particle": "create:block/entity_detector_on"
}
}

View file

@ -15,8 +15,8 @@
}, },
"textures": { "textures": {
"brass_casing": "create:block/brass_casing", "brass_casing": "create:block/brass_casing",
"entity_detector_off": "create:block/entity_detector_off", "entity_detector_off": "create:block/belt_observer_detect",
"entity_detector_front": "create:block/entity_detector_front" "entity_detector_front": "create:block/belt_observer_front"
}, },
"elements": [ "elements": [
{ {

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B