Skip to content

Commit

Permalink
Cleanup filters & implement players, rank & countdown filters (#1005)
Browse files Browse the repository at this point in the history
Signed-off-by: Pablete1234 <[email protected]>
  • Loading branch information
Pablete1234 authored Jul 28, 2022
1 parent c42e86c commit 42c8279
Show file tree
Hide file tree
Showing 144 changed files with 1,795 additions and 1,290 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/tc/oc/pgm/action/ActionMatchModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.match.MatchModule;
import tc.oc.pgm.api.module.exception.ModuleLoadException;
import tc.oc.pgm.filters.dynamic.FilterMatchModule;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

public class ActionMatchModule implements MatchModule {
private final Match match;
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/tc/oc/pgm/action/ActionModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.match.MatchModule;
import tc.oc.pgm.api.module.exception.ModuleLoadException;
import tc.oc.pgm.filters.dynamic.FilterMatchModule;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.util.xml.InvalidXMLException;

public class ActionModule implements MapModule {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/tc/oc/pgm/action/ActionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.features.FeatureDefinitionContext;
import tc.oc.pgm.filters.FilterParser;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.filters.parse.FilterParser;
import tc.oc.pgm.kits.Kit;
import tc.oc.pgm.util.MethodParser;
import tc.oc.pgm.util.MethodParsers;
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/tc/oc/pgm/action/Trigger.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package tc.oc.pgm.action;

import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.Filterable;

public class Trigger<T extends Filterable<?>> {
private final Class<T> scope;
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/tc/oc/pgm/api/Modules.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
import tc.oc.pgm.fallingblocks.FallingBlocksModule;
import tc.oc.pgm.ffa.FreeForAllMatchModule;
import tc.oc.pgm.ffa.FreeForAllModule;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.FilterModule;
import tc.oc.pgm.filters.dynamic.FilterMatchModule;
import tc.oc.pgm.fireworks.FireworkMatchModule;
import tc.oc.pgm.flag.FlagMatchModule;
import tc.oc.pgm.flag.FlagModule;
Expand Down
36 changes: 35 additions & 1 deletion core/src/main/java/tc/oc/pgm/api/feature/FeatureDefinition.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
package tc.oc.pgm.api.feature;

import java.util.stream.Stream;

/**
* Used as a base-class for all templates of features. Kept around during parsing time so that we
* can easily convert a definition into a Feature for match-time, and persist the ID from the XML.
* Also stored in the {@link tc.oc.pgm.features.FeatureDefinitionContext} so that we don't collide
* IDs.
*/
public interface FeatureDefinition {}
public interface FeatureDefinition {

default FeatureDefinition get() {
return this;
}

/** Concrete class of the definition object (rather than a proxy). */
default Class<? extends FeatureDefinition> getDefinitionType() {
return getClass();
}

default boolean isInstanceOf(Class<? extends FeatureDefinition> type) {
return type.isAssignableFrom(getDefinitionType());
}

default Stream<? extends FeatureDefinition> dependencies() {
return Stream.of();
}

default <T extends FeatureDefinition> Stream<? extends T> dependencies(Class<T> type) {
//noinspection unchecked
return (Stream<T>) dependencies().filter(type::isInstance);
}

default <T extends FeatureDefinition> Stream<? extends T> deepDependencies(Class<T> type) {
Stream<? extends T> stream = dependencies(type).flatMap(dep -> dep.deepDependencies(type));
if (isInstanceOf(type)) {
//noinspection unchecked
stream = Stream.concat(Stream.of((T) get()), stream);
}
return stream;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tc.oc.pgm.api.feature;

import javax.annotation.Nullable;

/** A checked exception indicating a problem related to a particular {@link FeatureDefinition} */
public class FeatureDefinitionException extends Exception {

private final FeatureDefinition featureDefinition;

public FeatureDefinitionException(@Nullable String message, FeatureDefinition featureDefinition) {
this(message, null, featureDefinition);
}

public FeatureDefinitionException(
@Nullable String message, @Nullable Throwable cause, FeatureDefinition featureDefinition) {
super(message, cause);
this.featureDefinition = featureDefinition;
}

public FeatureDefinition featureDefinition() {
return featureDefinition;
}
}
94 changes: 60 additions & 34 deletions core/src/main/java/tc/oc/pgm/api/filter/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@

import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.List;
import org.bukkit.event.Event;
import tc.oc.pgm.api.feature.Feature;
import tc.oc.pgm.api.feature.FeatureDefinition;
import tc.oc.pgm.api.feature.FeatureReference;
import tc.oc.pgm.api.filter.query.Query;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.filters.FilterParser;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.parse.FilterParser;

/**
* Something that can answer "yes", "no" or "i don't care" to the imagined question: "Can X
Expand All @@ -26,26 +22,17 @@
*
* @see Query
*/
public interface Filter {
public interface Filter extends FeatureDefinition {

/** {@link Filterable}s ordered from general to specific */
List<Class<? extends Filterable<?>>> SCOPES =
ImmutableList.of(Match.class, Party.class, MatchPlayer.class);
/** ALLOW or DENY the given {@link Query}, or ABSTAIN from responding. */
QueryResponse query(Query query);

/**
* Filters with children are responsible for returning the events of their children.
* Return true if this filter ALLOWs the given {@link Query}, false if this filter DENYes it, or
* throw a {@link UnsupportedOperationException} if this filter cannot respond to the given query.
*
* <p>Empty list tells us that the filter is not dynamic
* <p>{@link #assertRespondsTo(Class)} can be used to ensure that this method will not throw.
*/
default Collection<Class<? extends Event>> getRelevantEvents() {
return ImmutableList.of();
}

/** Least-derived query type that this filter might not abstain from */
Class<? extends Query> getQueryType();

QueryResponse query(Query query);

default boolean response(Query query) {
switch (query(query)) {
case ALLOW:
Expand All @@ -58,6 +45,54 @@ default boolean response(Query query) {
}
}

/**
* Return true only if ALL following conditions are true:
*
* <p>1. This filter always responds to queries of the given type (i.e. never ABSTAINS) 2. This
* filter's response is derived only from properties of the given query type, and not on any
* properties in subtypes of that query. 3. All dependencies of this filter also meet the above
* conditions.
*/
boolean respondsTo(Class<? extends Query> queryType);

/**
* Throw a {@link FilterTypeException} unless this filter, and ALL dependency filters, return true
* from {@link #respondsTo(Class)} for the given query type.
*
* <p>If this filter has dependencies, it should call this method on them directly, so that the
* exception contains the specific filter that failed the test.
*/
default void assertRespondsTo(Class<? extends Query> queryType) throws FilterTypeException {
if (!respondsTo(queryType)) {
throw new FilterTypeException(this, queryType);
}
}

/**
* Does this filter support dynamic notifications?
*
* <p>If this returns true, then any change in the response of this filter to a query that passes
* {@link #assertRespondsTo(Class)} must notify {@link FilterListener}s registered through {@link
* tc.oc.pgm.filters.FilterMatchModule}.
*
* <p>This method should NOT account for the behavior of any {@link #dependencies()}, as that is
* done automatically by the calling code. This method can return true as long as it does NOT
* change its response to any query, without firing a notification, at a time when none of its
* dynamic dependencies change their response.
*/
default boolean isDynamic() {
return !getRelevantEvents().isEmpty();
}

/**
* Filters with children are responsible for returning the events of their children.
*
* <p>Empty list tells us that the filter is not dynamic
*/
default Collection<Class<? extends Event>> getRelevantEvents() {
return ImmutableList.of();
}

enum QueryResponse {
ALLOW,
DENY,
Expand All @@ -71,6 +106,10 @@ public boolean isDenied() {
return this == DENY;
}

public boolean isPresent() {
return this != ABSTAIN;
}

public static QueryResponse any(QueryResponse... responses) {
QueryResponse result = ABSTAIN;
for (QueryResponse response : responses) {
Expand Down Expand Up @@ -110,17 +149,4 @@ public static QueryResponse fromBoolean(boolean allow) {
return allow ? ALLOW : DENY;
}
}

/**
* Return the "scope" of this filter, which is the most general {@link Filterable} type that it
* responds to.
*/
default Class<? extends Filterable<?>> getScope() {
for (Class<? extends Filterable<?>> scope : SCOPES) {
if (this.getQueryType().isAssignableFrom(scope)) return scope;
}

throw new IllegalStateException(
"Filter type " + this.getQueryType().getSimpleName() + " does not have a filterable scope");
}
}
27 changes: 15 additions & 12 deletions core/src/main/java/tc/oc/pgm/api/filter/FilterListener.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package tc.oc.pgm.api.filter;

import javax.annotation.Nullable;
import tc.oc.pgm.api.filter.query.Query;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

/**
* Can be registered to listen for changes in the response to particular queries on particular
* filters. When registered, the listener will be called immediately with null as oldResponse and
* the current value of the query as newResponse. After that, the listener will only be called when
* the response has changed.
* Handler of dynamic {@link Filter} events
*
* @see FilterMatchModule#onChange(Class, Filter, FilterListener)
*/
public interface FilterListener {
void filterQueryChanged(
Filter filter,
Query query,
@Nullable Filter.QueryResponse oldResponse,
Filter.QueryResponse newResponse);
@FunctionalInterface
public interface FilterListener<F extends Filterable<?>> {

/**
* The callback method.
*
* @param filterable the filterable that the filter has a new response for
* @param response the new response, {@code true} if rise and {@code false} if fall
*/
void filterQueryChanged(F filterable, boolean response);
}
23 changes: 23 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/filter/FilterTypeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tc.oc.pgm.api.filter;

import tc.oc.pgm.api.feature.FeatureDefinitionException;
import tc.oc.pgm.api.filter.query.Query;

public class FilterTypeException extends FeatureDefinitionException {

private final Class<? extends Query> queryType;

public FilterTypeException(Filter filter, Class<? extends Query> queryType) {
super(
"Filter type "
+ filter.getDefinitionType().getSimpleName()
+ " cannot respond to queries of type "
+ queryType.getSimpleName(),
filter);
this.queryType = queryType;
}

public Class<? extends Query> queryType() {
return queryType;
}
}
27 changes: 27 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/filter/Filterables.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package tc.oc.pgm.api.filter;

import com.google.common.collect.ImmutableList;
import java.util.List;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.filters.Filterable;

public interface Filterables {
/** {@link Filterable}s ordered from general to specific */
List<Class<? extends Filterable<?>>> SCOPES =
ImmutableList.of(Match.class, Party.class, MatchPlayer.class);

/**
* Return the "scope" of the given filter, which is the most general {@link Filterable} type that
* it responds to.
*/
static Class<? extends Filterable<?>> scope(Filter filter) {
for (Class<? extends Filterable<?>> scope : SCOPES) {
if (filter.respondsTo(scope)) return scope;
}

throw new IllegalStateException(
"Filter type " + filter.getClass().getSimpleName() + " does not have a filterable scope");
}
}
4 changes: 2 additions & 2 deletions core/src/main/java/tc/oc/pgm/api/filter/ReactorFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import org.bukkit.event.Event;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.match.event.MatchLoadEvent;
import tc.oc.pgm.filters.dynamic.FilterMatchModule;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

/**
* Implemented by filters which can act dynamically but needs more than Bukkit {@link Event}s to
Expand Down
18 changes: 17 additions & 1 deletion core/src/main/java/tc/oc/pgm/api/filter/query/MatchQuery.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package tc.oc.pgm.api.filter.query;

import java.util.Optional;
import tc.oc.pgm.api.filter.ReactorFactory;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.api.match.MatchModule;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.Filterable;

public interface MatchQuery extends Query {
Match getMatch();
Expand All @@ -12,4 +16,16 @@ default Filterable<?> extractFilterable() {
if (this instanceof PartyQuery) return ((PartyQuery) this).getParty();
return this.getMatch();
}

default <T extends MatchModule> T moduleRequire(Class<T> cls) {
return getMatch().needModule(cls);
}

default <T extends MatchModule> Optional<T> moduleOptional(Class<T> cls) {
return Optional.ofNullable(getMatch().getModule(cls));
}

default <T extends ReactorFactory.Reactor> T reactor(ReactorFactory<T> factory) {
return getMatch().needModule(FilterMatchModule.class).getReactor(factory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import tc.oc.pgm.api.map.exception.MapException;
import tc.oc.pgm.api.module.ModuleContext;
import tc.oc.pgm.features.FeatureDefinitionContext;
import tc.oc.pgm.filters.FilterParser;
import tc.oc.pgm.filters.parse.FilterParser;
import tc.oc.pgm.kits.KitParser;
import tc.oc.pgm.regions.RegionParser;
import tc.oc.pgm.util.Version;
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/tc/oc/pgm/api/match/Match.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import tc.oc.pgm.api.time.Tick;
import tc.oc.pgm.countdowns.CountdownContext;
import tc.oc.pgm.features.MatchFeatureContext;
import tc.oc.pgm.filters.dynamic.Filterable;
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.util.Audience;

/**
Expand Down
Loading

0 comments on commit 42c8279

Please sign in to comment.