Skip to content

Commit

Permalink
Routing condition cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Sm0keySa1m0n committed Sep 5, 2023
1 parent ea86662 commit fede8c4
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 295 deletions.
1 change: 1 addition & 0 deletions src/api/java/mods/railcraft/api/carts/NeedsFuel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mods.railcraft.api.carts;

public interface NeedsFuel {

boolean needsFuel();
}
38 changes: 18 additions & 20 deletions src/main/java/mods/railcraft/util/routing/RoutingLogic.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

public record RoutingLogic(Deque<Expression> expressions) {

public static final String REGEX_SYMBOL = "\\?";

public static RoutingLogic parseTable(Deque<String> data) throws RoutingLogicException {
Deque<Expression> stack = new ArrayDeque<>();
var it = data.descendingIterator();
Expand Down Expand Up @@ -70,32 +68,32 @@ public boolean matches(RouterBlockEntity blockEntityRouting, AbstractMinecart ca
private static Expression parseLine(String line, Deque<Expression> stack)
throws RoutingLogicException {
try {
if (line.startsWith("Dest")) {
return new DestCondition(line);
if (line.startsWith(DestCondition.KEYWORD)) {
return DestCondition.parse(line);
}
if (line.startsWith("Color")) {
return new ColorCondition(line);
if (line.startsWith(ColorCondition.KEYWORD)) {
return ColorCondition.parse(line);
}
if (line.startsWith("Owner")) {
return new OwnerCondition(line);
if (line.startsWith(OwnerCondition.KEYWORD)) {
return OwnerCondition.parse(line);
}
if (line.startsWith("Name")) {
return new NameCondition(line);
if (line.startsWith(NameCondition.KEYWORD)) {
return NameCondition.parse(line);
}
if (line.startsWith("Type")) {
return new TypeCondition(line);
if (line.startsWith(TypeCondition.KEYWORD)) {
return TypeCondition.parse(line);
}
if (line.startsWith("NeedsRefuel")) {
return new RefuelCondition(line);
if (line.startsWith(RefuelCondition.KEYWORD)) {
return RefuelCondition.parse(line);
}
if (line.startsWith("Rider")) {
return new RiderCondition(line);
if (line.startsWith(RiderCondition.KEYWORD)) {
return RiderCondition.parse(line);
}
if (line.startsWith("Redstone")) {
return new RedstoneCondition(line);
if (line.startsWith(RedstoneCondition.KEYWORD)) {
return RedstoneCondition.parse(line);
}
if (line.startsWith("Loco")) {
return new LocomotiveCondition(line);
if (line.startsWith(LocomotiveCondition.KEYWORD)) {
return LocomotiveCondition.parse(line);
}
} catch (RoutingLogicException ex) {
throw ex;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package mods.railcraft.util.routing;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.jetbrains.annotations.Nullable;
import mods.railcraft.Translations;

public class RoutingStatementParser {

public static final String REGEX_SYMBOL = "\\?";

public static ParsedStatement parse(String keyword, boolean supportsRegex, String line)
throws RoutingLogicException {
String keywordMatch = keyword + REGEX_SYMBOL + "?=";
if (!line.matches(keywordMatch + ".*")) {
throw new RoutingLogicException(Translations.RoutingTable.UNRECOGNIZED_KEYWORD, line);
}
var isRegex = line.matches(keyword + REGEX_SYMBOL + "=.*");
if (!supportsRegex && isRegex) {
throw new RoutingLogicException(Translations.RoutingTable.ERROR_UNSUPPORTED_REGEX, line);
}
var value = line.replaceFirst(keywordMatch, "");
Pattern pattern = null;
if (isRegex) {
try {
pattern = Pattern.compile(line);
} catch (PatternSyntaxException ex) {
throw new RoutingLogicException(Translations.RoutingTable.ERROR_INVALID_REGEX, line);
}
}
return new ParsedStatement(value, pattern);
}

public record ParsedStatement(String value, @Nullable Pattern pattern) {

public boolean isRegex() {
return this.pattern != null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,28 @@
@FunctionalInterface
public interface Expression {

Expression FALSE = (router, cart) -> false;
Expression TRUE = (router, cart) -> true;
Expression FALSE = (router, minecart) -> false;
Expression TRUE = (router, minecart) -> true;

boolean evaluate(RouterBlockEntity router, AbstractMinecart cart);
boolean evaluate(RouterBlockEntity router, AbstractMinecart minecart);

default Expression negate() {
return (router, cart) -> !this.evaluate(router, cart);
return (router, minecart) -> !this.evaluate(router, minecart);
}

default Expression and(Expression other) {
return (router, cart) -> this.evaluate(router, cart) && other.evaluate(router, cart);
return (router, minecart) -> this.evaluate(router, minecart)
&& other.evaluate(router, minecart);
}

default Expression or(Expression other) {
return (router, cart) -> this.evaluate(router, cart) || other.evaluate(router, cart);
return (router, minecart) -> this.evaluate(router, minecart)
|| other.evaluate(router, minecart);
}

default Expression select(Expression success, Expression fail) {
return (router, cart) -> this.evaluate(router, cart)
? success.evaluate(router, cart)
: fail.evaluate(router, cart);
return (router, minecart) -> this.evaluate(router, minecart)
? success.evaluate(router, minecart)
: fail.evaluate(router, minecart);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,39 @@
import java.util.Locale;
import mods.railcraft.Translations;
import mods.railcraft.api.carts.Paintable;
import mods.railcraft.util.routing.RouterBlockEntity;
import mods.railcraft.util.routing.RoutingLogicException;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import mods.railcraft.util.routing.RoutingStatementParser;
import mods.railcraft.util.routing.expression.Expression;
import net.minecraft.world.item.DyeColor;

public class ColorCondition extends ParsedCondition {
public class ColorCondition {

private final DyeColor primary, secondary;
public static final String KEYWORD = "Color";

public ColorCondition(String line) throws RoutingLogicException {
super("Color", false, line);
var colors = value.toLowerCase(Locale.ROOT).split(",");
if ("Any".equals(colors[0]) || "*".equals(colors[0])) {
primary = null;
} else {
primary = DyeColor.byName(colors[0], null);
if (primary == null) {
throw new RoutingLogicException(Translations.RoutingTable.UNRECOGNIZED_KEYWORD, colors[0]);
}
}
if (colors.length == 1 || colors[1].equals("Any") || colors[1].equals("*")) {
secondary = null;
} else {
secondary = DyeColor.byName(colors[1], null);
if (secondary == null) {
throw new RoutingLogicException(Translations.RoutingTable.UNRECOGNIZED_KEYWORD, colors[1]);
public static Expression parse(String line) throws RoutingLogicException {
var statement = RoutingStatementParser.parse(KEYWORD, false, line);
var colors = statement.value().toLowerCase(Locale.ROOT).split(",");

var primary = parseColor(colors[0]);
var secondary = colors.length < 2 ? null : parseColor(colors[1]);

return (router, minecart) -> {
if (minecart instanceof Paintable paintable) {
return (primary == null || primary.equals(paintable.getPrimaryDyeColor())) &&
(secondary == null || secondary.equals(paintable.getSecondaryDyeColor()));
}
}
return false;
};
}

@Override
public boolean evaluate(RouterBlockEntity routerBlockEntity, AbstractMinecart cart) {
if (cart instanceof Paintable paintedCart) {
return (primary == null || primary.equals(paintedCart.getPrimaryDyeColor())) &&
(secondary == null || secondary.equals(paintedCart.getSecondaryDyeColor()));
private static DyeColor parseColor(String name) throws RoutingLogicException {
if ("Any".equals(name) || "*".equals(name)) {
return null;
}
var color = DyeColor.byName(name, null);
if (color == null) {
throw new RoutingLogicException(Translations.RoutingTable.UNRECOGNIZED_KEYWORD, name);
}
return false;
return color;
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
package mods.railcraft.util.routing.expression.condition;

import java.util.function.Predicate;
import org.apache.commons.lang3.StringUtils;
import mods.railcraft.api.carts.Routable;
import mods.railcraft.util.routing.RouterBlockEntity;
import mods.railcraft.util.routing.RoutingLogicException;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import mods.railcraft.util.routing.RoutingStatementParser;
import mods.railcraft.util.routing.expression.Expression;

public class DestCondition extends ParsedCondition {
public class DestCondition {

public DestCondition(String line) throws RoutingLogicException {
super("Dest", true, line);
}
public static final String KEYWORD = "Dest";

@Override
public boolean evaluate(RouterBlockEntity routerBlockEntity, AbstractMinecart cart) {
if (cart instanceof Routable routableCart) {
String cartDest = routableCart.getDestination();
if (StringUtils.equalsIgnoreCase("null", value)) {
return StringUtils.isBlank(cartDest);
}
if (StringUtils.isBlank(cartDest)) {
return false;
}
if (isRegex) {
return cartDest.matches(value);
public static Expression parse(String line) throws RoutingLogicException {
var statement = RoutingStatementParser.parse(KEYWORD, true, line);
Predicate<String> predicate = statement.isRegex()
? statement.pattern().asMatchPredicate()
: s -> s.startsWith(statement.value());
return (router, minecart) -> {
if (minecart instanceof Routable routable) {
var destination = routable.getDestination();
if (StringUtils.equalsIgnoreCase("null", statement.value())) {
return StringUtils.isBlank(destination);
}
if (StringUtils.isBlank(destination)) {
return false;
}
return predicate.test(destination);
}
return cartDest.startsWith(value);
}
return false;
return false;
};
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
package mods.railcraft.util.routing.expression.condition;

import mods.railcraft.util.routing.RouterBlockEntity;
import java.util.Locale;
import java.util.function.Predicate;
import mods.railcraft.util.routing.RoutingLogicException;
import mods.railcraft.util.routing.RoutingStatementParser;
import mods.railcraft.util.routing.expression.Expression;
import mods.railcraft.world.entity.RailcraftEntityTypes;
import mods.railcraft.world.entity.vehicle.locomotive.Locomotive;
import net.minecraft.world.entity.vehicle.AbstractMinecart;

public class LocomotiveCondition extends ParsedCondition {
public class LocomotiveCondition {

public LocomotiveCondition(String line) throws RoutingLogicException {
super("Loco", false, line);
}
public static final String KEYWORD = "Loco";

@Override
public boolean evaluate(RouterBlockEntity routerBlockEntity, AbstractMinecart cart) {
if (cart instanceof Locomotive loco) {
if (value.equalsIgnoreCase("Electric")) {
return loco.getType() == RailcraftEntityTypes.ELECTRIC_LOCOMOTIVE.get();
}
if (value.equalsIgnoreCase("Steam")) {
return loco.getType() == RailcraftEntityTypes.STEAM_LOCOMOTIVE.get();
}
if (value.equalsIgnoreCase("Creative")) {
return loco.getType() == RailcraftEntityTypes.CREATIVE_LOCOMOTIVE.get();
public static Expression parse(String line) throws RoutingLogicException {
var statement = RoutingStatementParser.parse(KEYWORD, false, line);
Predicate<Locomotive> predicate = switch (statement.value().toLowerCase(Locale.ROOT)) {
case "electric" -> loco -> loco.getType() == RailcraftEntityTypes.ELECTRIC_LOCOMOTIVE.get();
case "steam" -> loco -> loco.getType() == RailcraftEntityTypes.STEAM_LOCOMOTIVE.get();
case "creative" -> loco -> loco.getType() == RailcraftEntityTypes.CREATIVE_LOCOMOTIVE.get();
case "none" -> null;
default -> throw new IllegalArgumentException("Unexpected value: " + statement.value());
};
return (router, minecart) -> {
if (minecart instanceof Locomotive loco && predicate != null) {
return predicate.test(loco);
}
if (value.equalsIgnoreCase("None")) {
return false;
}
}
return value.equalsIgnoreCase("None");
return true;

};
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
package mods.railcraft.util.routing.expression.condition;

import org.apache.commons.lang3.StringUtils;
import mods.railcraft.util.routing.RouterBlockEntity;
import java.util.function.Predicate;
import mods.railcraft.util.routing.RoutingLogicException;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import mods.railcraft.util.routing.RoutingStatementParser;
import mods.railcraft.util.routing.expression.Expression;

public class NameCondition extends ParsedCondition {
public class NameCondition {

public NameCondition(String line) throws RoutingLogicException {
super("Name", true, line);
}
public static final String KEYWORD = "Name";

@Override
public boolean evaluate(RouterBlockEntity routerBlockEntity, AbstractMinecart cart) {
if (!cart.hasCustomName()) {
return StringUtils.equalsIgnoreCase("null", value);
}
String customName = cart.getDisplayName().getString();
if (isRegex) {
return customName.matches(value);
}
return StringUtils.equalsIgnoreCase(customName, value);
public static Expression parse(String line) throws RoutingLogicException {
var statement = RoutingStatementParser.parse(KEYWORD, true, line);
Predicate<String> predicate = statement.isRegex()
? statement.pattern().asMatchPredicate()
: statement.value()::equalsIgnoreCase;
return (router, minecart) -> minecart.hasCustomName()
? predicate.test(minecart.getCustomName().getString())
: statement.value().equalsIgnoreCase("null");
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package mods.railcraft.util.routing.expression.condition;

import org.apache.commons.lang3.StringUtils;
import mods.railcraft.util.routing.RouterBlockEntity;
import mods.railcraft.util.routing.RoutingLogicException;
import mods.railcraft.util.routing.RoutingStatementParser;
import mods.railcraft.util.routing.expression.Expression;
import mods.railcraft.world.entity.vehicle.CartTools;
import net.minecraft.world.entity.vehicle.AbstractMinecart;

public class OwnerCondition extends ParsedCondition {
public class OwnerCondition {

public OwnerCondition(String line) throws RoutingLogicException {
super("Owner", false, line);
}
public static final String KEYWORD = "Owner";

@Override
public boolean evaluate(RouterBlockEntity routerBlockEntity, AbstractMinecart cart) {
var owner = CartTools.getCartOwner(cart);
if (owner == null) {
return false;
}
return StringUtils.equalsIgnoreCase(value, owner.getName());
public static Expression parse(String line) throws RoutingLogicException {
var statement = RoutingStatementParser.parse(KEYWORD, false, line);
return (router, minecart) -> {
var owner = CartTools.getCartOwner(minecart);
return owner != null && statement.value().equalsIgnoreCase(owner.getName());
};
}
}

0 comments on commit fede8c4

Please sign in to comment.