Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize list of material filters #1464

Merged
merged 1 commit into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion core/src/main/java/tc/oc/pgm/broadcast/Broadcast.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
public class Broadcast implements Comparable<Broadcast> {
public enum Type {
TIP(translatable("misc.tip", NamedTextColor.BLUE), Sounds.TIP),

ALERT(translatable("misc.alert", NamedTextColor.YELLOW), Sounds.ALERT);

final Component prefix;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public MaterialFilter(MaterialMatcher pattern) {
this.pattern = pattern;
}

public MaterialMatcher getPattern() {
return pattern;
}

@Override
public Class<? extends MaterialQuery> queryType() {
return MaterialQuery.class;
Expand Down
25 changes: 23 additions & 2 deletions core/src/main/java/tc/oc/pgm/filters/operator/AnyFilter.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package tc.oc.pgm.filters.operator;

import java.util.ArrayList;
import java.util.Collection;
import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.api.filter.query.Query;
import tc.oc.pgm.filters.matcher.block.MaterialFilter;
import tc.oc.pgm.util.material.MaterialMatcher;

public class AnyFilter extends MultiFilterFunction {

Expand All @@ -26,10 +29,28 @@ public QueryResponse query(Query query) {
}

public static Filter of(Filter... filters) {
return MultiFilterFunction.of(AnyFilter::new, filters);
return MultiFilterFunction.of(AnyFilter::mergeMaterials, filters);
}

public static Filter of(Collection<Filter> filters) {
return MultiFilterFunction.of(AnyFilter::new, filters);
return MultiFilterFunction.of(AnyFilter::mergeMaterials, filters);
}

/**
* Optimization when creating any -> materials type of filters. The material filters get unwrapped
* and turned into just one material filter with a multi-material matcher.
*
* @param filters collection of the filters to wrap into an AnyFilter
* @return an equivalent of AnyFilter, but with optimized materials
*/
private static Filter mergeMaterials(Collection<Filter> filters) {
var materials = MaterialMatcher.builder();
var children = new ArrayList<Filter>(filters.size());
for (Filter filter : filters) {
if (filter instanceof MaterialFilter mf) materials.add(mf.getPattern());
else children.add(filter);
}
if (!materials.isEmpty()) children.add(new MaterialFilter(materials.build()));
return MultiFilterFunction.of(AnyFilter::new, children);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package tc.oc.pgm.filters.operator;

import org.jdom2.Element;
import tc.oc.pgm.api.feature.FeatureReference;
import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.api.filter.query.Query;

/**
* Wrapper around a child filter, exists only as a parsing optimization. Single-child "any", "all"
* or "one" filters can often be replaced with their single child, but when the child is a
* reference, they can instead be turned into a wrapped filter. <br>
* For example, {@code <all id="outer"><region id="other"/></all>}. Because the child is a
* reference, if we simplified parsing to returning "other", pgm wouldn't register it under the
* "outer" name (you can't register a reference, otherwise it creates duplicates). For those cases,
* we create a filter wrapper around "other", and return that instead.
*/
public class FilterWrapper extends SingleFilterFunction {

private FilterWrapper(Filter filter) {
super(filter);
}

@Override
public QueryResponse query(Query query) {
return filter.query(query);
}

public static Filter of(Element el, Filter filter) {
if (el.getAttribute("id") == null || !(filter instanceof FeatureReference<?>)) return filter;
return new FilterWrapper(filter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,19 @@ public String toString() {
}

public static Filter of(Function<Collection<Filter>, Filter> builder, Filter... filters) {
switch (filters.length) {
case 0:
return StaticFilter.ABSTAIN;
case 1:
return filters[0];
default:
return builder.apply(Arrays.asList(filters));
}
return switch (filters.length) {
case 0 -> StaticFilter.ABSTAIN;
case 1 -> filters[0];
default -> builder.apply(Arrays.asList(filters));
};
}

public static Filter of(
Function<Collection<Filter>, Filter> builder, Collection<Filter> filters) {
switch (filters.size()) {
case 0:
return StaticFilter.ABSTAIN;
case 1:
return filters.iterator().next();
default:
return builder.apply(filters);
}
return switch (filters.size()) {
case 0 -> StaticFilter.ABSTAIN;
case 1 -> filters.iterator().next();
default -> builder.apply(filters);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,6 @@ public Filter parseDeny(Element el) throws InvalidXMLException {
return new DenyFilter(parseChild(el));
}

// Override with a version that only accepts a single child filter
@MethodParser("not")
public Filter parseNot(Element el) throws InvalidXMLException {
return new InverseFilter(parseChild(el));
}

private static final Pattern INLINE_VARIABLE =
Pattern.compile("(%VAR%)(?:\\[(\\d+)])?\\s*=\\s*(%RANGE%|%NUM%)"
.replace("%VAR%", VariablesModule.Factory.VARIABLE_ID.pattern())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import tc.oc.pgm.filters.modifier.SameTeamQueryModifier;
import tc.oc.pgm.filters.operator.AllFilter;
import tc.oc.pgm.filters.operator.AnyFilter;
import tc.oc.pgm.filters.operator.FilterWrapper;
import tc.oc.pgm.filters.operator.InverseFilter;
import tc.oc.pgm.filters.operator.OneFilter;
import tc.oc.pgm.filters.operator.TeamFilterAdapter;
Expand Down Expand Up @@ -220,22 +221,22 @@ public Filter parseNever(Element el) {

@MethodParser("any")
public Filter parseAny(Element el) throws InvalidXMLException {
return new AnyFilter(parseChildren(el));
return FilterWrapper.of(el, AnyFilter.of(parseChildren(el)));
}

@MethodParser("all")
public Filter parseAll(Element el) throws InvalidXMLException {
return new AllFilter(parseChildren(el));
return FilterWrapper.of(el, AllFilter.of(parseChildren(el)));
}

@MethodParser("one")
public Filter parseOne(Element el) throws InvalidXMLException {
return new OneFilter(parseChildren(el));
return FilterWrapper.of(el, OneFilter.of(parseChildren(el)));
}

@MethodParser("not")
public Filter parseNot(Element el) throws InvalidXMLException {
return new InverseFilter(AnyFilter.of(parseChildren(el)));
return new InverseFilter(parseChild(el));
}

@MethodParser("team")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import tc.oc.pgm.api.map.factory.MapFactory;
import tc.oc.pgm.api.region.Region;
import tc.oc.pgm.filters.matcher.block.MaterialFilter;
import tc.oc.pgm.filters.operator.AnyFilter;
import tc.oc.pgm.filters.operator.FilterNode;
import tc.oc.pgm.filters.operator.InverseFilter;
import tc.oc.pgm.util.MethodParser;
import tc.oc.pgm.util.material.MaterialMatcher;
import tc.oc.pgm.util.xml.InvalidXMLException;
Expand Down Expand Up @@ -112,6 +114,12 @@ public Filter parseFilter(Element el) throws InvalidXMLException {
}
}

// Legacy not allows for multiple children and is an implicit and
@MethodParser("not")
public Filter parseNot(Element el) throws InvalidXMLException {
return new InverseFilter(AnyFilter.of(parseChildren(el)));
}

// Removed in proto 1.4 to avoid conflict with <block> region
@MethodParser("block")
public Filter parseBlock(Element el) throws InvalidXMLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import tc.oc.pgm.util.material.MaterialData;
import tc.oc.pgm.util.material.MaterialMatcher;

@SuppressWarnings("deprecation")
public class BlockStateMaterialMatcher implements MaterialMatcher {
public class BlockStateMaterialMatcher implements MaterialMatcher.Singular {
private final BlockData data;

public BlockStateMaterialMatcher(BlockData data) {
Expand All @@ -21,6 +20,11 @@ public Set<Material> getMaterials() {
return Set.of(data.getMaterial());
}

@Override
public Material getMaterial() {
return data.getMaterial();
}

@Override
public boolean matches(Material material) {
return material == data.getMaterial();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import tc.oc.pgm.util.material.MaterialMatcher;

@SuppressWarnings("deprecation")
public class ExactMaterialMatcher implements MaterialMatcher {
public class ExactMaterialMatcher implements MaterialMatcher.Singular {
private final Material material;
private final byte data;

Expand All @@ -22,6 +22,11 @@ public Set<Material> getMaterials() {
return Set.of(material);
}

@Override
public Material getMaterial() {
return material;
}

@Override
public boolean matches(Material material) {
return material == this.material && this.data == 0;
Expand Down
14 changes: 14 additions & 0 deletions util/src/main/java/tc/oc/pgm/util/material/MaterialMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ static MaterialMatcher.Builder builder() {
return MATERIAL_UTILS.matcherBuilder();
}

interface Singular extends MaterialMatcher {
Material getMaterial();
}

interface Builder {
/**
* Set the builder to only accept materials, error on material:data syntax
Expand Down Expand Up @@ -206,6 +210,16 @@ public Builder addAll(Predicate<Material> materialPredicate) {

@Override
public Builder add(MaterialMatcher matcher) {
// Already part of the matcher in form of material, can ignore
if (matcher instanceof Singular s && materials.contains(s.getMaterial())) return this;
if (matcher instanceof SingularMaterialMatcher
|| matcher instanceof MultipleMaterialMatcher) {
Set<Material> toAdd = matcher.getMaterials();
materials.addAll(toAdd);
// Ignore any matcher already handled by our generic material list
matchers.removeIf(m -> m instanceof Singular s && toAdd.contains(s.getMaterial()));
return this;
}
matchers.add(matcher);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,9 @@ public static MaterialMatcher of(Collection<Material> materials) {
default -> new MultipleMaterialMatcher(materials);
};
}

@Override
public String toString() {
return "MultipleMaterialMatcher{" + "materials=" + materials + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import tc.oc.pgm.util.material.MaterialData;
import tc.oc.pgm.util.material.MaterialMatcher;

public class SingularMaterialMatcher implements MaterialMatcher {
public class SingularMaterialMatcher implements MaterialMatcher.Singular {
private final Material material;

private SingularMaterialMatcher(Material material) {
Expand All @@ -36,6 +36,11 @@ public Set<Material> getMaterials() {
return Set.of(material);
}

@Override
public Material getMaterial() {
return material;
}

@Override
public Set<BlockMaterialData> getPossibleBlocks() {
return MATERIAL_UTILS.getPossibleBlocks(material);
Expand All @@ -44,4 +49,9 @@ public Set<BlockMaterialData> getPossibleBlocks() {
public static MaterialMatcher of(Material material) {
return material == null ? NoMaterialMatcher.INSTANCE : new SingularMaterialMatcher(material);
}

@Override
public String toString() {
return "SingularMaterialMatcher{" + "material=" + material + '}';
}
}
Loading