personthecat.catlib.data.BiomePredicate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of catlib-quilt Show documentation
Show all versions of catlib-quilt Show documentation
Utilities for serialization, commands, noise generation, IO, and some new data types.
The newest version!
package personthecat.catlib.data;
import com.mojang.serialization.Codec;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import net.minecraft.class_1959;
import net.minecraft.class_2960;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import personthecat.catlib.data.collections.InfinitySet;
import personthecat.catlib.data.collections.InvertibleSet;
import personthecat.catlib.data.collections.MultiValueHashMap;
import personthecat.catlib.data.collections.MultiValueMap;
import personthecat.catlib.registry.DynamicRegistries;
import personthecat.catlib.mixin.BiomeAccessor;
import personthecat.catlib.serialization.codec.CodecUtils;
import personthecat.catlib.util.McUtils;
import javax.annotation.concurrent.NotThreadSafe;
import java.util.*;
import java.util.function.Predicate;
import static personthecat.catlib.serialization.codec.CodecUtils.codecOf;
import static personthecat.catlib.serialization.codec.CodecUtils.simpleEither;
import static personthecat.catlib.serialization.codec.FieldDescriptor.defaultGet;
import static personthecat.catlib.serialization.codec.FieldDescriptor.defaulted;
@Getter
@Builder
@NotThreadSafe
@FieldNameConstants
@AllArgsConstructor
@RequiredArgsConstructor
public class BiomePredicate implements Predicate {
@With private final boolean blacklist;
// Todo: additional conditions
@NotNull private final List names;
@NotNull private final List mods;
@NotNull private final List types;
@Nullable private Set compiled;
private int registryTracker;
public static final BiomePredicate ALL_BIOMES = builder().build();
private static final Codec OBJECT_CODEC = codecOf(
defaulted(Codec.BOOL, Fields.blacklist, false, BiomePredicate::isBlacklist),
defaultGet(CodecUtils.ID_LIST, Fields.names, Collections::emptyList, BiomePredicate::getNames),
defaultGet(CodecUtils.STRING_LIST, Fields.mods, Collections::emptyList, BiomePredicate::getMods),
defaultGet(CodecUtils.CATEGORY_LIST, Fields.types, Collections::emptyList, BiomePredicate::getTypes),
BiomePredicate::new
);
private static final Codec ID_CODEC =
CodecUtils.ID_LIST.xmap(ids -> builder().names(ids).build(), BiomePredicate::getNames);
public static final Codec CODEC = simpleEither(ID_CODEC, OBJECT_CODEC)
.withEncoder(bp -> bp.isNamesOnly() ? ID_CODEC : OBJECT_CODEC);
@Override
public boolean test(final class_1959 biome) {
return this.getCompiled().contains(biome);
}
@NotNull
@SuppressWarnings("UnusedReturnValue")
public synchronized Set compile() {
final Set all = new HashSet<>();
DynamicRegistries.BIOMES.forEach(all::add);
if (this.isEmpty()) {
return new InfinitySet<>(all);
}
final Set matching = new HashSet<>();
DynamicRegistries.BIOMES.forEach((id, biome) -> {
if (this.matches(biome, id)) {
matching.add(biome);
}
});
this.registryTracker = DynamicRegistries.BIOMES.getId();
return this.compiled = new InvertibleSet<>(matching, this.blacklist).optimize(all);
}
@NotNull
public Set getCompiled() {
if (this.compiled == null || this.registryTracker != DynamicRegistries.BIOMES.getId()) {
return this.compile();
}
return this.compiled;
}
public boolean isEmpty() {
return this.names.isEmpty() && this.types.isEmpty() && this.mods.isEmpty();
}
public boolean matches(final class_1959 biome, final class_2960 id) {
if (this.isEmpty()) return true;
return this.names.contains(id)
|| this.mods.contains(id.method_12836())
|| this.types.contains(((BiomeAccessor) (Object) biome).getBiomeCategory());
}
public boolean matchesName(final class_2960 id) {
return this.names.isEmpty() || this.names.contains(id);
}
public boolean matchesMod(final class_2960 id) {
return this.mods.isEmpty() || this.mods.contains(id.method_12836());
}
public boolean matchesType(final class_1959.class_1961 type) {
return this.types.isEmpty() || this.types.contains(type);
}
public boolean isNamesOnly() {
return !this.blacklist && this.mods.isEmpty() && this.types.isEmpty();
}
public BiomePredicate simplify() {
if (this.equals(ALL_BIOMES)) {
return ALL_BIOMES;
}
final InvertibleSet biomes = this.reconstruct();
final MultiValueMap categories = categorize(biomes);
final List names = new ArrayList<>();
final List types = new ArrayList<>();
for (final Map.Entry> entry : categories.entrySet()) {
final List possible = McUtils.getBiomes(entry.getKey());
if (possible.size() == entry.getValue().size()) {
types.add(entry.getKey());
} else {
for (final class_1959 biome : entry.getValue()) {
names.add(DynamicRegistries.BIOMES.getKey(biome));
}
}
}
return new BiomePredicate(biomes.isBlacklist(), names, Collections.emptyList(), types);
}
private InvertibleSet reconstruct() {
final Set compiled = this.compiled != null ? this.compiled : this.compile();
final Set all = new HashSet<>();
DynamicRegistries.BIOMES.forEach(all::add);
if (compiled.size() > all.size() / 2) {
final Set inverted = new HashSet<>(all);
inverted.removeAll(compiled);
return InvertibleSet.wrap(inverted).blacklist(true);
}
return InvertibleSet.wrap(compiled);
}
private static MultiValueMap categorize(final Collection biomes) {
final MultiValueMap categories = new MultiValueHashMap<>();
for (final class_1959 biome : biomes) {
categories.add(((BiomeAccessor) (Object) biome).getBiomeCategory(), biome);
}
return categories;
}
@Override
public int hashCode() {
return this.getCompiled().hashCode();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o instanceof BiomePredicate) {
return this.getCompiled().equals(((BiomePredicate) o).getCompiled());
}
return false;
}
public static class BiomePredicateBuilder {
@SuppressWarnings("ConstantConditions")
public BiomePredicate build() {
if (this.names == null) this.names = Collections.emptyList();
if (this.mods == null) this.mods = Collections.emptyList();
if (this.types == null) this.types = Collections.emptyList();
return new BiomePredicate(this.blacklist, this.names, this.mods, this.types);
}
}
}