package net.t7seven7t.craftfx.target;
import com.google.common.collect.ImmutableList;
import net.t7seven7t.craftfx.Registry;
import net.t7seven7t.craftfx.Target;
import net.t7seven7t.craftfx.data.effect.TargetSelectorData;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
*
*/
public class TargetSelectorRegistry implements Registry<TargetSelectorSpec> {
private final List<TargetSelectorSpec> targetSelectorList = new ArrayList<>();
private final TargetSelectorSpec defaultSpec = TargetSelectorSpec.builder().aliases("self")
.build();
public TargetSelectorRegistry() {
initDefaults();
}
@Override
public void register(TargetSelectorSpec spec) {
for (String alias : spec.getAliases()) {
if (getSpecOrEmpty(alias).isPresent()) {
throw new IllegalArgumentException("A TargetSelectorSpec is already registered " +
"with the alias " + alias);
}
}
targetSelectorList.add(spec);
}
@Override
public Optional<TargetSelectorSpec> getSpec(String alias) {
return Optional.of(getSpecOrEmpty(alias).orElse(defaultSpec));
}
private Optional<TargetSelectorSpec> getSpecOrEmpty(String alias) {
alias = alias.toLowerCase();
for (TargetSelectorSpec spec : targetSelectorList) {
if (spec.getAliases().contains(alias)) {
return Optional.of(spec);
}
}
return Optional.empty();
}
private void initDefaults() {
final TargetAdapter toPlayer = c -> c.getOrigin().getPlayer()
.filter(p -> !p.equals(c.getInitiator()))
.map(Target::new)
.map(ImmutableList::of)
.orElse(ImmutableList.of());
final TargetAdapter toEntity = c -> {
final TargetSelectorData data = c.getData(TargetSelectorData.class).get();
Optional<Entity> optEntity = c.getOrigin().getEntity();
if (!optEntity.isPresent() || optEntity.get() == c.getInitiator()) {
return ImmutableList.of();
} else if (data.getEntityType() == null) {
return ImmutableList.of(c.getOrigin());
} else {
return optEntity.filter(e -> e.getType() == data.getEntityType())
.map(Target::new).map(ImmutableList::of).orElse(ImmutableList.of());
}
};
final TargetAdapter toBlock = c -> {
final Optional<Block> optBlock = c.getOrigin().getAsBlock();
if (optBlock.isPresent()) return ImmutableList.of(c.getOrigin());
return ImmutableList.of();
};
register(defaultSpec);
register(TargetSelectorSpec.builder()
.aliases("player")
.adapter(toPlayer)
.build());
register(TargetSelectorSpec.builder()
.aliases("entity")
.adapter(toEntity)
.build());
register(TargetSelectorSpec.builder()
.aliases("block")
.adapter(toBlock)
.build());
register(TargetSelectorSpec.builder()
.aliases("aoe entity")
.adapter(c -> {
// get entities around the origin
final Location origin = c.getOrigin().getAsLocation().orElse(null);
if (origin == null) return ImmutableList.of();
final TargetSelectorData data = c.getData(TargetSelectorData.class).get();
final double radius = data.getAoeRadius();
return origin.getWorld().getNearbyEntities(origin, radius, radius, radius)
.stream()
.sorted(Comparator.comparingDouble(e ->
e.getLocation().distance(origin)))
.map(e -> toEntity.apply(new TargetSelectorContext(new Target(e),
c.getInitiator(), c.getDataHolder())))
.filter(e -> !e.isEmpty())
.limit(data.getLimit())
.map(e -> e.get(0))
.collect(Collectors.toList());
}).build());
register(TargetSelectorSpec.builder()
.aliases("aoe player")
.adapter(c -> {
final Location origin = c.getOrigin().getAsLocation().orElse(null);
if (origin == null) return ImmutableList.of();
final TargetSelectorData data = c.getData(TargetSelectorData.class).get();
final double radius = data.getAoeRadius();
return origin.getWorld().getNearbyEntities(origin, radius, radius, radius)
.stream()
.filter(e -> e instanceof Player)
.sorted(Comparator.comparingDouble(p ->
p.getLocation().distance(origin)))
.map(p -> toPlayer.apply(new TargetSelectorContext(new Target(p),
c.getInitiator(), c.getDataHolder())))
.filter(p -> !p.isEmpty())
.limit(data.getLimit())
.map(l -> l.get(0))
.collect(Collectors.toList());
}).build());
}
}