diff --git a/build.gradle b/build.gradle index 0c3ac10ec8..c694d91fdf 100644 --- a/build.gradle +++ b/build.gradle @@ -132,9 +132,13 @@ repositories { includeGroup "mysticdrew" } } + maven { url = "https://oss.sonatype.org" } // RE2J } dependencies { + jarJar(implementation("com.google.re2j:re2j:1.8")) + additionalRuntimeClasspath "com.google.re2j:re2j:1.8" + jarJar(implementation("com.tterrag.registrate:Registrate:${registrate_version}")) jarJar("net.createmod.ponder:Ponder-NeoForge-${minecraft_version}:${ponder_version}") diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 94c9e8facd..e49febbf25 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1259,6 +1259,9 @@ "create.gui.filter.ignore_data.description": "Items match regardless of their attributes.", "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.package_filter.use_glob_patterns": "Use glob patterns for address pattern matching", + "create.gui.package_filter.use_regex": "Use regex for address pattern matching", + "create.gui.package_filter.use_regex_advanced": "(ADVANCED)", "create.gui.gauge.info_header": "Gauge Information:", "create.gui.goggles.at_current_speed": "at current speed", "create.gui.goggles.basin_contents": "Basin Contents:", @@ -1270,9 +1273,14 @@ "create.gui.package_port.catch_packages": "Catch packages addressed to...", "create.gui.package_port.catch_packages_empty": "Leave empty to match non-addressed", "create.gui.package_port.catch_packages_wildcard": "Use * as a text wildcard", + "create.gui.package_port.catch_packages_regex": "Regex: Escape special characters with \\", + "create.gui.package_port.catch_packages_wildcard_regex": "Use .* as a text wildcard", "create.gui.package_port.not_targeting_anything": "No target selected", "create.gui.package_port.send_and_receive": "Send and receive packages", "create.gui.package_port.send_only": "Only send packages", + "create.gui.package_port.use_glob_patterns": "Use glob patterns for address pattern matching", + "create.gui.package_port.use_regex": "(ADVANCED) Use regex for address pattern matching", + "create.gui.package_port.use_regex_disabled": "Enable regex in gameplay settings", "create.gui.redstone_requester.allow_partial": "Allow partial orders", "create.gui.redstone_requester.dont_allow_partial": "Must send all items", "create.gui.redstone_requester.requester_address": "Send order to...", @@ -1288,6 +1296,9 @@ "create.gui.schedule.move_up": "Move up", "create.gui.schedule.remove_entry": "Remove Action", "create.gui.schedule.rmb_remove": "Right-Click to Remove", + "create.gui.schedule.fetch_packages.use_glob": "Glob", + "create.gui.schedule.fetch_packages.use_regex": "Regex", + "create.gui.schedule.fetch_packages.address_matching": "Match Address by...", "create.gui.schematicTable.availableSchematics": "Available Schematics", "create.gui.schematicTable.finished": "Upload Finished!", "create.gui.schematicTable.noSchematics": "No Schematics Saved", @@ -3365,4 +3376,4 @@ "item.create.zinc_nugget": "Zinc Nugget", "itemGroup.create.base": "Create", "itemGroup.create.palettes": "Create's Building Blocks" -} \ No newline at end of file +} diff --git a/src/main/java/com/simibubi/create/AllDataComponents.java b/src/main/java/com/simibubi/create/AllDataComponents.java index a1d766343b..f65bc634d6 100644 --- a/src/main/java/com/simibubi/create/AllDataComponents.java +++ b/src/main/java/com/simibubi/create/AllDataComponents.java @@ -314,6 +314,11 @@ public class AllDataComponents { builder -> builder.persistent(Codec.STRING).networkSynchronized(ByteBufCodecs.STRING_UTF8) ); + public static final DataComponentType FILTER_BY_REGEX = register( + "filter_by_regex", + builder -> builder.persistent(Codec.BOOL).networkSynchronized(ByteBufCodecs.BOOL) + ); + public static final DataComponentType PACKAGE_CONTENTS = register( "package_contents", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(ItemContainerContents.STREAM_CODEC) diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorBlockEntity.java b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorBlockEntity.java index bcb3580c55..13e34aab5a 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorBlockEntity.java @@ -62,7 +62,7 @@ public class ChainConveyorBlockEntity extends KineticBlockEntity implements Tran public record ConnectionStats(float tangentAngle, float chainLength, Vec3 start, Vec3 end) { } - public record ConnectedPort(float chainPosition, @Nullable BlockPos connection, String filter) { + public record ConnectedPort(float chainPosition, @Nullable BlockPos connection, String filter, boolean usesRegex) { } public Set connections = new HashSet<>(); @@ -105,11 +105,9 @@ public boolean canAcceptMorePackages() { public boolean canAcceptPackagesFor(@Nullable BlockPos connection) { if (connection == null && !canAcceptMorePackages()) return false; - if (connection != null - && (!(level.getBlockEntity(worldPosition.offset(connection)) instanceof ChainConveyorBlockEntity otherClbe) - || !otherClbe.canAcceptMorePackages())) - return false; - return true; + return connection == null + || (level.getBlockEntity(worldPosition.offset(connection)) instanceof ChainConveyorBlockEntity otherClbe + && otherClbe.canAcceptMorePackages()); } public boolean canAcceptMorePackagesFromOtherConveyor() { @@ -206,9 +204,9 @@ public void tick() { box.chainPosition += serverSpeed * distancePerTick; box.chainPosition = Math.min(stats.chainLength, box.chainPosition); - float anticipatePosition = box.chainPosition; - anticipatePosition += serverSpeed * distancePerTick * 4; - anticipatePosition = Math.min(stats.chainLength, anticipatePosition); + float anticipatedPosition = box.chainPosition; + anticipatedPosition += serverSpeed * distancePerTick * 4; + anticipatedPosition = Math.min(stats.chainLength, anticipatedPosition); if (level.isClientSide() && !isVirtual()) continue; @@ -223,9 +221,9 @@ public void tick() { continue; boolean notAtPositionYet = box.chainPosition < chainPosition; - if (notAtPositionYet && anticipatePosition < chainPosition) + if (notAtPositionYet && anticipatedPosition < chainPosition) continue; - if (!PackageItem.matchAddress(box.item, port.filter())) + if (!PackageItem.matchAddress(box.item, port.filter(), port.usesRegex())) continue; if (notAtPositionYet) { notifyPortToAnticipate(portEntry.getKey()); @@ -276,7 +274,7 @@ public void tick() { boolean notAtPositionYet = !loopThresholdCrossed(box.chainPosition, prevChainPosition, offBranchAngle); if (notAtPositionYet && !loopThresholdCrossed(anticipatePosition, prevChainPosition, offBranchAngle)) continue; - if (!PackageItem.matchAddress(box.item, port.filter())) + if (!PackageItem.matchAddress(box.item, port.filter(), port.usesRegex())) continue; if (notAtPositionYet) { notifyPortToAnticipate(portEntry.getKey()); @@ -793,8 +791,7 @@ public void transform(BlockEntity be, StructureTransform transform) { .toList()); HashMap> newMap = new HashMap<>(); - travellingPackages.entrySet() - .forEach(e -> newMap.put(transform.applyWithoutOffset(e.getKey()), e.getValue())); + travellingPackages.forEach((key, value) -> newMap.put(transform.applyWithoutOffset(key), value)); travellingPackages = newMap; connectionStats = null; diff --git a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorRoutingTable.java b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorRoutingTable.java index fb8ac8f5aa..3493bcfe63 100644 --- a/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorRoutingTable.java +++ b/src/main/java/com/simibubi/create/content/kinetics/chainConveyor/ChainConveyorRoutingTable.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.mutable.MutableInt; import com.simibubi.create.content.logistics.box.PackageItem; +import com.simibubi.create.foundation.utility.LogisticParser; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -17,7 +18,7 @@ public class ChainConveyorRoutingTable { public static final int ENTRY_TIMEOUT = 100; public static final int PORT_ENTRY_TIMEOUT = 20; - public record RoutingTableEntry(String port, int distance, BlockPos nextConnection, MutableInt timeout, + public record RoutingTableEntry(String port, boolean useRegex, int distance, BlockPos nextConnection, MutableInt timeout, boolean endOfRoute) { public void tick() { @@ -29,7 +30,7 @@ public boolean invalid() { } public RoutingTableEntry copyForNeighbour(BlockPos connection) { - return new RoutingTableEntry(port, distance + 1, connection.multiply(-1), new MutableInt(ENTRY_TIMEOUT), + return new RoutingTableEntry(port, useRegex, distance + 1, connection.multiply(-1), new MutableInt(ENTRY_TIMEOUT), false); } @@ -49,13 +50,13 @@ public boolean shouldAdvertise() { return changed || lastUpdate > ENTRY_TIMEOUT - 20; } - public void receivePortInfo(String filter, BlockPos connection) { - insert(new RoutingTableEntry(filter, "*".equals(filter) ? 1000 : 0, connection, new MutableInt(PORT_ENTRY_TIMEOUT), true)); + public void receivePortInfo(String filter, boolean usesRegex, BlockPos connection) { + insert(new RoutingTableEntry(filter, usesRegex, LogisticParser.matchesAll(filter, usesRegex) ? Integer.MAX_VALUE : 0, connection, new MutableInt(PORT_ENTRY_TIMEOUT), true)); } public BlockPos getExitFor(ItemStack box) { for (RoutingTableEntry entry : entriesByDistance) - if (PackageItem.matchAddress(box, entry.port())) + if (PackageItem.matchAddress(box, entry.port(), entry.useRegex())) return entry.nextConnection(); return BlockPos.ZERO; } diff --git a/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java b/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java index a773e61a7a..36e6575d5a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/box/PackageItem.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; +import com.google.re2j.Pattern; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllDataComponents; @@ -16,8 +17,9 @@ import com.simibubi.create.content.logistics.stockTicker.PackageOrderWithCrafts; import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.LogisticParser; + import net.createmod.catnip.codecs.stream.CatnipStreamCodecBuilders; -import net.createmod.catnip.data.Glob; import net.createmod.catnip.math.VecHelper; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; @@ -139,20 +141,21 @@ public static void addOrderContext(ItemStack box, PackageOrderWithCrafts orderCo box.set(AllDataComponents.PACKAGE_ORDER_CONTEXT, orderContext); } - public static boolean matchAddress(ItemStack box, String address) { - return matchAddress(getAddress(box), address); + public static boolean matchAddress(ItemStack box, String address, boolean useRegex) { + return matchAddress(getAddress(box), address, useRegex); } - public static boolean matchAddress(String boxAddress, String address) { + public static boolean matchAddress(String boxAddress, String address, boolean useRegex) { if (address.isBlank()) return boxAddress.isBlank(); - if (address.equals("*") || boxAddress.equals("*")) - return true; - String matcher = Glob.toRegexPattern(address, ""); - String boxMatcher = Glob.toRegexPattern(boxAddress, ""); - return address.matches(boxMatcher) || boxAddress.matches(matcher); + Pattern addressMatcher = LogisticParser.dynamicToRegex(address, "", useRegex); + Pattern boxAddressMatcher = LogisticParser.dynamicToRegex(boxAddress, "", useRegex); + + return LogisticParser.anyMatches(addressMatcher, boxAddress) || LogisticParser.anyMatches(boxAddressMatcher, address); } + // public static boolean + public static String getAddress(ItemStack box) { return box.getOrDefault(AllDataComponents.PACKAGE_ADDRESS, ""); } diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java index 599befa1ab..4a338aa838 100644 --- a/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterItemStack.java @@ -239,16 +239,18 @@ public boolean test(Level world, ItemStack stack, boolean matchNBT) { public static class PackageFilterItemStack extends FilterItemStack { public String filterString; + public boolean useRegex; protected PackageFilterItemStack(ItemStack filter) { super(filter); filterString = PackageItem.getAddress(filter); + useRegex = filter.getOrDefault(AllDataComponents.FILTER_BY_REGEX, false); } @Override public boolean test(Level world, ItemStack stack, boolean matchNBT) { return (filterString.isBlank() && super.test(world, stack, matchNBT)) - || PackageItem.isPackage(stack) && PackageItem.matchAddress(stack, filterString); + || PackageItem.isPackage(stack) && PackageItem.matchAddress(stack, filterString, useRegex); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java index a50dd5fd9b..43a39f42ca 100644 --- a/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/FilterScreenPacket.java @@ -66,11 +66,13 @@ public void handle(ServerPlayer player) { if (player.containerMenu instanceof PackageFilterMenu c) { if (option == Option.UPDATE_ADDRESS) c.address = tag.getString("Address"); + if (option == Option.UPDATE_MATCH_TYPE) + c.useRegex = tag.getBoolean("UseRegex"); } } public enum Option { - WHITELIST, WHITELIST2, BLACKLIST, RESPECT_DATA, IGNORE_DATA, UPDATE_FILTER_ITEM, ADD_TAG, ADD_INVERTED_TAG, UPDATE_ADDRESS; + WHITELIST, WHITELIST2, BLACKLIST, RESPECT_DATA, IGNORE_DATA, UPDATE_FILTER_ITEM, ADD_TAG, ADD_INVERTED_TAG, UPDATE_ADDRESS, UPDATE_MATCH_TYPE; public static final StreamCodec STREAM_CODEC = CatnipStreamCodecBuilders.ofEnum(Option.class); } diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterMenu.java b/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterMenu.java index 25a1237794..afaab6e8f9 100644 --- a/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterMenu.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterMenu.java @@ -3,6 +3,8 @@ import com.simibubi.create.AllDataComponents; import com.simibubi.create.AllMenuTypes; +import com.simibubi.create.infrastructure.config.AllConfigs; + import net.minecraft.client.gui.components.EditBox; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.world.entity.player.Inventory; @@ -14,6 +16,7 @@ public class PackageFilterMenu extends AbstractFilterMenu { String address; + boolean useRegex; EditBox addressInput; public PackageFilterMenu(MenuType type, int id, Inventory inv, RegistryFriendlyByteBuf extraData) { @@ -55,17 +58,23 @@ public void clearContents() { protected void initAndReadInventory(ItemStack filterItem) { super.initAndReadInventory(filterItem); address = filterItem.getOrDefault(AllDataComponents.PACKAGE_ADDRESS, ""); + useRegex = filterItem.getOrDefault(AllDataComponents.FILTER_BY_REGEX, false); + } + + public boolean usingRegex() { + return AllConfigs.server().extras.enableAdvancedRegex.get() && useRegex; } @Override protected void saveData(ItemStack filterItem) { super.saveData(filterItem); + filterItem.set(AllDataComponents.FILTER_BY_REGEX, useRegex); if (address.isBlank()) filterItem.remove(AllDataComponents.PACKAGE_ADDRESS); else filterItem.set(AllDataComponents.PACKAGE_ADDRESS, address); } - + @Override public ItemStack quickMoveStack(Player playerIn, int index) { return ItemStack.EMPTY; diff --git a/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterScreen.java index d53b130564..4657b5ca0b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/filter/PackageFilterScreen.java @@ -1,5 +1,11 @@ package com.simibubi.create.content.logistics.filter; +import com.simibubi.create.foundation.gui.AllIcons; + +import com.simibubi.create.foundation.utility.CreateLang; + +import net.minecraft.ChatFormatting; + import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.vertex.PoseStack; @@ -16,9 +22,12 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; +import java.util.concurrent.atomic.AtomicBoolean; + public class PackageFilterScreen extends AbstractFilterScreen { private AddressEditBox addressBox; + private IconButton useGlobPatternButton, useRegexButton; private boolean deferFocus; public PackageFilterScreen(PackageFilterMenu menu, Inventory inv, Component title) { @@ -37,6 +46,7 @@ protected void containerTick() { @Override protected void init() { + AtomicBoolean regexState = new AtomicBoolean(menu.useRegex); setWindowOffset(-11, 7); super.init(); @@ -49,6 +59,31 @@ protected void init() { addressBox.setResponder(this::onAddressEdited); addRenderableWidget(addressBox); + useGlobPatternButton = new IconButton(x + 18, y + 28 + 36, AllIcons.I_GLOB_PATTERN); + useGlobPatternButton.withCallback(() -> { + useGlobPatternButton.green = true; + useRegexButton.green = false; + regexState.set(false); + onRegexToggled(regexState); + }); + useGlobPatternButton.setToolTip(CreateLang.translate("gui.package_filter.use_glob_patterns") + .style(ChatFormatting.WHITE) + .component()); + addRenderableWidget(useGlobPatternButton); + + useRegexButton = new IconButton(x + 18 + 18, y + 28 + 36, AllIcons.I_REGEX); + useRegexButton.active = menu.usingRegex(); + useRegexButton.withCallback(() -> { + useGlobPatternButton.green = false; + useRegexButton.green = true; + regexState.set(true); + onRegexToggled(regexState); + }); + useRegexButton.setToolTip(CreateLang.translate("gui.package_filter.use_regex") + .style(ChatFormatting.GOLD) + .component()); + addRenderableWidget(useRegexButton); + setFocused(addressBox); } @@ -71,6 +106,13 @@ public void onAddressEdited(String s) { CatnipServices.NETWORK.sendToServer(new FilterScreenPacket(Option.UPDATE_ADDRESS, tag)); } + public void onRegexToggled(AtomicBoolean b) { + menu.useRegex = b.get(); + CompoundTag tag = new CompoundTag(); + tag.putBoolean("UseRegex", b.get()); + CatnipServices.NETWORK.sendToServer(new FilterScreenPacket(Option.UPDATE_MATCH_TYPE, tag)); + } + @Override public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { return super.mouseClicked(pMouseX, pMouseY, pButton); diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortAutomationInventoryWrapper.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortAutomationInventoryWrapper.java index 304863bc2e..a1220f4933 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortAutomationInventoryWrapper.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortAutomationInventoryWrapper.java @@ -29,7 +29,8 @@ public ItemStack extractItem(int slot, int amount, boolean simulate) { if (!PackageItem.isPackage(stack)) return false; String filterString = ppbe.getFilterString(); - return filterString != null && PackageItem.matchAddress(stack, filterString); + boolean usesRegex = ppbe.usingRegex(); + return filterString != null && PackageItem.matchAddress(stack, filterString, usesRegex); }, simulate); access = false; @@ -41,7 +42,8 @@ public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { if (!PackageItem.isPackage(stack)) return stack; String filterString = ppbe.getFilterString(); - if (filterString != null && PackageItem.matchAddress(stack, filterString)) + boolean usesRegex = ppbe.usingRegex(); + if (filterString != null && PackageItem.matchAddress(stack, filterString, usesRegex)) return stack; return super.insertItem(slot, stack, simulate); } diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortBlockEntity.java index 556e0709ff..83fa15d6a1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortBlockEntity.java @@ -12,6 +12,7 @@ import com.simibubi.create.foundation.blockEntity.behaviour.animatedContainer.AnimatedContainerBehaviour; import com.simibubi.create.foundation.item.SmartInventory; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; import net.createmod.catnip.codecs.CatnipCodecUtils; import net.minecraft.core.BlockPos; @@ -35,6 +36,7 @@ public abstract class PackagePortBlockEntity extends SmartBlockEntity implements MenuProvider { public boolean acceptsPackages; + public boolean usesRegex; public String addressFilter; public PackagePortTarget target; public SmartInventory inventory; @@ -46,6 +48,7 @@ public abstract class PackagePortBlockEntity extends SmartBlockEntity implements public PackagePortBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); addressFilter = ""; + usesRegex = false; acceptsPackages = true; inventory = new SmartInventory(18, this); itemHandler = new PackagePortAutomationInventoryWrapper(inventory, this); @@ -77,6 +80,10 @@ public String getFilterString() { return acceptsPackages ? addressFilter : null; } + public boolean usingRegex() { + return usesRegex && AllConfigs.server().extras.enableAdvancedRegex.get(); + } + @Override protected void write(CompoundTag tag, HolderLookup.Provider registries, boolean clientPacket) { super.write(tag, registries, clientPacket); @@ -84,6 +91,7 @@ protected void write(CompoundTag tag, HolderLookup.Provider registries, boolean tag.put("Target", CatnipCodecUtils.encode(PackagePortTarget.CODEC, target).orElseThrow()); tag.putString("AddressFilter", addressFilter); tag.putBoolean("AcceptsPackages", acceptsPackages); + tag.putBoolean("UsesRegex", usesRegex); tag.put("Inventory", inventory.serializeNBT(registries)); } @@ -95,6 +103,7 @@ protected void read(CompoundTag tag, HolderLookup.Provider registries, boolean c target = CatnipCodecUtils.decode(PackagePortTarget.CODEC, tag.getCompound("Target")).orElse(null); addressFilter = tag.getString("AddressFilter"); acceptsPackages = tag.getBoolean("AcceptsPackages"); + usesRegex = tag.getBoolean("UsesRegex"); if (clientPacket && prevTarget != target) invalidateRenderBoundingBox(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortConfigurationPacket.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortConfigurationPacket.java index 115bdf784f..285f57f850 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortConfigurationPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortConfigurationPacket.java @@ -3,6 +3,8 @@ import com.simibubi.create.AllPackets; import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; +import com.simibubi.create.infrastructure.config.AllConfigs; + import io.netty.buffer.ByteBuf; import net.minecraft.core.BlockPos; import net.minecraft.network.codec.ByteBufCodecs; @@ -14,16 +16,19 @@ public class PackagePortConfigurationPacket extends BlockEntityConfigurationPack BlockPos.STREAM_CODEC, packet -> packet.pos, ByteBufCodecs.STRING_UTF8, packet -> packet.newFilter, ByteBufCodecs.BOOL, packet -> packet.acceptPackages, + ByteBufCodecs.BOOL, packet -> packet.useRegex, PackagePortConfigurationPacket::new ); private final String newFilter; private final boolean acceptPackages; + private final boolean useRegex; - public PackagePortConfigurationPacket(BlockPos pos, String newFilter, boolean acceptPackages) { + public PackagePortConfigurationPacket(BlockPos pos, String newFilter, boolean acceptPackages, boolean useRegex) { super(pos); this.newFilter = newFilter; this.acceptPackages = acceptPackages; + this.useRegex = useRegex; } @Override @@ -33,10 +38,11 @@ public PacketTypeProvider getTypeProvider() { @Override protected void applySettings(ServerPlayer player, PackagePortBlockEntity be) { - if (be.addressFilter.equals(newFilter) && be.acceptsPackages == acceptPackages) + if (be.addressFilter.equals(newFilter) && be.acceptsPackages == acceptPackages && be.usesRegex == useRegex) return; be.addressFilter = newFilter; be.acceptsPackages = acceptPackages; + be.usesRegex = useRegex; be.filterChanged(); be.notifyUpdate(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortScreen.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortScreen.java index eaa769c403..aa0ee7167d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortScreen.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Stream; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.platform.InputConstants; @@ -14,6 +15,8 @@ import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.utility.CreateLang; +import com.simibubi.create.infrastructure.config.AllConfigs; + import net.createmod.catnip.gui.element.GuiGameElement; import net.createmod.catnip.gui.widget.AbstractSimiWidget; import net.createmod.catnip.platform.CatnipServices; @@ -25,6 +28,8 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + public class PackagePortScreen extends AbstractSimiContainerScreen { private boolean frogMode; @@ -34,6 +39,8 @@ public class PackagePortScreen extends AbstractSimiContainerScreen { + useGlobPatterns.green = true; + useRegex.green = false; + }); + useGlobPatterns.green = !menu.contentHolder.usesRegex; + useGlobPatterns.visible = menu.contentHolder.acceptsPackages; + useGlobPatterns.setToolTip( + CreateLang.translate("gui.package_port.use_glob_patterns") + .style(ChatFormatting.WHITE) + .component()); + addRenderableWidget(useGlobPatterns); + + useRegex = new IconButton(x + 37 + 18 + 22 + 18, y + background.getHeight() - 24, AllIcons.I_REGEX); + useRegex.withCallback(() -> { + useRegex.green = true; + useGlobPatterns.green = false; + }); + useRegex.green = menu.contentHolder.usesRegex; + + boolean regexEnabled = AllConfigs.server().extras.enableAdvancedRegex.get(); + + useRegex.visible = menu.contentHolder.acceptsPackages; + useRegex.active = regexEnabled; + useRegex.setToolTip( + CreateLang.translate("gui.package_port.use_regex") + .style(ChatFormatting.WHITE) + .component()); + + addRenderableWidget(useRegex); + + containerTick(); extraAreas = ImmutableList.of(new Rect2i(x + background.getWidth(), y + background.getHeight() - 50, 70, 60)); @@ -107,6 +152,8 @@ private int nameBoxX(String s, EditBox nameBox) { protected void containerTick() { acceptPackages.visible = menu.contentHolder.target != null; dontAcceptPackages.visible = menu.contentHolder.target != null; + useRegex.visible = menu.contentHolder.target != null; + useGlobPatterns.visible = menu.contentHolder.target != null; super.containerTick(); } @@ -149,16 +196,32 @@ protected void renderBg(GuiGraphics graphics, float pPartialTick, int pMouseX, i graphics.renderItem(menu.contentHolder.target.getIcon(), x + 1, y + 1); if (addressBox.isHovered()) { - graphics.renderComponentTooltip(font, List.of(CreateLang.translate("gui.package_port.catch_packages") - .color(AbstractSimiWidget.HEADER_RGB) - .component(), + List<@NotNull Component> staticTooltip = List.of(CreateLang.translate("gui.package_port.catch_packages") + .color(AbstractSimiWidget.HEADER_RGB) + .component(), CreateLang.translate("gui.package_port.catch_packages_empty") .style(ChatFormatting.GRAY) - .component(), - CreateLang.translate("gui.package_port.catch_packages_wildcard") + .component()); + List<@NotNull Component> dynamicTooltip; + + if (AllConfigs.server().extras.enableAdvancedRegex.get()) { + dynamicTooltip = List.of( + CreateLang.translate("gui.package_port.catch_packages_wildcard_regex") + .style(ChatFormatting.GRAY) + .component(), + CreateLang.translate("gui.package_port.catch_packages_regex") + .style(ChatFormatting.GOLD) + .component()); + } else { + dynamicTooltip = List.of( + CreateLang.translate("gui.package_port.catch_packages_wildcard") .style(ChatFormatting.GRAY) - .component()), - pMouseX, pMouseY); + .component()); + } + + List<@NotNull Component> fullTooltip = Stream.concat(staticTooltip.stream(), dynamicTooltip.stream()).toList(); + + graphics.renderComponentTooltip(font, fullTooltip, pMouseX, pMouseY); } } @@ -178,7 +241,7 @@ public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { @Override public void removed() { CatnipServices.NETWORK.sendToServer(new PackagePortConfigurationPacket(menu.contentHolder.getBlockPos(), addressBox.getValue(), - acceptPackages.green)); + acceptPackages.green, useRegex.green)); super.removed(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortTarget.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortTarget.java index 6719620966..9d71b37b39 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortTarget.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/PackagePortTarget.java @@ -10,6 +10,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; +import com.simibubi.create.Create; import com.simibubi.create.api.registry.CreateBuiltInRegistries; import com.simibubi.create.api.registry.CreateRegistries; import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorBlockEntity; @@ -18,6 +19,8 @@ import com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorPackage; import com.simibubi.create.content.trains.station.StationBlockEntity; +import com.simibubi.create.infrastructure.config.AllConfigs; + import io.netty.buffer.ByteBuf; import net.createmod.catnip.codecs.stream.CatnipStreamCodecBuilders; import net.minecraft.core.BlockPos; @@ -125,8 +128,10 @@ public boolean export(LevelAccessor level, BlockPos portPos, ItemStack box, bool @Override public void register(PackagePortBlockEntity ppbe, LevelAccessor level, BlockPos portPos) { - if (!(be(level, portPos) instanceof ChainConveyorBlockEntity clbe)) + if (!(be(level, portPos) instanceof ChainConveyorBlockEntity clbe)) { + Create.LOGGER.warn("No valid attached ChainConveyor"); return; + } ChainConveyorBlockEntity actualBe = clbe; // Jump to opposite chain if motion reversed @@ -153,9 +158,10 @@ public void register(PackagePortBlockEntity ppbe, LevelAccessor level, BlockPos String portFilter = ppbe.getFilterString(); if (portFilter == null) return; - actualBe.routingTable.receivePortInfo(portFilter, connection == null ? BlockPos.ZERO : connection); + actualBe.routingTable.receivePortInfo(portFilter, ppbe.usingRegex(), connection == null ? BlockPos.ZERO : connection); Map portMap = connection == null ? actualBe.loopPorts : actualBe.travelPorts; - portMap.put(relativePos.multiply(-1), new ConnectedPort(chainPos, connection, portFilter)); + portMap.put(relativePos.multiply(-1), new ConnectedPort(chainPos, connection, portFilter, ppbe.usingRegex())); + actualBe.notifyUpdate(); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportBlockEntity.java index 04e9e011e7..02bd48b94f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/packagePort/frogport/FrogportBlockEntity.java @@ -295,8 +295,9 @@ public boolean tryPullingFrom(IItemHandler handler) { if (!PackageItem.isPackage(stack)) return false; String filterString = getFilterString(); + boolean usesRegex = usingRegex(); return filterString == null || handler instanceof PackagerItemHandler - || !PackageItem.matchAddress(stack, filterString); + || !PackageItem.matchAddress(stack, filterString, usesRegex); }, false); if (extract.isEmpty()) return false; diff --git a/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java b/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java index baa05e1375..724bf37c94 100644 --- a/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java +++ b/src/main/java/com/simibubi/create/content/trains/display/GlobalTrainDisplayData.java @@ -6,10 +6,11 @@ import java.util.List; import java.util.Map; +import com.google.re2j.Pattern; import com.simibubi.create.Create; import com.simibubi.create.content.trains.entity.Train; -import net.createmod.catnip.data.Glob; +import com.simibubi.create.foundation.utility.LogisticParser; import net.minecraft.network.chat.MutableComponent; @@ -32,11 +33,10 @@ public static void refresh() { } public static List prepare(String filter, int maxLines) { - String regex = Glob.toRegexPattern(filter, ""); + Pattern regex = LogisticParser.globToRegex(filter, ""); return statusByDestination.entrySet() .stream() - .filter(e -> e.getKey() - .matches(regex)) + .filter(e -> LogisticParser.anyMatches(regex, e.getKey())) .flatMap(e -> e.getValue() .stream()) .sorted() diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java index d7aede323b..c33d7df013 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/ScheduleScreen.java @@ -12,6 +12,7 @@ import javax.annotation.Nullable; import com.google.common.collect.ImmutableList; +import com.google.re2j.Pattern; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllDataComponents; @@ -322,14 +323,14 @@ private List> getViableStations(IScheduleInput field) { continue; if (destination == field) continue; - String filter = destination.getFilterForRegex(); - if (filter.isBlank()) + Pattern filter = destination.getFilterRegex(); + if (filter.pattern().isBlank()) continue; Graphs: for (Iterator iterator = viableGraphs.iterator(); iterator.hasNext(); ) { TrackGraph trackGraph = iterator.next(); for (GlobalStation station : trackGraph.getPoints(EdgePointType.STATION)) { - if (station.name.matches(filter)) + if (filter.matches(station.name)) continue Graphs; } iterator.remove(); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java index 0fd404c276..526fa102a4 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java @@ -92,7 +92,7 @@ public DiscoveredPath start(ScheduleRuntime runtime, Level level) { firstPackage = PackageItem.getAddress(stack); for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { for (Entry port : globalStation.connectedPorts.entrySet()) { - if (!PackageItem.matchAddress(stack, port.getValue().address)) + if (!PackageItem.matchAddress(stack, port.getValue().address, port.getValue().usesRegex)) continue; anyMatch = true; validStations.add(globalStation); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java index f38b5d5baf..50a0ee094f 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/DestinationInstruction.java @@ -5,6 +5,12 @@ import javax.annotation.Nullable; +import com.google.re2j.Pattern; +import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import com.simibubi.create.foundation.utility.LogisticParser; + +import com.simibubi.create.infrastructure.config.AllConfigs; + import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; @@ -17,7 +23,6 @@ import com.simibubi.create.content.trains.station.GlobalStation; import com.simibubi.create.foundation.utility.CreateLang; -import net.createmod.catnip.data.Glob; import net.createmod.catnip.data.Pair; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.EditBox; @@ -28,6 +33,8 @@ import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + public class DestinationInstruction extends TextScheduleInstruction { @Override @@ -50,12 +57,37 @@ public ItemStack getSecondLineIcon() { return AllBlocks.TRACK_STATION.asStack(); } + @Override + @OnlyIn(Dist.CLIENT) + public void initConfigurationWidgets(ModularGuiLineBuilder builder) { + List<@NotNull String> scrollInputOptions = AllConfigs.server().extras.enableAdvancedRegex.get() + ? List.of("use_glob", "use_regex") + : List.of("use_glob"); + + builder.addTextInput(0, 103-18-9, (e, t) -> modifyEditBox(e), "Text") + .addSelectionScrollInput(103-22, + 40, + (si, l) -> si.forOptions(CreateLang + .translatedOptions("gui.schedule.fetch_packages", + scrollInputOptions)) + .titled(CreateLang + .translate("gui.schedule.fetch_packages.address_matching") + .component()), + "UseRegex"); + } + + public boolean useRegex() { + return data.getInt("UseRegex") == 1; + } + public String getFilter() { return getLabelText(); } - public String getFilterForRegex() { - return Glob.toRegexPattern(getFilter(), ""); + public Pattern getFilterRegex() { + if (getFilter().isBlank()) + return Pattern.compile(".*"); + return LogisticParser.dynamicToRegex(getFilter(), "", useRegex()); } @Override @@ -78,7 +110,7 @@ protected void modifyEditBox(EditBox box) { @Override @Nullable public DiscoveredPath start(ScheduleRuntime runtime, Level level) { - String regex = getFilterForRegex(); + Pattern regex = getFilterRegex(); boolean anyMatch = false; ArrayList validStations = new ArrayList<>(); Train train = runtime.train; @@ -91,7 +123,7 @@ public DiscoveredPath start(ScheduleRuntime runtime, Level level) { for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) { - if (!globalStation.name.matches(regex)) + if (!LogisticParser.anyMatches(regex, globalStation.name)) continue; anyMatch = true; validStations.add(globalStation); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java index 005488a3c0..077746bddf 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java @@ -5,6 +5,15 @@ import java.util.Map.Entry; import java.util.regex.PatternSyntaxException; +import com.google.re2j.Pattern; + +import com.simibubi.create.foundation.gui.ModularGuiLineBuilder; +import com.simibubi.create.foundation.utility.LogisticParser; + +import com.simibubi.create.infrastructure.config.AllConfigs; + +import net.createmod.catnip.data.Glob; + import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; @@ -21,7 +30,6 @@ import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort; import com.simibubi.create.foundation.utility.CreateLang; -import net.createmod.catnip.data.Glob; import net.createmod.catnip.data.Pair; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.EditBox; @@ -37,6 +45,8 @@ import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.items.IItemHandlerModifiable; +import org.jetbrains.annotations.NotNull; + public class FetchPackagesInstruction extends TextScheduleInstruction { @Override @@ -60,14 +70,37 @@ public ItemStack getSecondLineIcon() { return PackageStyles.getDefaultBox(); } + @Override + @OnlyIn(Dist.CLIENT) + public void initConfigurationWidgets(ModularGuiLineBuilder builder) { + List<@NotNull String> scrollInputOptions = AllConfigs.server().extras.enableAdvancedRegex.get() + ? List.of("use_glob", "use_regex") + : List.of("use_glob"); + + builder.addTextInput(0, 103-18-9, (e, t) -> modifyEditBox(e), "Text") + .addSelectionScrollInput(103-22, + 40, + (si, l) -> si.forOptions(CreateLang + .translatedOptions("gui.schedule.fetch_packages", + scrollInputOptions)) + .titled(CreateLang + .translate("gui.schedule.fetch_packages.address_matching") + .component()), + "UseRegex"); + } + + public boolean useRegex() { + return data.getString("UseRegex").contains("Regex"); + } + public String getFilter() { return getLabelText(); } - public String getFilterForRegex() { + public Pattern getFilterRegex() { if (getFilter().isBlank()) - return Glob.toRegexPattern("*", ""); - return Glob.toRegexPattern(getFilter(), ""); + return Pattern.compile(".*"); + return LogisticParser.dynamicToRegex(getFilter(), "", useRegex()); } @Override @@ -102,8 +135,7 @@ public DiscoveredPath start(ScheduleRuntime runtime, Level level) { MinecraftServer server = level.getServer(); if (server == null) return null; - - String regex = getFilterForRegex(); + boolean anyMatch = false; ArrayList validStations = new ArrayList<>(); Train train = runtime.train; @@ -118,24 +150,25 @@ public DiscoveredPath start(ScheduleRuntime runtime, Level level) { ServerLevel dimLevel = server.getLevel(globalStation.blockEntityDimension); if (dimLevel == null) continue; - + Pattern regex = getFilterRegex(); + for (Entry entry : globalStation.connectedPorts.entrySet()) { GlobalPackagePort port = entry.getValue(); BlockPos pos = entry.getKey(); IItemHandlerModifiable postboxInventory = port.offlineBuffer; - if (dimLevel.isLoaded(pos) && dimLevel.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) + if (dimLevel.isLoaded(pos) && dimLevel.getBlockEntity(pos) instanceof PostboxBlockEntity ppbe) { postboxInventory = ppbe.inventory; + } for (int slot = 0; slot < postboxInventory.getSlots(); slot++) { ItemStack stack = postboxInventory.getStackInSlot(slot); if (!PackageItem.isPackage(stack)) continue; - if (PackageItem.matchAddress(stack, port.address)) + if (PackageItem.matchAddress(stack, port.address, port.usesRegex)) continue; try { - if (!PackageItem.getAddress(stack) - .matches(regex)) + if (!regex.matches(PackageItem.getAddress(stack))) continue; anyMatch = true; validStations.add(globalStation); diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java index 0ab7670759..8892d795d9 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/ScheduleInstruction.java @@ -34,6 +34,7 @@ public final CompoundTag write(HolderLookup.Provider registries) { CompoundTag dataCopy = data.copy(); writeAdditional(registries, dataCopy); tag.putString("Id", getId().toString()); + tag.put("Data", dataCopy); return tag; } diff --git a/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java b/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java index 9a9a5591c4..18fb76260b 100644 --- a/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java +++ b/src/main/java/com/simibubi/create/content/trains/schedule/destination/TextScheduleInstruction.java @@ -13,7 +13,6 @@ import net.neoforged.api.distmarker.OnlyIn; public abstract class TextScheduleInstruction extends ScheduleInstruction { - protected String getLabelText() { return textData("Text"); } diff --git a/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java index adf1ffd470..c898048de4 100644 --- a/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java +++ b/src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java @@ -72,6 +72,7 @@ public void read(CompoundTag nbt, HolderLookup.Provider registries, boolean migr port.address = c.getString("Address"); port.offlineBuffer.deserializeNBT(registries, c.getCompound("OfflineBuffer")); port.primed = c.getBoolean("Primed"); + port.usesRegex = c.getBoolean("UsesRegex"); connectedPorts.put(NBTHelper.readBlockPos(c, "Pos"), port); }); } @@ -96,6 +97,7 @@ public void write(CompoundTag nbt, HolderLookup.Provider registries, DimensionPa c.putString("Address", e.getValue().address); c.put("OfflineBuffer", e.getValue().offlineBuffer.serializeNBT(registries)); c.putBoolean("Primed", e.getValue().primed); + c.putBoolean("UsesRegex", e.getValue().usesRegex); c.put("Pos", NbtUtils.writeBlockPos(e.getKey())); return c; })); @@ -166,6 +168,7 @@ public Train getNearestTrain() { // Package Port integration public static class GlobalPackagePort { public String address = ""; + public boolean usesRegex = false; public ItemStackHandler offlineBuffer = new ItemStackHandler(18); public boolean primed = false; } @@ -205,7 +208,7 @@ public void runMailTransfer() { ItemStack stack = postboxInventory.getStackInSlot(slot); if (!PackageItem.isPackage(stack)) continue; - if (PackageItem.matchAddress(stack, port.address)) + if (PackageItem.matchAddress(stack, port.address, port.usesRegex)) continue; ItemStack result = ItemHandlerHelper.insertItemStacked(carriageInventory, stack, false); @@ -230,7 +233,7 @@ public void runMailTransfer() { BlockPos pos = entry.getKey(); PostboxBlockEntity box = null; - if (!PackageItem.matchAddress(stack, port.address)) + if (!PackageItem.matchAddress(stack, port.address, port.usesRegex)) continue; IItemHandler postboxInventory = port.offlineBuffer; diff --git a/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java b/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java index 375f06df8b..d7fcfc63de 100644 --- a/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java @@ -62,7 +62,6 @@ import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.infrastructure.config.AllConfigs; -import dan200.computercraft.api.peripheral.PeripheralCapability; import net.createmod.catnip.data.Iterate; import net.createmod.catnip.nbt.NBTHelper; import net.createmod.catnip.math.VecHelper; @@ -999,6 +998,7 @@ public void attachPackagePort(PackagePortBlockEntity ppbe) { GlobalPackagePort globalPackagePort = new GlobalPackagePort(); globalPackagePort.address = ppbe.addressFilter; + globalPackagePort.usesRegex = ppbe.usingRegex(); station.connectedPorts.put(ppbe.getBlockPos(), globalPackagePort); } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index e8551a3bfb..bb994d4617 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -165,10 +165,11 @@ public class AllIcons implements ScreenElement { I_SEND_ONLY = newRow(), I_SEND_AND_RECEIVE = next(), + I_GLOB_PATTERN = next(), + I_REGEX = next(), I_PARTIAL_REQUESTS = next(), I_FULL_REQUESTS = next(), I_MOVE_GAUGE = next(); - ; public AllIcons(int x, int y) { iconX = x * 16; diff --git a/src/main/java/com/simibubi/create/foundation/utility/CreateLang.java b/src/main/java/com/simibubi/create/foundation/utility/CreateLang.java index 08a47f0bee..2e1c38f06d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/CreateLang.java +++ b/src/main/java/com/simibubi/create/foundation/utility/CreateLang.java @@ -33,6 +33,13 @@ public static List translatedOptions(String prefix, String... keys) { return result; } + public static List translatedOptions(String prefix, List keys) { + List result = new ArrayList<>(keys.size()); + for (String key : keys) + result.add(translate((prefix != null ? prefix + "." : "") + key).component()); + return result; + } + // public static LangBuilder builder() { diff --git a/src/main/java/com/simibubi/create/foundation/utility/LogisticParser.java b/src/main/java/com/simibubi/create/foundation/utility/LogisticParser.java new file mode 100644 index 0000000000..7105d31a23 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/LogisticParser.java @@ -0,0 +1,47 @@ +package com.simibubi.create.foundation.utility; + +import java.util.regex.PatternSyntaxException; + +import com.google.re2j.Pattern; + +import net.createmod.catnip.data.Glob; + +public class LogisticParser { + // Dynamic regex creation: + // - If raw regex is enabled, uses a SAFE RE2/J parser + // - Otherwise, uses the current glob parser + public static Pattern dynamicToRegex(String pattern, String defaultPatternIfError, boolean usingRawRegex) { + return usingRawRegex ? toRegex(pattern, defaultPatternIfError) : globToRegex(pattern, defaultPatternIfError); + // return AllConfigs.server().extras.enableAdvancedRegex.get() + // ? toRegex(pattern, defaultPatternIfError) + // : globToRegex(pattern, defaultPatternIfError); + } + + // Basic regex creation: + // - Uses a SAFE RE2/J parser + public static Pattern toRegex(String pattern, String defaultPatternIfError) { + try { + return Pattern.compile(pattern); + } catch (PatternSyntaxException e) { + return Pattern.compile(defaultPatternIfError); + } + } + + // Glob regex creation: + // - Uses the current glob parser + public static Pattern globToRegex(String pattern, String defaultGlobIfError) { + try { + return Pattern.compile(Glob.toRegexPattern(pattern)); + } catch (PatternSyntaxException e) { + return Pattern.compile(Glob.toRegexPattern(defaultGlobIfError)); + } + } + + public static boolean anyMatches(Pattern pattern, String match) { + return pattern.matcher(match).find(); + } + + public static boolean matchesAll(String pattern, boolean useRegex) { + return pattern.equals(useRegex ? ".*" : "*"); + } +} diff --git a/src/main/java/com/simibubi/create/infrastructure/config/AllConfigs.java b/src/main/java/com/simibubi/create/infrastructure/config/AllConfigs.java index 7ec56c39b6..f968bc1d37 100644 --- a/src/main/java/com/simibubi/create/infrastructure/config/AllConfigs.java +++ b/src/main/java/com/simibubi/create/infrastructure/config/AllConfigs.java @@ -5,6 +5,8 @@ import java.util.Map.Entry; import java.util.function.Supplier; +import com.simibubi.create.Create; + import net.createmod.catnip.config.ConfigBase; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModContainer; diff --git a/src/main/java/com/simibubi/create/infrastructure/config/CExtras.java b/src/main/java/com/simibubi/create/infrastructure/config/CExtras.java new file mode 100644 index 0000000000..c889b6fde1 --- /dev/null +++ b/src/main/java/com/simibubi/create/infrastructure/config/CExtras.java @@ -0,0 +1,17 @@ +package com.simibubi.create.infrastructure.config; + +import net.createmod.catnip.config.ConfigBase; + +public class CExtras extends ConfigBase { + + public final ConfigBool enableAdvancedRegex = b(false, "enableAdvancedRegex", "[requires restart]", Comments.enableAdvancedRegex); + + @Override + public String getName() { + return "extras"; + } + + private static class Comments { + static String enableAdvancedRegex = "Whether to enable the use of regex-based address matching in package logistics and train schedules."; + } +} diff --git a/src/main/java/com/simibubi/create/infrastructure/config/CLogistics.java b/src/main/java/com/simibubi/create/infrastructure/config/CLogistics.java index 726f5c7c1b..cd17577952 100644 --- a/src/main/java/com/simibubi/create/infrastructure/config/CLogistics.java +++ b/src/main/java/com/simibubi/create/infrastructure/config/CLogistics.java @@ -1,6 +1,5 @@ package com.simibubi.create.infrastructure.config; - import net.createmod.catnip.config.ConfigBase; public class CLogistics extends ConfigBase { diff --git a/src/main/java/com/simibubi/create/infrastructure/config/CServer.java b/src/main/java/com/simibubi/create/infrastructure/config/CServer.java index 4ff528019c..8cf9d71788 100644 --- a/src/main/java/com/simibubi/create/infrastructure/config/CServer.java +++ b/src/main/java/com/simibubi/create/infrastructure/config/CServer.java @@ -14,7 +14,8 @@ public class CServer extends ConfigBase { public final CLogistics logistics = nested(0, CLogistics::new, Comments.logistics); public final CSchematics schematics = nested(0, CSchematics::new, Comments.schematics); public final CEquipment equipment = nested(0, CEquipment::new, Comments.equipment); - public final CTrains trains = nested(0, CTrains::new, Comments.trains); + public final CTrains trains = nested(1, CTrains::new, Comments.trains); + public final CExtras extras = nested(0, CExtras::new, Comments.extras); @Override public String getName() { @@ -29,6 +30,7 @@ private static class Comments { static String logistics = "Tweaks for logistical components"; static String equipment = "Equipment and gadgets added by Create"; static String trains = "Create's builtin Railway systems"; + static String extras = "Advanced options for additional customization"; static String infrastructure = "The Backbone of Create"; static String tickrateSyncTimer = "The amount of time a server waits before sending out tickrate synchronization packets."; diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index a32bf6de3a..35779c7eda 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