The Filter Brothers

- Torque generators no longer show stress impact levels
- Added Filters for matching outputs against a group of items / nested filters
- Added Attribute Filters for matching outputs against a collection of item properties
- Extraction count on Extractors and Transposers can now be adjusted through scrolling on the value box
This commit is contained in:
simibubi 2020-01-19 19:29:39 +01:00
parent d40fd52043
commit 40e9a1ee41
47 changed files with 1870 additions and 79 deletions

View file

@ -3,6 +3,10 @@ package com.simibubi.create;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.logistics.block.inventories.FlexcrateContainer;
import com.simibubi.create.modules.logistics.block.inventories.FlexcrateScreen;
import com.simibubi.create.modules.logistics.item.filter.AttributeFilterContainer;
import com.simibubi.create.modules.logistics.item.filter.AttributeFilterScreen;
import com.simibubi.create.modules.logistics.item.filter.FilterContainer;
import com.simibubi.create.modules.logistics.item.filter.FilterScreen;
import com.simibubi.create.modules.logistics.management.controller.LogisticalInventoryControllerContainer;
import com.simibubi.create.modules.logistics.management.controller.LogisticalInventoryControllerScreen;
import com.simibubi.create.modules.logistics.management.index.LogisticalIndexContainer;
@ -33,6 +37,9 @@ public enum AllContainers {
LOGISTICAL_INDEX(LogisticalIndexContainer::new),
LOGISTICAL_CONTROLLER(LogisticalInventoryControllerContainer::new),
FILTER(FilterContainer::new),
ATTRIBUTE_FILTER(AttributeFilterContainer::new),
;
public ContainerType<? extends Container> type;
@ -57,6 +64,8 @@ public enum AllContainers {
bind(FLEXCRATE, FlexcrateScreen::new);
bind(LOGISTICAL_INDEX, LogisticalIndexScreen::new);
bind(LOGISTICAL_CONTROLLER, LogisticalInventoryControllerScreen::new);
bind(FILTER, FilterScreen::new);
bind(ATTRIBUTE_FILTER, AttributeFilterScreen::new);
}
@OnlyIn(Dist.CLIENT)

View file

@ -17,7 +17,7 @@ import com.simibubi.create.modules.curiosities.symmetry.SymmetryWandItem;
import com.simibubi.create.modules.curiosities.symmetry.client.SymmetryWandItemRenderer;
import com.simibubi.create.modules.gardens.TreeFertilizerItem;
import com.simibubi.create.modules.logistics.item.CardboardBoxItem;
import com.simibubi.create.modules.logistics.item.FilterItem;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import com.simibubi.create.modules.logistics.management.LogisticalDialItem;
import com.simibubi.create.modules.logistics.management.base.LogisticalControllerBlock.Type;
import com.simibubi.create.modules.logistics.management.base.LogisticalControllerItem;
@ -108,6 +108,8 @@ public enum AllItems {
CARDBOARD_BOX_1410(new CardboardBoxItem(standardItemProperties())),
FILTER(new FilterItem(standardItemProperties()), true),
PROPERTY_FILTER(new FilterItem(standardItemProperties()), true),
LOGISTICAL_FILTER(new FilterItem(standardItemProperties())),
LOGISTICAL_DIAL(new LogisticalDialItem(standardItemProperties())),
LOGISTICAL_CONTROLLER_SUPPLY(new LogisticalControllerItem(standardItemProperties(), Type.SUPPLY)),
LOGISTICAL_CONTROLLER_REQUEST(new LogisticalControllerItem(standardItemProperties(), Type.REQUEST)),

View file

@ -4,6 +4,7 @@ import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.simibubi.create.foundation.behaviour.filtering.FilteringCountUpdatePacket;
import com.simibubi.create.foundation.packet.NbtPacket;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ConfigureChassisPacket;
@ -12,6 +13,7 @@ import com.simibubi.create.modules.contraptions.components.motor.ConfigureMotorP
import com.simibubi.create.modules.curiosities.placementHandgun.BuilderGunBeamPacket;
import com.simibubi.create.modules.curiosities.symmetry.SymmetryEffectPacket;
import com.simibubi.create.modules.logistics.block.diodes.ConfigureFlexpeaterPacket;
import com.simibubi.create.modules.logistics.item.filter.FilterScreenPacket;
import com.simibubi.create.modules.logistics.management.controller.LogisticalControllerConfigurationPacket;
import com.simibubi.create.modules.logistics.management.index.IndexContainerUpdatePacket;
import com.simibubi.create.modules.logistics.management.index.IndexOrderRequest;
@ -43,6 +45,8 @@ public enum AllPackets {
PLACE_SCHEMATIC(SchematicPlacePacket.class, SchematicPlacePacket::new),
UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new),
INDEX_ORDER_REQUEST(IndexOrderRequest.class, IndexOrderRequest::new),
CONFIGURE_FILTER(FilterScreenPacket.class, FilterScreenPacket::new),
CONFIGURE_FILTERING_AMOUNT(FilteringCountUpdatePacket.class, FilteringCountUpdatePacket::new),
// Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new),

View file

@ -3,6 +3,7 @@ package com.simibubi.create;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.foundation.behaviour.filtering.FilteringHandler;
import com.simibubi.create.foundation.block.IHaveScrollableValue;
import com.simibubi.create.foundation.gui.ScreenOpener;
import com.simibubi.create.foundation.item.TooltipHelper;
@ -100,7 +101,8 @@ public class ClientEvents {
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta)
|| IHaveScrollableValue.onScroll(delta);
|| IHaveScrollableValue.onScroll(delta)
|| FilteringHandler.onScroll(delta);
event.setCanceled(cancelled);
}

View file

@ -33,6 +33,9 @@ public enum ScreenResources {
STOCKSWITCH_BOUND_LEFT("flex_crate_and_stockpile_switch.png", 234, 129, 7, 21),
STOCKSWITCH_BOUND_RIGHT("flex_crate_and_stockpile_switch.png", 241, 129, 7, 21),
FILTER("filter.png", 200, 100),
ATTRIBUTE_FILTER("filter.png", 0, 100, 200, 86),
// Logistical Index
INDEX_TOP("index.png", 41, 0, 174, 22),
INDEX_TOP_TRIM("index.png", 41, 22, 174, 6),
@ -130,6 +133,15 @@ public enum ScreenResources {
I_PRIORITY_VERY_HIGH(112, 0),
I_ACTIVE(64, 16),
I_PASSIVE(80, 16),
I_BLACKLIST(128, 0),
I_WHITELIST(144, 0),
I_WHITELIST_OR(160, 0),
I_WHITELIST_AND(176, 0),
I_WHITELIST_NOT(192, 0),
I_RESPECT_NBT(208, 0),
I_IGNORE_NBT(224, 0),
;

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.behaviour;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;
@ -28,10 +29,12 @@ public class ValueBox {
}
public static class ItemValueBox extends ValueBox {
ItemStack stack;
int count;
public ItemValueBox(String label, AxisAlignedBB bb, int count) {
public ItemValueBox(String label, AxisAlignedBB bb, ItemStack stack, int count) {
super(label, bb);
this.stack = stack;
this.count = count;
}

View file

@ -1,11 +1,11 @@
package com.simibubi.create.foundation.behaviour;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.behaviour.ValueBox.ItemValueBox;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.modules.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
@ -67,12 +67,20 @@ public class ValueBoxRenderer {
}
if (box instanceof ItemValueBox) {
String count = ((ItemValueBox) box).count + "";
GlStateManager.translated(-7 - font.getStringWidth(count), 10, 10 + 1 / 4f);
GlStateManager.scaled(1.5, 1.5, 1.5);
font.drawString(count, 0, 0, 0xEDEDED);
GlStateManager.translated(0, 0, -1 / 4f);
font.drawString(count, 1, 1, 0x4F4F4F);
ItemValueBox itemValueBox = (ItemValueBox) box;
String count = itemValueBox.count == 0 ? "*" : itemValueBox.count + "";
boolean isFilter = itemValueBox.stack.getItem() instanceof FilterItem;
if (isFilter)
GlStateManager.translated(3, 8, 7.25f);
else
GlStateManager.translated(-7 - font.getStringWidth(count), 10, 10 + 1 / 4f);
double scale = 1.5;
GlStateManager.scaled(scale, scale, scale);
font.drawString(count, 0, 0, isFilter ? 0xFFFFFF : 0xEDEDED);
GlStateManager.translated(0, 0, -1 / 16f);
font.drawString(count, 1 - 1 / 8f, 1 - 1 / 8f, 0x4F4F4F);
}
}
@ -89,7 +97,7 @@ public class ValueBoxRenderer {
private static float customZOffset(Item item) {
float NUDGE = -.1f;
if (AllItems.FILTER.get() == item)
if (item instanceof FilterItem)
return NUDGE;
if (item instanceof BlockItem) {
Block block = ((BlockItem) item).getBlock();

View file

@ -69,6 +69,12 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
behaviours.values().forEach(tb -> tb.writeNBT(compound));
return super.write(compound);
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
behaviours.values().forEach(tb -> tb.writeToClient(compound));
return super.writeToClient(compound);
}
@Override
public void read(CompoundNBT compound) {

View file

@ -98,4 +98,8 @@ public abstract class TileEntityBehaviour {
return ste.getBehaviour(type);
}
public CompoundNBT writeToClient(CompoundNBT compound) {
return compound;
}
}

View file

@ -3,9 +3,11 @@ package com.simibubi.create.foundation.behaviour.filtering;
import java.util.function.Consumer;
import java.util.function.Function;
import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.behaviour.base.IBehaviourType;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
@ -22,8 +24,13 @@ public class FilteringBehaviour extends TileEntityBehaviour {
Vec3d textShift;
private ItemStack filter;
public int count;
private Consumer<ItemStack> callback;
int scrollableValue;
int ticksUntilScrollPacket;
boolean forceClientState;
public FilteringBehaviour(SmartTileEntity te) {
super(te);
filter = ItemStack.EMPTY;
@ -32,20 +39,54 @@ public class FilteringBehaviour extends TileEntityBehaviour {
callback = stack -> {
};
textShift = Vec3d.ZERO;
count = -1;
ticksUntilScrollPacket = -1;
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.put("Filter", getFilter().serializeNBT());
nbt.putInt("FilterAmount", count);
super.writeNBT(nbt);
}
@Override
public void readNBT(CompoundNBT nbt) {
filter = ItemStack.read(nbt.getCompound("Filter"));
count = nbt.getInt("FilterAmount");
if (nbt.contains("ForceScrollable")) {
scrollableValue = count;
ticksUntilScrollPacket = -1;
}
super.readNBT(nbt);
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
if (forceClientState) {
compound.putBoolean("ForceScrollable", true);
forceClientState = false;
}
return super.writeToClient(compound);
}
@Override
public void tick() {
super.tick();
if (!getWorld().isRemote)
return;
if (ticksUntilScrollPacket == -1)
return;
if (ticksUntilScrollPacket > 0) {
ticksUntilScrollPacket--;
return;
}
AllPackets.channel.sendToServer(new FilteringCountUpdatePacket(getPos(), scrollableValue));
ticksUntilScrollPacket = -1;
}
public FilteringBehaviour withCallback(Consumer<ItemStack> filterCallback) {
callback = filterCallback;
return this;
@ -65,10 +106,23 @@ public class FilteringBehaviour extends TileEntityBehaviour {
textShift = shift;
return this;
}
@Override
public void initialize() {
super.initialize();
scrollableValue = count;
}
public void setFilter(ItemStack stack) {
filter = stack.copy();
callback.accept(filter);
if (filter.getItem() instanceof FilterItem)
count = 0;
else
count = stack.getCount();
forceClientState = true;
tileEntity.markDirty();
tileEntity.sendData();
}
@ -82,7 +136,7 @@ public class FilteringBehaviour extends TileEntityBehaviour {
}
public boolean test(ItemStack stack) {
return filter.isEmpty() || ItemStack.areItemsEqual(filter, stack);
return filter.isEmpty() || FilterItem.test(stack, filter);
}
@Override
@ -98,6 +152,14 @@ public class FilteringBehaviour extends TileEntityBehaviour {
Vec3d localHit = hit.subtract(new Vec3d(tileEntity.getPos()));
return localHit.distanceTo(offset) < slotPositioning.scale / 2;
}
public int getAmount() {
return count;
}
public boolean anyAmount() {
return count == 0;
}
public static class SlotPositioning {
Function<BlockState, Vec3d> offset;

View file

@ -0,0 +1,44 @@
package com.simibubi.create.foundation.behaviour.filtering;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.packet.TileEntityConfigurationPacket;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
public class FilteringCountUpdatePacket extends TileEntityConfigurationPacket<SmartTileEntity> {
int amount;
public FilteringCountUpdatePacket(PacketBuffer buffer) {
super(buffer);
}
public FilteringCountUpdatePacket(BlockPos pos, int amount) {
super(pos);
this.amount = amount;
}
@Override
protected void writeSettings(PacketBuffer buffer) {
buffer.writeInt(amount);
}
@Override
protected void readSettings(PacketBuffer buffer) {
amount = buffer.readInt();
}
@Override
protected void applySettings(SmartTileEntity te) {
FilteringBehaviour behaviour = TileEntityBehaviour.get(te, FilteringBehaviour.TYPE);
if (behaviour == null)
return;
behaviour.forceClientState = true;
behaviour.count = amount;
te.markDirty();
te.sendData();
}
}

View file

@ -1,16 +1,25 @@
package com.simibubi.create.foundation.behaviour.filtering;
import com.simibubi.create.AllKeys;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.RaycastHelper;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.LogicalSide;
@ -38,12 +47,54 @@ public class FilteringHandler {
return;
if (behaviour.testHit(ray.getHitVec())) {
if (event.getSide() != LogicalSide.CLIENT)
behaviour.setFilter(player.getHeldItem(hand));
if (event.getSide() != LogicalSide.CLIENT) {
ItemStack heldItem = player.getHeldItem(hand).copy();
if (!player.isCreative()) {
if (behaviour.getFilter().getItem() instanceof FilterItem)
player.inventory.placeItemBackInInventory(world, behaviour.getFilter());
if (heldItem.getItem() instanceof FilterItem)
player.getHeldItem(hand).shrink(1);
}
if (heldItem.getItem() instanceof FilterItem)
heldItem.setCount(1);
behaviour.setFilter(heldItem);
}
event.setCanceled(true);
event.setCancellationResult(ActionResultType.SUCCESS);
world.playSound(null, pos, SoundEvents.ENTITY_ITEM_FRAME_ADD_ITEM, SoundCategory.BLOCKS, .25f, .1f);
}
}
@OnlyIn(Dist.CLIENT)
public static boolean onScroll(double delta) {
RayTraceResult objectMouseOver = Minecraft.getInstance().objectMouseOver;
if (!(objectMouseOver instanceof BlockRayTraceResult))
return false;
BlockRayTraceResult result = (BlockRayTraceResult) objectMouseOver;
Minecraft mc = Minecraft.getInstance();
ClientWorld world = mc.world;
BlockPos blockPos = result.getPos();
FilteringBehaviour filtering = TileEntityBehaviour.get(world, blockPos, FilteringBehaviour.TYPE);
if (filtering == null)
return false;
if (mc.player.isSneaking())
return false;
if (!mc.player.isAllowEdit())
return false;
if (!filtering.isCountVisible())
return false;
if (!filtering.testHit(objectMouseOver.getHitVec()))
return false;
if (filtering.getFilter().isEmpty())
return false;
filtering.ticksUntilScrollPacket = 10;
filtering.scrollableValue = (int) MathHelper
.clamp(filtering.scrollableValue + delta * (AllKeys.ctrlDown() ? 16 : 1), 0, 64);
return true;
}
}

View file

@ -10,10 +10,12 @@ import com.simibubi.create.foundation.behaviour.filtering.FilteringBehaviour.Slo
import com.simibubi.create.foundation.utility.GlHelper;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.modules.logistics.item.filter.FilterItem;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
@ -41,6 +43,8 @@ public class FilteringRenderer {
FilteringBehaviour behaviour = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
if (behaviour == null)
return;
if (Minecraft.getInstance().player.isSneaking())
return;
TessellatorHelper.prepareForDrawing();
GlStateManager.translated(pos.getX(), pos.getY(), pos.getZ());
@ -50,7 +54,10 @@ public class FilteringRenderer {
AxisAlignedBB bb = new AxisAlignedBB(Vec3d.ZERO, Vec3d.ZERO).grow(.25f);
String label = Lang.translate("logistics.filter");
ValueBox box = behaviour.isCountVisible() ? new ItemValueBox(label, bb, behaviour.getFilter().getCount())
ItemStack filter = behaviour.getFilter();
if (filter.getItem() instanceof FilterItem)
label = "";
ValueBox box = behaviour.isCountVisible() ? new ItemValueBox(label, bb, filter, behaviour.scrollableValue)
: new ValueBox(label, bb);
box.offsetLabel(behaviour.textShift).withColors(0x7777BB, 0xCCBBFF);
ValueBoxRenderer.renderBox(box, behaviour.testHit(target.getHitVec()));

View file

@ -39,19 +39,17 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
this.customAmountFilter = filter;
return this;
}
public ExtractingBehaviour withAdditionalFilter(Predicate<ItemStack> filter) {
this.customFilter = filter;
return this;
}
public boolean extract() {
int amount = -1;
FilteringBehaviour filter = get(tileEntity, FilteringBehaviour.TYPE);
if (filter != null) {
ItemStack filterItem = filter.getFilter();
amount = filterItem.isEmpty() ? -1 : filterItem.getCount();
}
if (filter != null && !filter.anyAmount())
amount = filter.getAmount();
return extract(amount);
}
@ -70,7 +68,7 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour {
extract = ItemHelper.extract(inv, test, exactAmount, false);
else
extract = ItemHelper.extract(inv, test, customAmountFilter, false);
if (!extract.isEmpty()) {
callback.accept(extract);
return true;

View file

@ -29,7 +29,7 @@ public abstract class AbstractSimiContainerScreen<T extends Container> extends C
protected List<Widget> widgets;
protected AbstractSimiContainerScreen(T container, PlayerInventory inv, ITextComponent title) {
public AbstractSimiContainerScreen(T container, PlayerInventory inv, ITextComponent title) {
super(container, inv, title);
widgets = new ArrayList<>();
}
@ -126,7 +126,7 @@ public abstract class AbstractSimiContainerScreen<T extends Container> extends C
}
protected void renderWindowForeground(int mouseX, int mouseY, float partialTicks) {
super.renderHoveredToolTip(mouseX, mouseY);
renderHoveredToolTip(mouseX, mouseY);
for (Widget widget : widgets) {
if (!widget.isHovered())
continue;

View file

@ -12,7 +12,7 @@ public class Label extends AbstractSimiWidget {
protected boolean hasShadow;
protected int color;
protected FontRenderer font;
public Label(int x, int y, String text) {
super(x, y, Minecraft.getInstance().fontRenderer.getStringWidth(text), 10);
font = Minecraft.getInstance().fontRenderer;
@ -21,34 +21,60 @@ public class Label extends AbstractSimiWidget {
hasShadow = false;
suffix = "";
}
public Label colored(int color) {
this.color = color;
return this;
}
public Label withShadow() {
this.hasShadow = true;
return this;
}
public Label withSuffix(String s) {
suffix = s;
return this;
}
public void setTextAndTrim(String newText, boolean trimFront, int maxWidthPx) {
FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer;
if (fontRenderer.getStringWidth(newText) <= maxWidthPx) {
text = newText;
return;
}
String trim = "...";
int trimWidth = fontRenderer.getStringWidth(trim);
StringBuilder builder = new StringBuilder(newText);
int startIndex = trimFront ? 0 : newText.length() - 1;
int endIndex = !trimFront ? 0 : newText.length() - 1;
int step = (int) Math.signum(endIndex - startIndex);
for (int i = startIndex; i != endIndex; i += step) {
String sub = builder.substring(trimFront ? i : startIndex, trimFront ? endIndex + 1 : i + 1);
if (fontRenderer.getStringWidth(sub) + trimWidth <= maxWidthPx) {
text = trimFront ? trim + sub : sub + trim;
return;
}
}
}
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
if (!visible)
return;
if (text == null || text.isEmpty())
return;
GlStateManager.color4f(1, 1, 1, 1);
if (hasShadow)
font.drawStringWithShadow(text + suffix, x, y, color);
else
font.drawString(text + suffix, x, y, color);
}
}

View file

@ -69,7 +69,7 @@ public class ItemDescription {
linesOnShift = new ArrayList<>();
linesOnCtrl = new ArrayList<>();
}
public ItemDescription withSummary(String summary) {
add(linesOnShift, cutString(summary, palette.color, palette.hColor));
add(linesOnShift, "");
@ -86,11 +86,12 @@ public class ItemDescription {
if (hasSpeedRequirement) {
List<String> speedLevels = Lang.translatedOptions("tooltip.speedRequirement", "none", "medium", "high");
int index = minimumRequiredSpeedLevel.ordinal();
String level = minimumRequiredSpeedLevel.getTextColor() + makeProgressBar(3, index) + speedLevels.get(index);
String level = minimumRequiredSpeedLevel.getTextColor() + makeProgressBar(3, index)
+ speedLevels.get(index);
add(linesOnShift, GRAY + Lang.translate("tooltip.speedRequirement"));
add(linesOnShift, level);
}
if (hasStressImpact) {
if (hasStressImpact && !block.hideStressImpact()) {
List<String> stressLevels = Lang.translatedOptions("tooltip.stressImpact", "low", "medium", "high");
double impact = parameters.stressEntries.get(id).get();
StressImpact impactId = impact >= parameters.highStressImpact.get() ? StressImpact.HIGH
@ -109,6 +110,10 @@ public class ItemDescription {
: (capacity >= parameters.mediumCapacity.get() ? StressImpact.MEDIUM : StressImpact.HIGH);
int index = StressImpact.values().length - 1 - impactId.ordinal();
String level = impactId.getColor() + makeProgressBar(3, index) + stressCapacityLevels.get(index);
if (block.showCapacityWithAnnotation())
level += " " + DARK_GRAY + TextFormatting.ITALIC
+ Lang.translate("tooltip.capacityProvided.asGenerator");
add(linesOnShift, GRAY + Lang.translate("tooltip.capacityProvided"));
add(linesOnShift, level);
}

View file

@ -57,5 +57,13 @@ public interface IRotate extends IWrenchable {
public default SpeedLevel getMinimumRequiredSpeedLevel() {
return SpeedLevel.NONE;
}
public default boolean hideStressImpact() {
return false;
}
public default boolean showCapacityWithAnnotation() {
return false;
}
}

View file

@ -43,10 +43,15 @@ public class MechanicalBearingBlock extends DirectionalKineticBlock
protected boolean hasStaticPart() {
return true;
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(FACING).getAxis();
}
@Override
public boolean showCapacityWithAnnotation() {
return true;
}
}

View file

@ -77,5 +77,10 @@ public class EncasedFanBlock extends DirectionalKineticBlock implements IWithTil
public boolean hasShaftTowards(World world, BlockPos pos, BlockState state, Direction face) {
return face == state.get(FACING).getOpposite();
}
@Override
public boolean showCapacityWithAnnotation() {
return true;
}
}

View file

@ -20,7 +20,8 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
public class MotorBlock extends HorizontalKineticBlock implements IWithTileEntity<MotorTileEntity>, IHaveScrollableValue {
public class MotorBlock extends HorizontalKineticBlock
implements IWithTileEntity<MotorTileEntity>, IHaveScrollableValue {
private static final Vec3d valuePos = new Vec3d(15 / 16f, 5 / 16f, 5 / 16f);
@ -91,4 +92,9 @@ public class MotorBlock extends HorizontalKineticBlock implements IWithTileEntit
public Direction getValueBoxDirection(BlockState state, IWorld world, BlockPos pos) {
return state.get(HORIZONTAL_FACING).getOpposite();
}
@Override
public boolean hideStressImpact() {
return true;
}
}

View file

@ -144,4 +144,9 @@ public class WaterWheelBlock extends HorizontalKineticBlock {
return 1f;
}
@Override
public boolean hideStressImpact() {
return true;
}
}

View file

@ -56,7 +56,7 @@ public abstract class BeltAttachableLogisticalBlock extends AttachedLogisticalBl
if (extracting == null)
return false;
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getFilter().getCount()))
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getAmount()))
return false;
return true;
@ -76,10 +76,10 @@ public abstract class BeltAttachableLogisticalBlock extends AttachedLogisticalBl
return false;
FilteringBehaviour filtering = TileEntityBehaviour.get(world, pos, FilteringBehaviour.TYPE);
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getFilter().getCount()))
if (filtering != null && (!filtering.test(stack) || stack.getCount() < filtering.getAmount()))
return false;
if (!extracting.getShouldExtract().get())
return !filtering.getFilter().isEmpty();
return !filtering.anyAmount();
return !extracting.extractFromInventory();
}

View file

@ -57,7 +57,7 @@ public class TransposerTileEntity extends ExtractorTileEntity {
return te.tryInsertingFromSide(facing, stack, true);
}
if (filtering.getFilter().isEmpty())
if (filtering.anyAmount())
return true;
return inserting.insert(stack, true).isEmpty();
}

View file

@ -1,11 +0,0 @@
package com.simibubi.create.modules.logistics.item;
import net.minecraft.item.Item;
public class FilterItem extends Item {
public FilterItem(Properties properties) {
super(properties);
}
}

View file

@ -0,0 +1,142 @@
package com.simibubi.create.modules.logistics.item.filter;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
public abstract class AbstractFilterContainer extends Container {
public PlayerEntity player;
protected PlayerInventory playerInventory;
public ItemStack filterItem;
public ItemStackHandler filterInventory;
protected AbstractFilterContainer(ContainerType<?> type, int id, PlayerInventory inv, PacketBuffer extraData) {
this(type, id, inv, extraData.readItemStack());
}
protected AbstractFilterContainer(ContainerType<?> type, int id, PlayerInventory inv, ItemStack filterItem) {
super(type, id);
player = inv.player;
playerInventory = inv;
this.filterItem = filterItem;
init();
}
protected void init() {
this.filterInventory = createFilterInventory();
readData(filterItem);
addPlayerSlots();
addFilterSlots();
detectAndSendChanges();
}
protected void clearContents() {
for (int i = 0; i < filterInventory.getSlots(); i++)
filterInventory.setStackInSlot(i, ItemStack.EMPTY);
}
protected abstract int getInventoryOffset();
protected abstract void addFilterSlots();
protected abstract ItemStackHandler createFilterInventory();
protected abstract void readData(ItemStack filterItem);
protected abstract void saveData(ItemStack filterItem);
protected void addPlayerSlots() {
int x = 58;
int y = 28 + getInventoryOffset();
for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot)
this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58));
for (int row = 0; row < 3; ++row)
for (int col = 0; col < 9; ++col)
this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18));
}
@Override
public boolean canMergeSlot(ItemStack stack, Slot slotIn) {
return canDragIntoSlot(slotIn);
}
@Override
public boolean canDragIntoSlot(Slot slotIn) {
return slotIn.inventory == playerInventory;
}
@Override
public boolean canInteractWith(PlayerEntity playerIn) {
return true;
}
@Override
public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) {
if (slotId == playerInventory.currentItem && clickTypeIn != ClickType.THROW)
return ItemStack.EMPTY;
ItemStack held = playerInventory.getItemStack();
if (slotId < 36)
return super.slotClick(slotId, dragType, clickTypeIn, player);
if (clickTypeIn == ClickType.THROW)
return ItemStack.EMPTY;
int slot = slotId - 36;
if (clickTypeIn == ClickType.CLONE) {
if (player.isCreative() && held.isEmpty()) {
ItemStack stackInSlot = filterInventory.getStackInSlot(slot).copy();
stackInSlot.setCount(64);
playerInventory.setItemStack(stackInSlot);
return ItemStack.EMPTY;
}
return ItemStack.EMPTY;
}
if (held.isEmpty()) {
filterInventory.setStackInSlot(slot, ItemStack.EMPTY);
return ItemStack.EMPTY;
}
ItemStack insert = held.copy();
insert.setCount(1);
filterInventory.setStackInSlot(slot, insert);
return held;
}
@Override
public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
if (index < 36) {
ItemStack stackToInsert = playerInventory.getStackInSlot(index);
for (int i = 0; i < filterInventory.getSlots(); i++) {
ItemStack stack = filterInventory.getStackInSlot(i);
if (ItemHandlerHelper.canItemStacksStack(stack, stackToInsert))
break;
if (stack.isEmpty()) {
ItemStack copy = stackToInsert.copy();
copy.setCount(1);
filterInventory.insertItem(i, copy, false);
break;
}
}
} else
filterInventory.extractItem(index - 36, 1, false);
return ItemStack.EMPTY;
}
@Override
public void onContainerClosed(PlayerEntity playerIn) {
super.onContainerClosed(playerIn);
filterItem.getOrCreateTag().put("Items", filterInventory.serializeNBT());
saveData(filterItem);
}
}

View file

@ -0,0 +1,154 @@
package com.simibubi.create.modules.logistics.item.filter;
import static com.simibubi.create.ScreenResources.PLAYER_INVENTORY;
import static net.minecraft.util.text.TextFormatting.GRAY;
import java.util.Collections;
import java.util.List;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllPackets;
import com.simibubi.create.ScreenResources;
import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen;
import com.simibubi.create.foundation.gui.widgets.IconButton;
import com.simibubi.create.foundation.gui.widgets.Indicator;
import com.simibubi.create.foundation.gui.widgets.Indicator.State;
import com.simibubi.create.foundation.item.ItemDescription.Palette;
import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.modules.logistics.item.filter.FilterScreenPacket.Option;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.text.ITextComponent;
public abstract class AbstractFilterScreen<F extends AbstractFilterContainer> extends AbstractSimiContainerScreen<F> {
protected ScreenResources background;
private IconButton resetButton;
private IconButton confirmButton;
protected AbstractFilterScreen(F container, PlayerInventory inv, ITextComponent title, ScreenResources background) {
super(container, inv, title);
this.background = background;
}
@Override
protected void init() {
setWindowSize(background.width + 80, background.height + PLAYER_INVENTORY.height + 20);
super.init();
widgets.clear();
resetButton = new IconButton(guiLeft + 15, guiTop + background.height - 30, ScreenResources.I_TRASH);
confirmButton = new IconButton(guiLeft + 159, guiTop + background.height - 30, ScreenResources.I_CONFIRM);
widgets.add(resetButton);
widgets.add(confirmButton);
}
@Override
protected void renderWindow(int mouseX, int mouseY, float partialTicks) {
int x = guiLeft;
int y = guiTop;
background.draw(this, x, y);
int invX = x + 50;
int invY = y + background.height + 10;
PLAYER_INVENTORY.draw(this, invX, invY);
font.drawString(playerInventory.getDisplayName().getFormattedText(), invX + 7, invY + 6, 0x666666);
font.drawString(I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 9, 0x5B5037);
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.pushMatrix();
GlStateManager.translated(guiLeft + background.width + 0, guiTop + background.height - 60, 0);
GlStateManager.scaled(5, 5, 5);
itemRenderer.renderItemIntoGUI(container.filterItem, 0, 0);
GlStateManager.popMatrix();
}
@Override
public void tick() {
handleTooltips();
super.tick();
handleIndicators();
if (!container.player.getHeldItemMainhand().equals(container.filterItem, false))
minecraft.player.closeScreen();
}
public void handleIndicators() {
List<IconButton> tooltipButtons = getTooltipButtons();
for (IconButton button : tooltipButtons)
button.active = isButtonEnabled(button);
for (Widget w : widgets)
if (w instanceof Indicator)
((Indicator) w).state = isIndicatorOn((Indicator) w) ? State.ON : State.OFF;
}
protected abstract boolean isButtonEnabled(IconButton button);
protected abstract boolean isIndicatorOn(Indicator indicator);
protected void handleTooltips() {
List<IconButton> tooltipButtons = getTooltipButtons();
for (IconButton button : tooltipButtons) {
if (!button.getToolTip().isEmpty()) {
button.setToolTip(button.getToolTip().get(0));
button.getToolTip().add(TooltipHelper.holdShift(Palette.Yellow, hasShiftDown()));
}
}
if (hasShiftDown()) {
List<String> tooltipDescriptions = getTooltipDescriptions();
for (int i = 0; i < tooltipButtons.size(); i++)
fillToolTip(tooltipButtons.get(i), tooltipDescriptions.get(i));
}
}
protected List<IconButton> getTooltipButtons() {
return Collections.emptyList();
}
protected List<String> getTooltipDescriptions() {
return Collections.emptyList();
}
private void fillToolTip(IconButton button, String tooltip) {
if (!button.isHovered())
return;
List<String> tip = button.getToolTip();
tip.addAll(TooltipHelper.cutString(tooltip, GRAY, GRAY));
}
@Override
public boolean mouseClicked(double x, double y, int button) {
boolean mouseClicked = super.mouseClicked(x, y, button);
if (button == 0) {
if (confirmButton.isHovered()) {
minecraft.player.closeScreen();
return true;
}
if (resetButton.isHovered()) {
container.clearContents();
contentsCleared();
sendOptionUpdate(Option.CLEAR);
return true;
}
}
return mouseClicked;
}
protected void contentsCleared() {
}
protected void sendOptionUpdate(Option option) {
AllPackets.channel.sendToServer(new FilterScreenPacket(option));
}
}

View file

@ -0,0 +1,138 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.AllContainers;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
public class AttributeFilterContainer extends AbstractFilterContainer {
public enum WhitelistMode {
WHITELIST_DISJ, WHITELIST_CONJ, BLACKLIST;
}
WhitelistMode whitelistMode;
List<ItemAttribute> selectedAttributes;
public AttributeFilterContainer(int id, PlayerInventory inv, PacketBuffer extraData) {
super(AllContainers.ATTRIBUTE_FILTER.type, id, inv, extraData);
}
public AttributeFilterContainer(int id, PlayerInventory inv, ItemStack stack) {
super(AllContainers.ATTRIBUTE_FILTER.type, id, inv, stack);
}
public void appendSelectedAttribute(ItemAttribute itemAttribute) {
selectedAttributes.add(itemAttribute);
}
@Override
protected void clearContents() {
selectedAttributes.clear();
}
@Override
protected void init() {
super.init();
ItemStack stack = new ItemStack(Items.NAME_TAG);
stack.setDisplayName(
new StringTextComponent("Selected Tags").applyTextStyles(TextFormatting.RESET, TextFormatting.BLUE));
filterInventory.setStackInSlot(1, stack);
}
@Override
protected ItemStackHandler createFilterInventory() {
return new ItemStackHandler(2);
}
protected void addFilterSlots() {
this.addSlot(new SlotItemHandler(filterInventory, 0, 16, 23));
this.addSlot(new SlotItemHandler(filterInventory, 1, 59, 56) {
@Override
public boolean canTakeStack(PlayerEntity playerIn) {
return false;
}
});
}
@Override
public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) {
if (slotId == 37)
return ItemStack.EMPTY;
return super.slotClick(slotId, dragType, clickTypeIn, player);
}
@Override
public boolean canDragIntoSlot(Slot slotIn) {
if (slotIn.slotNumber == 37)
return false;
return super.canDragIntoSlot(slotIn);
}
@Override
public boolean canMergeSlot(ItemStack stack, Slot slotIn) {
if (slotIn.slotNumber == 37)
return false;
return super.canMergeSlot(stack, slotIn);
}
@Override
public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
if (index == 37)
return ItemStack.EMPTY;
if (index == 36) {
filterInventory.setStackInSlot(37, ItemStack.EMPTY);
return ItemStack.EMPTY;
}
if (index < 36) {
ItemStack stackToInsert = playerInventory.getStackInSlot(index);
ItemStack copy = stackToInsert.copy();
copy.setCount(1);
filterInventory.setStackInSlot(0, copy);
}
return ItemStack.EMPTY;
}
@Override
protected int getInventoryOffset() {
return 86;
}
@Override
protected void readData(ItemStack filterItem) {
selectedAttributes = new ArrayList<>();
whitelistMode = WhitelistMode.values()[filterItem.getOrCreateTag().getInt("WhitelistMode")];
ListNBT attributes = filterItem.getOrCreateTag().getList("MatchedAttributes", NBT.TAG_COMPOUND);
attributes.forEach(inbt -> selectedAttributes.add(ItemAttribute.fromNBT((CompoundNBT) inbt)));
}
@Override
protected void saveData(ItemStack filterItem) {
filterItem.getOrCreateTag().putInt("WhitelistMode", whitelistMode.ordinal());
ListNBT attributes = new ListNBT();
selectedAttributes.forEach(at -> {
if (at == null)
return;
CompoundNBT compoundNBT = new CompoundNBT();
at.serializeNBT(compoundNBT);
attributes.add(compoundNBT);
});
filterItem.getOrCreateTag().put("MatchedAttributes", attributes);
}
}

View file

@ -0,0 +1,257 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllPackets;
import com.simibubi.create.ScreenResources;
import com.simibubi.create.foundation.gui.widgets.IconButton;
import com.simibubi.create.foundation.gui.widgets.Indicator;
import com.simibubi.create.foundation.gui.widgets.Label;
import com.simibubi.create.foundation.gui.widgets.SelectionScrollInput;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.logistics.item.filter.AttributeFilterContainer.WhitelistMode;
import com.simibubi.create.modules.logistics.item.filter.FilterScreenPacket.Option;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting;
public class AttributeFilterScreen extends AbstractFilterScreen<AttributeFilterContainer> {
private static final String PREFIX = "gui.attribute_filter.";
private IconButton whitelistDis, whitelistCon, blacklist;
private Indicator whitelistDisIndicator, whitelistConIndicator, blacklistIndicator;
private IconButton add;
private String whitelistDisN = Lang.translate(PREFIX + "whitelist_disjunctive");
private String whitelistDisDESC = Lang.translate(PREFIX + "whitelist_disjunctive.description");
private String whitelistConN = Lang.translate(PREFIX + "whitelist_conjunctive");
private String whitelistConDESC = Lang.translate(PREFIX + "whitelist_conjunctive.description");
private String blacklistN = Lang.translate(PREFIX + "blacklist");
private String blacklistDESC = Lang.translate(PREFIX + "blacklist.description");
private String referenceH = Lang.translate(PREFIX + "add_reference_item");
private String noSelectedT = Lang.translate(PREFIX + "no_selected_attributes");
private String selectedT = Lang.translate(PREFIX + "selected_attributes");
private ItemStack lastItemScanned = ItemStack.EMPTY;
private List<ItemAttribute> attributesOfItem = new ArrayList<>();
private List<String> selectedAttributes = new ArrayList<>();
private SelectionScrollInput attributeSelector;
private Label attributeSelectorLabel;
public AttributeFilterScreen(AttributeFilterContainer container, PlayerInventory inv, ITextComponent title) {
super(container, inv, title, ScreenResources.ATTRIBUTE_FILTER);
}
@Override
protected void init() {
super.init();
int x = guiLeft;
int y = guiTop;
whitelistDis = new IconButton(x + 84, y + 58, ScreenResources.I_WHITELIST_OR);
whitelistDis.setToolTip(whitelistDisN);
whitelistCon = new IconButton(x + 102, y + 58, ScreenResources.I_WHITELIST_AND);
whitelistCon.setToolTip(whitelistConN);
blacklist = new IconButton(x + 120, y + 58, ScreenResources.I_WHITELIST_NOT);
blacklist.setToolTip(blacklistN);
whitelistDisIndicator = new Indicator(x + 84, y + 53, "");
whitelistConIndicator = new Indicator(x + 102, y + 53, "");
blacklistIndicator = new Indicator(x + 120, y + 53, "");
widgets.addAll(Arrays.asList(blacklist, whitelistCon, whitelistDis, blacklistIndicator, whitelistConIndicator,
whitelistDisIndicator));
add = new IconButton(x + 159, y + 22, ScreenResources.I_ADD);
widgets.add(add);
handleIndicators();
attributeSelectorLabel = new Label(x + 40, y + 27, "").colored(0xF3EBDE).withShadow();
attributeSelector = new SelectionScrollInput(x + 37, y + 24, 118, 14);
attributeSelector.forOptions(Arrays.asList(""));
attributeSelector.calling(s -> {
});
referenceItemChanged(container.filterInventory.getStackInSlot(0));
widgets.add(attributeSelector);
widgets.add(attributeSelectorLabel);
selectedAttributes.clear();
selectedAttributes
.add(TextFormatting.YELLOW + (container.selectedAttributes.isEmpty() ? noSelectedT : selectedT));
container.selectedAttributes.forEach(at -> selectedAttributes.add(TextFormatting.GRAY + "- " + at.format()));
}
private void referenceItemChanged(ItemStack stack) {
lastItemScanned = stack;
if (stack.isEmpty()) {
attributeSelector.active = false;
attributeSelector.visible = false;
attributeSelectorLabel.text = TextFormatting.ITALIC + referenceH;
add.active = false;
attributeSelector.calling(s -> {
});
return;
}
add.active = true;
attributeSelector.titled(stack.getDisplayName().getFormattedText() + "...");
attributesOfItem.clear();
for (ItemAttribute itemAttribute : ItemAttribute.types)
attributesOfItem.addAll(itemAttribute.listAttributesOf(stack));
List<String> options = attributesOfItem.stream().map(ItemAttribute::format).collect(Collectors.toList());
attributeSelector.forOptions(options);
attributeSelector.active = true;
attributeSelector.visible = true;
attributeSelector.setState(0);
attributeSelector.calling(i -> {
attributeSelectorLabel.setTextAndTrim(options.get(i), true, 112);
ItemAttribute selected = attributesOfItem.get(i);
for (ItemAttribute existing : container.selectedAttributes) {
CompoundNBT testTag = new CompoundNBT();
CompoundNBT testTag2 = new CompoundNBT();
existing.serializeNBT(testTag);
selected.serializeNBT(testTag2);
if (testTag.equals(testTag2)) {
add.active = false;
return;
}
}
add.active = true;
});
attributeSelector.onChanged();
}
@Override
public void renderWindowForeground(int mouseX, int mouseY, float partialTicks) {
ItemStack stack = container.filterInventory.getStackInSlot(1);
GlStateManager.pushMatrix();
GlStateManager.translatef(0.0F, 0.0F, 32.0F);
this.blitOffset = 200;
this.itemRenderer.zLevel = 200.0F;
this.itemRenderer.renderItemOverlayIntoGUI(font, stack, guiLeft + 59, guiTop + 56,
String.valueOf(selectedAttributes.size() - 1));
this.blitOffset = 0;
this.itemRenderer.zLevel = 0.0F;
GlStateManager.popMatrix();
super.renderWindowForeground(mouseX, mouseY, partialTicks);
}
@Override
public void tick() {
super.tick();
ItemStack stackInSlot = container.filterInventory.getStackInSlot(0);
if (!stackInSlot.equals(lastItemScanned, false))
referenceItemChanged(stackInSlot);
}
@Override
protected void renderHoveredToolTip(int mouseX, int mouseY) {
if (this.minecraft.player.inventory.getItemStack().isEmpty() && this.hoveredSlot != null
&& this.hoveredSlot.getHasStack()) {
if (this.hoveredSlot.slotNumber == 37) {
renderTooltip(selectedAttributes, mouseX, mouseY, font);
return;
}
this.renderTooltip(this.hoveredSlot.getStack(), mouseX, mouseY);
}
super.renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected List<IconButton> getTooltipButtons() {
return Arrays.asList(blacklist, whitelistCon, whitelistDis);
}
@Override
protected List<String> getTooltipDescriptions() {
return Arrays.asList(blacklistDESC, whitelistConDESC, whitelistDisDESC);
}
@Override
public boolean mouseClicked(double x, double y, int button) {
boolean mouseClicked = super.mouseClicked(x, y, button);
if (button != 0)
return mouseClicked;
if (blacklist.isHovered()) {
container.whitelistMode = WhitelistMode.BLACKLIST;
sendOptionUpdate(Option.BLACKLIST);
return true;
}
if (whitelistCon.isHovered()) {
container.whitelistMode = WhitelistMode.WHITELIST_CONJ;
sendOptionUpdate(Option.WHITELIST2);
return true;
}
if (whitelistDis.isHovered()) {
container.whitelistMode = WhitelistMode.WHITELIST_DISJ;
sendOptionUpdate(Option.WHITELIST);
return true;
}
if (add.isHovered() && add.active) {
int index = attributeSelector.getState();
if (index < attributesOfItem.size()) {
add.active = false;
CompoundNBT tag = new CompoundNBT();
ItemAttribute itemAttribute = attributesOfItem.get(index);
itemAttribute.serializeNBT(tag);
AllPackets.channel.sendToServer(new FilterScreenPacket(Option.ADD_TAG, tag));
container.selectedAttributes.add(itemAttribute);
if (container.selectedAttributes.size() == 1)
selectedAttributes.set(0, TextFormatting.YELLOW + selectedT);
selectedAttributes.add(TextFormatting.GRAY + "- " + itemAttribute.format());
return true;
}
}
return mouseClicked;
}
@Override
protected void contentsCleared() {
selectedAttributes.clear();
selectedAttributes.add(TextFormatting.YELLOW + noSelectedT);
if (!lastItemScanned.isEmpty())
add.active = true;
}
@Override
protected boolean isButtonEnabled(IconButton button) {
if (button == blacklist)
return container.whitelistMode != WhitelistMode.BLACKLIST;
if (button == whitelistCon)
return container.whitelistMode != WhitelistMode.WHITELIST_CONJ;
if (button == whitelistDis)
return container.whitelistMode != WhitelistMode.WHITELIST_DISJ;
return true;
}
@Override
protected boolean isIndicatorOn(Indicator indicator) {
if (indicator == blacklistIndicator)
return container.whitelistMode == WhitelistMode.BLACKLIST;
if (indicator == whitelistConIndicator)
return container.whitelistMode == WhitelistMode.WHITELIST_CONJ;
if (indicator == whitelistDisIndicator)
return container.whitelistMode == WhitelistMode.WHITELIST_DISJ;
return false;
}
}

View file

@ -0,0 +1,59 @@
package com.simibubi.create.modules.logistics.item.filter;
import com.simibubi.create.AllContainers;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
public class FilterContainer extends AbstractFilterContainer {
boolean respectNBT;
boolean blacklist;
public FilterContainer(int id, PlayerInventory inv, PacketBuffer extraData) {
super(AllContainers.FILTER.type, id, inv, extraData);
}
public FilterContainer(int id, PlayerInventory inv, ItemStack stack) {
super(AllContainers.FILTER.type, id, inv, stack);
}
@Override
protected void addFilterSlots() {
int x = 16;
int y = 21;
for (int row = 0; row < 2; ++row)
for (int col = 0; col < 9; ++col)
this.addSlot(new SlotItemHandler(filterInventory, col + row * 9, x + col * 18, y + row * 18));
}
@Override
protected ItemStackHandler createFilterInventory() {
return FilterItem.getFilterItems(filterItem);
}
@Override
protected int getInventoryOffset() {
return 100;
}
@Override
protected void readData(ItemStack filterItem) {
CompoundNBT tag = filterItem.getOrCreateTag();
respectNBT = tag.getBoolean("RespectNBT");
blacklist = tag.getBoolean("Blacklist");
}
@Override
protected void saveData(ItemStack filterItem) {
CompoundNBT tag = filterItem.getOrCreateTag();
tag.putBoolean("RespectNBT", respectNBT);
tag.putBoolean("Blacklist", blacklist);
}
}

View file

@ -0,0 +1,222 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllKeys;
import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.logistics.item.filter.AttributeFilterContainer.WhitelistMode;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
public class FilterItem extends Item implements INamedContainerProvider {
public FilterItem(Properties properties) {
super(properties);
}
@Override
public ActionResultType onItemUse(ItemUseContext context) {
return onItemRightClick(context.getWorld(), context.getPlayer(), context.getHand()).getType();
}
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, World worldIn, List<ITextComponent> tooltip, ITooltipFlag flagIn) {
if (!AllKeys.shiftDown()) {
List<String> makeSummary = makeSummary(stack);
if (makeSummary.isEmpty())
return;
ItemDescription.add(tooltip, " ");
ItemDescription.add(tooltip, makeSummary);
}
}
private List<String> makeSummary(ItemStack filter) {
List<String> list = new ArrayList<>();
if (AllItems.FILTER.typeOf(filter)) {
ItemStackHandler filterItems = getFilterItems(filter);
boolean blacklist = filter.getOrCreateTag().getBoolean("Blacklist");
list.add(TextFormatting.GOLD
+ (blacklist ? Lang.translate("gui.filter.blacklist") : Lang.translate("gui.filter.whitelist")));
int count = 0;
for (int i = 0; i < filterItems.getSlots(); i++) {
if (count > 3) {
list.add(TextFormatting.DARK_GRAY + "- ...");
break;
}
ItemStack filterStack = filterItems.getStackInSlot(i);
if (filterStack.isEmpty())
continue;
list.add(TextFormatting.GRAY + "- " + filterStack.getDisplayName().getFormattedText());
count++;
}
if (count == 0)
return Collections.emptyList();
}
if (AllItems.PROPERTY_FILTER.typeOf(filter)) {
WhitelistMode whitelistMode = WhitelistMode.values()[filter.getOrCreateTag().getInt("WhitelistMode")];
list.add(TextFormatting.GOLD + (whitelistMode == WhitelistMode.WHITELIST_CONJ
? Lang.translate("gui.attribute_filter.whitelist_conjunctive")
: whitelistMode == WhitelistMode.WHITELIST_DISJ
? Lang.translate("gui.attribute_filter.whitelist_disjunctive")
: Lang.translate("gui.attribute_filter.blacklist")));
int count = 0;
ListNBT attributes = filter.getOrCreateTag().getList("MatchedAttributes", NBT.TAG_COMPOUND);
for (INBT inbt : attributes) {
ItemAttribute attribute = ItemAttribute.fromNBT((CompoundNBT) inbt);
if (count > 3) {
list.add(TextFormatting.DARK_GRAY + "- ...");
break;
}
list.add(TextFormatting.GRAY + "- " + attribute.format());
count++;
}
if (count == 0)
return Collections.emptyList();
}
return list;
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, PlayerEntity player, Hand hand) {
ItemStack heldItem = player.getHeldItem(hand);
if (!player.isSneaking() && hand == Hand.MAIN_HAND) {
if (AllItems.LOGISTICAL_FILTER.typeOf(heldItem))
return ActionResult.newResult(ActionResultType.FAIL, heldItem);
if (!world.isRemote && player instanceof ServerPlayerEntity)
NetworkHooks.openGui((ServerPlayerEntity) player, this, buf -> {
buf.writeItemStack(heldItem);
});
return ActionResult.newResult(ActionResultType.SUCCESS, heldItem);
}
return ActionResult.newResult(ActionResultType.PASS, heldItem);
}
@Override
public Container createMenu(int id, PlayerInventory inv, PlayerEntity player) {
ItemStack heldItem = player.getHeldItemMainhand();
if (AllItems.FILTER.typeOf(heldItem))
return new FilterContainer(id, inv, heldItem);
if (AllItems.PROPERTY_FILTER.typeOf(heldItem))
return new AttributeFilterContainer(id, inv, heldItem);
return null;
}
@Override
public ITextComponent getDisplayName() {
return new StringTextComponent(getTranslationKey());
}
public static ItemStackHandler getFilterItems(ItemStack stack) {
ItemStackHandler newInv = new ItemStackHandler(18);
if (!AllItems.FILTER.typeOf(stack))
throw new IllegalArgumentException("Cannot get filter items from non-filter: " + stack);
CompoundNBT invNBT = stack.getOrCreateChildTag("Items");
if (!invNBT.isEmpty())
newInv.deserializeNBT(invNBT);
return newInv;
}
public static boolean test(ItemStack stack, ItemStack filter) {
return test(stack, filter, false);
}
private static boolean test(ItemStack stack, ItemStack filter, boolean matchNBT) {
if (!(filter.getItem() instanceof FilterItem))
return (matchNBT ? ItemHandlerHelper.canItemStacksStack(filter, stack)
: ItemStack.areItemsEqual(filter, stack));
if (AllItems.FILTER.typeOf(filter)) {
ItemStackHandler filterItems = getFilterItems(filter);
boolean respectNBT = filter.getOrCreateTag().getBoolean("RespectNBT");
boolean blacklist = filter.getOrCreateTag().getBoolean("Blacklist");
for (int slot = 0; slot < filterItems.getSlots(); slot++) {
ItemStack stackInSlot = filterItems.getStackInSlot(slot);
if (stackInSlot.isEmpty())
continue;
boolean matches = test(stack, stackInSlot, respectNBT);
if (matches)
return !blacklist;
}
return blacklist;
}
if (AllItems.PROPERTY_FILTER.typeOf(filter)) {
WhitelistMode whitelistMode = WhitelistMode.values()[filter.getOrCreateTag().getInt("WhitelistMode")];
ListNBT attributes = filter.getOrCreateTag().getList("MatchedAttributes", NBT.TAG_COMPOUND);
for (INBT inbt : attributes) {
ItemAttribute attribute = ItemAttribute.fromNBT((CompoundNBT) inbt);
boolean matches = attribute.appliesTo(stack);
if (matches) {
switch (whitelistMode) {
case BLACKLIST:
return false;
case WHITELIST_CONJ:
continue;
case WHITELIST_DISJ:
return true;
}
} else {
switch (whitelistMode) {
case BLACKLIST:
continue;
case WHITELIST_CONJ:
return false;
case WHITELIST_DISJ:
continue;
}
}
}
switch (whitelistMode) {
case BLACKLIST:
return true;
case WHITELIST_CONJ:
return true;
case WHITELIST_DISJ:
return false;
}
}
return false;
}
}

View file

@ -0,0 +1,132 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.Arrays;
import java.util.List;
import com.simibubi.create.ScreenResources;
import com.simibubi.create.foundation.gui.widgets.IconButton;
import com.simibubi.create.foundation.gui.widgets.Indicator;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.logistics.item.filter.FilterScreenPacket.Option;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.text.ITextComponent;
public class FilterScreen extends AbstractFilterScreen<FilterContainer> {
private static final String PREFIX = "gui.filter.";
private String whitelistN = Lang.translate(PREFIX + "whitelist");
private String whitelistDESC = Lang.translate(PREFIX + "whitelist.description");
private String blacklistN = Lang.translate(PREFIX + "blacklist");
private String blacklistDESC = Lang.translate(PREFIX + "blacklist.description");
private String respectDataN = Lang.translate(PREFIX + "respect_data");
private String respectDataDESC = Lang.translate(PREFIX + "respect_data.description");
private String ignoreDataN = Lang.translate(PREFIX + "ignore_data");
private String ignoreDataDESC = Lang.translate(PREFIX + "ignore_data.description");
private IconButton whitelist, blacklist;
private IconButton respectNBT, ignoreNBT;
private Indicator whitelistIndicator, blacklistIndicator;
private Indicator respectNBTIndicator, ignoreNBTIndicator;
public FilterScreen(FilterContainer container, PlayerInventory inv, ITextComponent title) {
super(container, inv, title, ScreenResources.FILTER);
}
@Override
protected void init() {
super.init();
int x = guiLeft;
int y = guiTop;
blacklist = new IconButton(x + 58, y + 72, ScreenResources.I_BLACKLIST);
blacklist.setToolTip(blacklistN);
whitelist = new IconButton(x + 76, y + 72, ScreenResources.I_WHITELIST);
whitelist.setToolTip(whitelistN);
blacklistIndicator = new Indicator(x + 58, y + 67, "");
whitelistIndicator = new Indicator(x + 76, y + 67, "");
widgets.addAll(Arrays.asList(blacklist, whitelist, blacklistIndicator, whitelistIndicator));
respectNBT = new IconButton(x + 98, y + 72, ScreenResources.I_RESPECT_NBT);
respectNBT.setToolTip(respectDataN);
ignoreNBT = new IconButton(x + 116, y + 72, ScreenResources.I_IGNORE_NBT);
ignoreNBT.setToolTip(ignoreDataN);
respectNBTIndicator = new Indicator(x + 98, y + 67, "");
ignoreNBTIndicator = new Indicator(x + 116, y + 67, "");
widgets.addAll(Arrays.asList(respectNBT, ignoreNBT, respectNBTIndicator, ignoreNBTIndicator));
handleIndicators();
}
@Override
public boolean mouseClicked(double x, double y, int button) {
boolean mouseClicked = super.mouseClicked(x, y, button);
if (button != 0)
return mouseClicked;
if (blacklist.isHovered()) {
container.blacklist = true;
sendOptionUpdate(Option.BLACKLIST);
return true;
}
if (whitelist.isHovered()) {
container.blacklist = false;
sendOptionUpdate(Option.WHITELIST);
return true;
}
if (respectNBT.isHovered()) {
container.respectNBT = true;
sendOptionUpdate(Option.RESPECT_DATA);
return true;
}
if (ignoreNBT.isHovered()) {
container.respectNBT = false;
sendOptionUpdate(Option.IGNORE_DATA);
return true;
}
return mouseClicked;
}
@Override
protected List<IconButton> getTooltipButtons() {
return Arrays.asList(blacklist, whitelist, respectNBT, ignoreNBT);
}
@Override
protected List<String> getTooltipDescriptions() {
return Arrays.asList(blacklistDESC, whitelistDESC, respectDataDESC, ignoreDataDESC);
}
@Override
protected boolean isButtonEnabled(IconButton button) {
if (button == blacklist)
return !container.blacklist;
if (button == whitelist)
return container.blacklist;
if (button == respectNBT)
return !container.respectNBT;
if (button == ignoreNBT)
return container.respectNBT;
return true;
}
@Override
protected boolean isIndicatorOn(Indicator indicator) {
if (indicator == blacklistIndicator)
return container.blacklist;
if (indicator == whitelistIndicator)
return !container.blacklist;
if (indicator == respectNBTIndicator)
return container.respectNBT;
if (indicator == ignoreNBTIndicator)
return !container.respectNBT;
return false;
}
}

View file

@ -0,0 +1,83 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.function.Supplier;
import com.simibubi.create.foundation.packet.SimplePacketBase;
import com.simibubi.create.modules.logistics.item.filter.AttributeFilterContainer.WhitelistMode;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent.Context;
public class FilterScreenPacket extends SimplePacketBase {
enum Option {
CLEAR, WHITELIST, WHITELIST2, BLACKLIST, RESPECT_DATA, IGNORE_DATA, ADD_TAG;
}
private Option option;
private CompoundNBT data;
public FilterScreenPacket(Option option) {
this(option, new CompoundNBT());
}
public FilterScreenPacket(Option option, CompoundNBT data) {
this.option = option;
this.data = data;
}
public FilterScreenPacket(PacketBuffer buffer) {
option = Option.values()[buffer.readInt()];
data = buffer.readCompoundTag();
}
@Override
public void write(PacketBuffer buffer) {
buffer.writeInt(option.ordinal());
buffer.writeCompoundTag(data);
}
@Override
public void handle(Supplier<Context> context) {
context.get().enqueueWork(() -> {
ServerPlayerEntity player = context.get().getSender();
if (player.openContainer instanceof AbstractFilterContainer) {
AbstractFilterContainer c = (AbstractFilterContainer) player.openContainer;
if (option == Option.CLEAR) {
c.clearContents();
return;
}
}
if (player.openContainer instanceof FilterContainer) {
FilterContainer c = (FilterContainer) player.openContainer;
if (option == Option.WHITELIST)
c.blacklist = false;
if (option == Option.BLACKLIST)
c.blacklist = true;
if (option == Option.RESPECT_DATA)
c.respectNBT = true;
if (option == Option.IGNORE_DATA)
c.respectNBT = false;
}
if (player.openContainer instanceof AttributeFilterContainer) {
AttributeFilterContainer c = (AttributeFilterContainer) player.openContainer;
if (option == Option.WHITELIST)
c.whitelistMode = WhitelistMode.WHITELIST_DISJ;
if (option == Option.WHITELIST2)
c.whitelistMode = WhitelistMode.WHITELIST_CONJ;
if (option == Option.BLACKLIST)
c.whitelistMode = WhitelistMode.BLACKLIST;
if (option == Option.ADD_TAG)
c.appendSelectedAttribute(ItemAttribute.fromNBT(data));
}
});
context.get().setPacketHandled(true);
}
}

View file

@ -0,0 +1,274 @@
package com.simibubi.create.modules.logistics.item.filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicates;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.AbstractFurnaceTileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.forgespi.language.IModInfo;
public interface ItemAttribute {
static List<ItemAttribute> types = new ArrayList<>();
static ItemAttribute standard = register(StandardTraits.DUMMY);
static ItemAttribute inTag = register(new InTag(new ResourceLocation("dummy")));
static ItemAttribute inItemGroup = register(new InItemGroup(ItemGroup.MISC));
static ItemAttribute addedBy = register(new AddedBy("dummy"));
static ItemAttribute register(ItemAttribute attributeType) {
types.add(attributeType);
return attributeType;
}
public boolean appliesTo(ItemStack stack);
public List<ItemAttribute> listAttributesOf(ItemStack stack);
public String getTranslationKey();
void writeNBT(CompoundNBT nbt);
ItemAttribute readNBT(CompoundNBT nbt);
public default void serializeNBT(CompoundNBT nbt) {
CompoundNBT compound = new CompoundNBT();
writeNBT(compound);
nbt.put(getNBTKey(), compound);
}
public static ItemAttribute fromNBT(CompoundNBT nbt) {
for (ItemAttribute itemAttribute : types) {
if (!itemAttribute.canRead(nbt))
continue;
return itemAttribute.readNBT(nbt.getCompound(itemAttribute.getNBTKey()));
}
return null;
}
default Object[] getTranslationParameters() {
return new String[0];
}
default boolean canRead(CompoundNBT nbt) {
return nbt.contains(getNBTKey());
}
default String getNBTKey() {
return getTranslationKey();
}
@OnlyIn(value = Dist.CLIENT)
default String format() {
return Lang.translate("item_attributes." + getTranslationKey(), getTranslationParameters());
}
public static enum StandardTraits implements ItemAttribute {
DUMMY(s -> false),
PLACEABLE(s -> s.getItem() instanceof BlockItem),
CONSUMABLE(ItemStack::isFood),
ENCHANTED(ItemStack::isEnchanted),
DAMAGED(ItemStack::isDamaged),
BADLY_DAMAGED(s -> s.isDamaged() && s.getDamage() / s.getMaxDamage() > 3 / 4f),
NOT_STACKABLE(Predicates.not(ItemStack::isStackable)),
EQUIPABLE(s -> s.getEquipmentSlot() != null),
FURNACE_FUEL(AbstractFurnaceTileEntity::isFuel);
private Predicate<ItemStack> test;
private StandardTraits(Predicate<ItemStack> test) {
this.test = test;
}
@Override
public boolean appliesTo(ItemStack stack) {
return test.test(stack);
}
@Override
public List<ItemAttribute> listAttributesOf(ItemStack stack) {
List<ItemAttribute> attributes = new ArrayList<>();
for (StandardTraits trait : values())
if (trait.test.test(stack))
attributes.add(trait);
return attributes;
}
@Override
public String getTranslationKey() {
return Lang.asId(name());
}
@Override
public String getNBTKey() {
return "standard_trait";
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.putBoolean(name(), true);
}
@Override
public ItemAttribute readNBT(CompoundNBT nbt) {
for (StandardTraits trait : values())
if (nbt.contains(trait.name()))
return trait;
return null;
}
}
public static class InTag implements ItemAttribute {
ResourceLocation tagName;
public InTag(ResourceLocation tagName) {
this.tagName = tagName;
}
@Override
public boolean appliesTo(ItemStack stack) {
return stack.getItem().getTags().contains(tagName);
}
@Override
public List<ItemAttribute> listAttributesOf(ItemStack stack) {
return stack.getItem().getTags().stream().map(InTag::new).collect(Collectors.toList());
}
@Override
public String getTranslationKey() {
return "in_tag";
}
@Override
public Object[] getTranslationParameters() {
return new Object[] { "#" + tagName.toString() };
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.putString("space", tagName.getNamespace());
nbt.putString("path", tagName.getPath());
}
@Override
public ItemAttribute readNBT(CompoundNBT nbt) {
return new InTag(new ResourceLocation(nbt.getString("space"), nbt.getString("path")));
}
}
public static class InItemGroup implements ItemAttribute {
private ItemGroup group;
public InItemGroup(ItemGroup group) {
this.group = group;
}
@Override
public boolean appliesTo(ItemStack stack) {
Item item = stack.getItem();
return item.getGroup() == group;
}
@Override
public List<ItemAttribute> listAttributesOf(ItemStack stack) {
ItemGroup group = stack.getItem().getGroup();
return group == null ? Collections.emptyList() : Arrays.asList(new InItemGroup(group));
}
@Override
public String getTranslationKey() {
return "in_item_group";
}
@OnlyIn(value = Dist.CLIENT)
public String format() {
return Lang.translate("item_attributes." + getTranslationKey(), I18n.format(group.getTranslationKey()));
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.putString("path", group.getPath());
}
@Override
public ItemAttribute readNBT(CompoundNBT nbt) {
String readPath = nbt.getString("path");
for (ItemGroup group : ItemGroup.GROUPS)
if (group.getPath().equals(readPath))
return new InItemGroup(group);
return null;
}
}
public static class AddedBy implements ItemAttribute {
private String modId;
public AddedBy(String modId) {
this.modId = modId;
}
@Override
public boolean appliesTo(ItemStack stack) {
return modId.equals(stack.getItem().getCreatorModId(stack));
}
@Override
public List<ItemAttribute> listAttributesOf(ItemStack stack) {
String id = stack.getItem().getCreatorModId(stack);
return id == null ? Collections.emptyList() : Arrays.asList(new AddedBy(id));
}
@Override
public String getTranslationKey() {
return "added_by";
}
@Override
public Object[] getTranslationParameters() {
Optional<? extends ModContainer> modContainerById = ModList.get().getModContainerById(modId);
String name = modContainerById.map(ModContainer::getModInfo).map(IModInfo::getDisplayName)
.orElse(StringUtils.capitalize(modId));
return new Object[] { name };
}
@Override
public void writeNBT(CompoundNBT nbt) {
nbt.putString("id", modId);
}
@Override
public ItemAttribute readNBT(CompoundNBT nbt) {
return new AddedBy(nbt.getString("id"));
}
}
}

View file

@ -16,6 +16,8 @@
"item.create.belt_connector": "Mechanical Belt",
"item.create.goggles": "Engineer's Goggles",
"item.create.filter": "Filter",
"item.create.property_filter": "Attribute Filter",
"item.create.logistical_filter": "Address Filter",
"item.create.rose_quartz": "Rose Quartz",
"item.create.refined_rose_quartz": "Refined Rose Quartz",
"item.create.refined_radiance_cube": "Refined Radiance",
@ -406,6 +408,37 @@
"create.gui.requester.requestedItemCount": "Requested Amount",
"create.gui.storage.passiveModeOnly": "Item Storage is Passive only",
"create.gui.filter.blacklist": "Blacklist",
"create.gui.filter.blacklist.description": "Items pass if they do NOT match any of the above. An empty Blacklist accepts everything.",
"create.gui.filter.whitelist": "Whitelist",
"create.gui.filter.whitelist.description": "Items pass if they match any of the above. An empty Whitelist rejects anything.",
"create.gui.filter.respect_data": "Respect Data",
"create.gui.filter.respect_data.description": "Items only match if their durability, enchantments and other attributes match as well.",
"create.gui.filter.ignore_data": "Ignore Data",
"create.gui.filter.ignore_data.description": "Items match regardless of their attributes.",
"create.item_attributes.placeable": "is placeable",
"create.item_attributes.consumable": "can be eaten",
"create.item_attributes.enchanted": "is enchanted",
"create.item_attributes.damaged": "is damaged",
"create.item_attributes.badly_damaged": "is heavily damaged",
"create.item_attributes.not_stackable": "cannot stack",
"create.item_attributes.equipable": "can be equipped",
"create.item_attributes.furnace_fuel": "is furnace fuel",
"create.item_attributes.in_tag": "is tagged %1$s",
"create.item_attributes.in_item_group": "belongs to %1$s",
"create.item_attributes.added_by": "was added by %1$s",
"create.gui.attribute_filter.no_selected_attributes": "No attributes selected",
"create.gui.attribute_filter.selected_attributes": "Selected attributes:",
"create.gui.attribute_filter.whitelist_disjunctive": "Whitelist (Any)",
"create.gui.attribute_filter.whitelist_disjunctive.description": "Items pass if they have at least one of the selected attributes.",
"create.gui.attribute_filter.whitelist_conjunctive": "Whitelist (All)",
"create.gui.attribute_filter.whitelist_conjunctive.description": "Items pass only if they have ALL of the selected attributes.",
"create.gui.attribute_filter.blacklist": "Blacklist",
"create.gui.attribute_filter.blacklist.description": "Items pass if they do NOT have any of the selected attributes.",
"create.gui.attribute_filter.add_reference_item": "Add Reference Item",
"create.tooltip.holdKey": "Hold [%1$s]",
"create.tooltip.holdKeyOrKey": "Hold [%1$s] or [%2$s]",
"create.tooltip.keyShift": "Shift",
@ -425,6 +458,7 @@
"create.tooltip.capacityProvided.low": "Small",
"create.tooltip.capacityProvided.medium": "Medium",
"create.tooltip.capacityProvided.high": "Large",
"create.tooltip.capacityProvided.asGenerator": "(As Generator)",
"create.tooltip.wip": "WIP",
"create.tooltip.workInProgress": "Work in progress!",
@ -484,7 +518,21 @@
"item.create.tree_fertilizer.tooltip.summary": "A powerful combination of minerals suitable for common tree types",
"item.create.tree_fertilizer.tooltip.condition1": "When used on Sapling",
"item.create.tree_fertilizer.tooltip.behaviour1": "Grows Trees regardless of their spacing Conditions",
"item.create.filter.tooltip": "FILTER",
"item.create.filter.tooltip.summary": "_Controls_ _outputs_ and inputs of logistical devices with more _precision,_ matching them against a _set_ _of_ _items_ or several _nested_ _filters._",
"item.create.filter.tooltip.condition1": "When in filter slot",
"item.create.filter.tooltip.behaviour1": "_Controls_ item flow according to its _configuration._",
"item.create.filter.tooltip.condition2": "When R-Clicked",
"item.create.filter.tooltip.behaviour2": "Opens the _configuration_ _interface._",
"item.create.property_filter.tooltip": "ATTRIBUTE FILTER",
"item.create.property_filter.tooltip.summary": "_Controls_ _outputs_ and inputs of logistical devices with more _precision,_ matching them against a _set_ _of_ item _attributes_ and _categories._",
"item.create.property_filter.tooltip.condition1": "When in filter slot",
"item.create.property_filter.tooltip.behaviour1": "_Controls_ item flow according to its _configuration._",
"item.create.property_filter.tooltip.condition2": "When R-Clicked",
"item.create.property_filter.tooltip.behaviour2": "Opens the _configuration_ _interface._",
"block.create.cocoa_log.tooltip": "COCOA LOG",
"block.create.cocoa_log.tooltip.summary": "An augmented jungle log allowing for easier automation of _Cocoa_ _Beans_",
"block.create.cocoa_log.tooltip.condition1": "When Mature",
@ -734,6 +782,7 @@
"block.create.package_funnel.tooltip": "WIP",
"block.create.logisticians_table.tooltip": "WIP",
"item.create.logistical_dial.tooltip": "WIP",
"item.create.logistical_filter.tooltip": "WIP",
"itemGroup.create": "Create"
}

View file

@ -2,10 +2,8 @@
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"0": "create:block/net",
"1": "create:block/brass_casing",
"2": "create:block/clutch_off",
"particle": "create:block/net"
"0": "create:item/filter",
"particle": "create:item/filter"
},
"elements": [
{
@ -13,12 +11,12 @@
"from": [13, 0, 3],
"to": [15, 2, 13],
"faces": {
"north": {"uv": [0, 6, 2, 8], "texture": "#1"},
"east": {"uv": [3, 0, 13, 2], "texture": "#1"},
"south": {"uv": [14, 6, 16, 8], "texture": "#1"},
"west": {"uv": [3, 0, 13, 2], "texture": "#1"},
"up": {"uv": [0, 3, 2, 13], "rotation": 180, "texture": "#1"},
"down": {"uv": [14, 3, 16, 13], "texture": "#1"}
"north": {"uv": [14, 0, 16, 2], "texture": "#0"},
"east": {"uv": [0, 0, 2, 10], "rotation": 90, "texture": "#0"},
"south": {"uv": [14, 0, 16, 2], "rotation": 180, "texture": "#0"},
"west": {"uv": [14, 0, 16, 10], "rotation": 270, "texture": "#0"},
"up": {"uv": [14, 0, 16, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [14, 0, 16, 10], "rotation": 180, "texture": "#0"}
}
},
{
@ -26,12 +24,12 @@
"from": [1, 0, 3],
"to": [3, 2, 13],
"faces": {
"north": {"uv": [2, 6, 0, 8], "texture": "#1"},
"east": {"uv": [13, 0, 3, 2], "texture": "#1"},
"south": {"uv": [16, 6, 14, 8], "texture": "#1"},
"west": {"uv": [13, 0, 3, 2], "texture": "#1"},
"up": {"uv": [2, 3, 0, 13], "rotation": 180, "texture": "#1"},
"down": {"uv": [16, 3, 14, 13], "texture": "#1"}
"north": {"uv": [16, 0, 14, 2], "texture": "#0"},
"east": {"uv": [14, 10, 16, 0], "rotation": 270, "texture": "#0"},
"south": {"uv": [16, 0, 14, 2], "rotation": 180, "texture": "#0"},
"west": {"uv": [0, 10, 2, 0], "rotation": 90, "texture": "#0"},
"up": {"uv": [16, 0, 14, 10], "rotation": 180, "texture": "#0"},
"down": {"uv": [16, 0, 14, 10], "rotation": 180, "texture": "#0"}
}
},
{
@ -39,8 +37,12 @@
"from": [3, 1, 4],
"to": [13, 1.1, 12],
"faces": {
"up": {"uv": [3.5, 4.5, 13.5, 12.5], "texture": "#0"},
"down": {"uv": [3.5, 4.5, 13.5, 12.5], "texture": "#0"}
"north": {"uv": [0, 0, 0, 0], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [0, 0, 0, 0], "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [2.5, 0.5, 12.5, 8.5], "texture": "#0"},
"down": {"uv": [2.5, 0.5, 12.5, 8.5], "texture": "#0"}
}
},
{
@ -48,10 +50,12 @@
"from": [3, 0.5, 3],
"to": [13, 1.5, 4],
"faces": {
"north": {"uv": [2, 7, 12, 8], "texture": "#2"},
"south": {"uv": [3, 7, 13, 8], "texture": "#2"},
"up": {"uv": [3, 7, 13, 8], "texture": "#2"},
"down": {"uv": [3, 7, 13, 8], "texture": "#2"}
"north": {"uv": [3, 9, 13, 10], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [3, 9, 13, 10], "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [3, 9, 13, 10], "texture": "#0"},
"down": {"uv": [3, 9, 13, 10], "texture": "#0"}
}
},
{
@ -59,10 +63,12 @@
"from": [3, 0.5, 12],
"to": [13, 1.5, 13],
"faces": {
"north": {"uv": [13, 7, 3, 8], "texture": "#2"},
"south": {"uv": [14, 7, 4, 8], "texture": "#2"},
"up": {"uv": [3, 8, 13, 7], "texture": "#2"},
"down": {"uv": [3, 8, 13, 7], "texture": "#2"}
"north": {"uv": [3, 9, 13, 10], "texture": "#0"},
"east": {"uv": [0, 0, 0, 0], "texture": "#0"},
"south": {"uv": [3, 9, 13, 10], "texture": "#0"},
"west": {"uv": [0, 0, 0, 0], "texture": "#0"},
"up": {"uv": [3, 9, 13, 10], "texture": "#0"},
"down": {"uv": [3, 9, 13, 10], "texture": "#0"}
}
}
],
@ -88,7 +94,7 @@
"scale": [0.5, 0.5, 0.5]
},
"ground": {
"translation": [0, 0.75, 0],
"translation": [0, 3, 0],
"scale": [0.5, 0.5, 0.5]
},
"gui": {

View file

@ -0,0 +1,7 @@
{
"parent": "create:item/filter",
"textures": {
"0": "create:item/logistical_filter",
"particle": "create:item/logistical_filter"
}
}

View file

@ -0,0 +1,7 @@
{
"parent": "create:item/filter",
"textures": {
"0": "create:item/property_filter",
"particle": "create:item/property_filter"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B