diff --git a/src/main/java/com/simibubi/create/AllContainers.java b/src/main/java/com/simibubi/create/AllContainers.java index d14325d20..bfd6f7be3 100644 --- a/src/main/java/com/simibubi/create/AllContainers.java +++ b/src/main/java/com/simibubi/create/AllContainers.java @@ -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 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) diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index fa7f61a4e..d43b46d27 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -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)), diff --git a/src/main/java/com/simibubi/create/AllPackets.java b/src/main/java/com/simibubi/create/AllPackets.java index d3046b799..00c498277 100644 --- a/src/main/java/com/simibubi/create/AllPackets.java +++ b/src/main/java/com/simibubi/create/AllPackets.java @@ -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), diff --git a/src/main/java/com/simibubi/create/ClientEvents.java b/src/main/java/com/simibubi/create/ClientEvents.java index eed93ddf1..093d08585 100644 --- a/src/main/java/com/simibubi/create/ClientEvents.java +++ b/src/main/java/com/simibubi/create/ClientEvents.java @@ -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); } diff --git a/src/main/java/com/simibubi/create/ScreenResources.java b/src/main/java/com/simibubi/create/ScreenResources.java index 6be7adbe8..4c83da215 100644 --- a/src/main/java/com/simibubi/create/ScreenResources.java +++ b/src/main/java/com/simibubi/create/ScreenResources.java @@ -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), ; diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBox.java b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBox.java index 858861aad..225d9d0d4 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBox.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBox.java @@ -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; } diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java index d5fd3b5f4..2369e40c8 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java @@ -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(); diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java index e16da9cd5..297a1255d 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java @@ -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) { diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/base/TileEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/behaviour/base/TileEntityBehaviour.java index 1451339db..d9128d533 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/base/TileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/base/TileEntityBehaviour.java @@ -98,4 +98,8 @@ public abstract class TileEntityBehaviour { return ste.getBehaviour(type); } + public CompoundNBT writeToClient(CompoundNBT compound) { + return compound; + } + } diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java index fa9fdac41..ebaaf0c94 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java @@ -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 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 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 offset; diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringCountUpdatePacket.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringCountUpdatePacket.java new file mode 100644 index 000000000..5b8eaa568 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringCountUpdatePacket.java @@ -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 { + + 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(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java index f210c1ce9..1fa219809 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java @@ -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; + } + } diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringRenderer.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringRenderer.java index f54046877..ff73ab21c 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringRenderer.java @@ -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())); diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/inventory/ExtractingBehaviour.java b/src/main/java/com/simibubi/create/foundation/behaviour/inventory/ExtractingBehaviour.java index 9a2a5714a..6340f8c78 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/inventory/ExtractingBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/inventory/ExtractingBehaviour.java @@ -39,19 +39,17 @@ public class ExtractingBehaviour extends InventoryManagementBehaviour { this.customAmountFilter = filter; return this; } - + public ExtractingBehaviour withAdditionalFilter(Predicate 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; diff --git a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java index 33b6d644f..1a1f5e3d1 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java @@ -29,7 +29,7 @@ public abstract class AbstractSimiContainerScreen extends C protected List 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 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; diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java index 3d58e5dac..5f55bfbe8 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java @@ -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); } - + } diff --git a/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java b/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java index 2eeb26366..8b8d524bb 100644 --- a/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java +++ b/src/main/java/com/simibubi/create/foundation/item/ItemDescription.java @@ -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 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 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); } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/IRotate.java b/src/main/java/com/simibubi/create/modules/contraptions/base/IRotate.java index d7da35144..3e4bcb1eb 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/IRotate.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/IRotate.java @@ -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; + } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingBlock.java index 5687166d2..1d237fe5c 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingBlock.java @@ -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; + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanBlock.java index c55fdcb9c..4e501d553 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/fan/EncasedFanBlock.java @@ -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; + } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/motor/MotorBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/motor/MotorBlock.java index 4605e6717..2aa49755c 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/motor/MotorBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/motor/MotorBlock.java @@ -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, IHaveScrollableValue { +public class MotorBlock extends HorizontalKineticBlock + implements IWithTileEntity, 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; + } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/waterwheel/WaterWheelBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/waterwheel/WaterWheelBlock.java index b27ec550d..b7f73cf1e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/waterwheel/WaterWheelBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/waterwheel/WaterWheelBlock.java @@ -144,4 +144,9 @@ public class WaterWheelBlock extends HorizontalKineticBlock { return 1f; } + @Override + public boolean hideStressImpact() { + return true; + } + } diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/belts/BeltAttachableLogisticalBlock.java b/src/main/java/com/simibubi/create/modules/logistics/block/belts/BeltAttachableLogisticalBlock.java index df8d652f3..10233a838 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/belts/BeltAttachableLogisticalBlock.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/belts/BeltAttachableLogisticalBlock.java @@ -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(); } diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/transposer/TransposerTileEntity.java b/src/main/java/com/simibubi/create/modules/logistics/block/transposer/TransposerTileEntity.java index 2bce19482..92d8a97d1 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/transposer/TransposerTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/transposer/TransposerTileEntity.java @@ -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(); } diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/FilterItem.java b/src/main/java/com/simibubi/create/modules/logistics/item/FilterItem.java deleted file mode 100644 index d10d2c612..000000000 --- a/src/main/java/com/simibubi/create/modules/logistics/item/FilterItem.java +++ /dev/null @@ -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); - } - -} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterContainer.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterContainer.java new file mode 100644 index 000000000..6a01c3db5 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterContainer.java @@ -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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterScreen.java new file mode 100644 index 000000000..564c00211 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AbstractFilterScreen.java @@ -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 extends AbstractSimiContainerScreen { + + 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 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 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 tooltipDescriptions = getTooltipDescriptions(); + for (int i = 0; i < tooltipButtons.size(); i++) + fillToolTip(tooltipButtons.get(i), tooltipDescriptions.get(i)); + } + } + + protected List getTooltipButtons() { + return Collections.emptyList(); + } + + protected List getTooltipDescriptions() { + return Collections.emptyList(); + } + + private void fillToolTip(IconButton button, String tooltip) { + if (!button.isHovered()) + return; + List 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)); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterContainer.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterContainer.java new file mode 100644 index 000000000..819678412 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterContainer.java @@ -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 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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterScreen.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterScreen.java new file mode 100644 index 000000000..f5b32a1f7 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/AttributeFilterScreen.java @@ -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 { + + 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 attributesOfItem = new ArrayList<>(); + private List 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 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 getTooltipButtons() { + return Arrays.asList(blacklist, whitelistCon, whitelistDis); + } + + @Override + protected List 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; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterContainer.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterContainer.java new file mode 100644 index 000000000..e3ed993ec --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterContainer.java @@ -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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterItem.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterItem.java new file mode 100644 index 000000000..0ac7aba75 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterItem.java @@ -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 tooltip, ITooltipFlag flagIn) { + if (!AllKeys.shiftDown()) { + List makeSummary = makeSummary(stack); + if (makeSummary.isEmpty()) + return; + ItemDescription.add(tooltip, " "); + ItemDescription.add(tooltip, makeSummary); + } + } + + private List makeSummary(ItemStack filter) { + List 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 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; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreen.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreen.java new file mode 100644 index 000000000..d25a87f48 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreen.java @@ -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 { + + 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 getTooltipButtons() { + return Arrays.asList(blacklist, whitelist, respectNBT, ignoreNBT); + } + + @Override + protected List 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; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreenPacket.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreenPacket.java new file mode 100644 index 000000000..0ce993235 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/FilterScreenPacket.java @@ -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.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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/logistics/item/filter/ItemAttribute.java b/src/main/java/com/simibubi/create/modules/logistics/item/filter/ItemAttribute.java new file mode 100644 index 000000000..11f17fa82 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/logistics/item/filter/ItemAttribute.java @@ -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 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 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 test; + + private StandardTraits(Predicate test) { + this.test = test; + } + + @Override + public boolean appliesTo(ItemStack stack) { + return test.test(stack); + } + + @Override + public List listAttributesOf(ItemStack stack) { + List 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 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 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 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 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")); + } + + } + +} diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index 70c83ceda..bf6e7114d 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -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" } diff --git a/src/main/resources/assets/create/models/item/filter.json b/src/main/resources/assets/create/models/item/filter.json index 1f0cf52d6..40fb9ed09 100644 --- a/src/main/resources/assets/create/models/item/filter.json +++ b/src/main/resources/assets/create/models/item/filter.json @@ -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": { diff --git a/src/main/resources/assets/create/models/item/logistical_filter.json b/src/main/resources/assets/create/models/item/logistical_filter.json new file mode 100644 index 000000000..709b0ab34 --- /dev/null +++ b/src/main/resources/assets/create/models/item/logistical_filter.json @@ -0,0 +1,7 @@ +{ + "parent": "create:item/filter", + "textures": { + "0": "create:item/logistical_filter", + "particle": "create:item/logistical_filter" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/property_filter.json b/src/main/resources/assets/create/models/item/property_filter.json new file mode 100644 index 000000000..93cc3e8e0 --- /dev/null +++ b/src/main/resources/assets/create/models/item/property_filter.json @@ -0,0 +1,7 @@ +{ + "parent": "create:item/filter", + "textures": { + "0": "create:item/property_filter", + "particle": "create:item/property_filter" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/copper_casing.png b/src/main/resources/assets/create/textures/block/copper_casing.png new file mode 100644 index 000000000..a42508803 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/copper_casing.png differ diff --git a/src/main/resources/assets/create/textures/gui/filter.pdn b/src/main/resources/assets/create/textures/gui/filter.pdn deleted file mode 100644 index 31cc0e758..000000000 Binary files a/src/main/resources/assets/create/textures/gui/filter.pdn and /dev/null differ diff --git a/src/main/resources/assets/create/textures/gui/filter.png b/src/main/resources/assets/create/textures/gui/filter.png new file mode 100644 index 000000000..00a65a06f Binary files /dev/null and b/src/main/resources/assets/create/textures/gui/filter.png differ diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index e451bcdad..5f8a79ec8 100644 Binary files a/src/main/resources/assets/create/textures/gui/icons.png and b/src/main/resources/assets/create/textures/gui/icons.png differ diff --git a/src/main/resources/assets/create/textures/item/filter.png b/src/main/resources/assets/create/textures/item/filter.png index c1bf77f7d..c7907c4f2 100644 Binary files a/src/main/resources/assets/create/textures/item/filter.png and b/src/main/resources/assets/create/textures/item/filter.png differ diff --git a/src/main/resources/assets/create/textures/item/filter_1.png b/src/main/resources/assets/create/textures/item/filter_1.png deleted file mode 100644 index 0b6fca2f4..000000000 Binary files a/src/main/resources/assets/create/textures/item/filter_1.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/item/filter_2.png b/src/main/resources/assets/create/textures/item/filter_2.png deleted file mode 100644 index bf8d0a23e..000000000 Binary files a/src/main/resources/assets/create/textures/item/filter_2.png and /dev/null differ diff --git a/src/main/resources/assets/create/textures/item/logistical_filter.png b/src/main/resources/assets/create/textures/item/logistical_filter.png new file mode 100644 index 000000000..a2989b1db Binary files /dev/null and b/src/main/resources/assets/create/textures/item/logistical_filter.png differ diff --git a/src/main/resources/assets/create/textures/item/property_filter.png b/src/main/resources/assets/create/textures/item/property_filter.png new file mode 100644 index 000000000..935c38456 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/property_filter.png differ