New Switch Int-State for SurfaceRules
This commit is contained in:
parent
835f4895b3
commit
4c41bb1764
10 changed files with 67 additions and 5 deletions
191
src/main/java/ru/bclib/api/surface/SurfaceRuleBuilder.java
Normal file
191
src/main/java/ru/bclib/api/surface/SurfaceRuleBuilder.java
Normal file
|
@ -0,0 +1,191 @@
|
|||
package ru.bclib.api.surface;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
|
||||
import net.minecraft.world.level.levelgen.placement.CaveSurface;
|
||||
import ru.bclib.api.biomes.BiomeAPI;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SurfaceRuleBuilder {
|
||||
private static final Map<String, SurfaceRuleEntry> RULES_CACHE = Maps.newHashMap();
|
||||
private static final SurfaceRuleBuilder INSTANCE = new SurfaceRuleBuilder();
|
||||
private List<SurfaceRuleEntry> rules = Lists.newArrayList();
|
||||
private SurfaceRuleEntry entryInstance;
|
||||
private ResourceKey<Biome> biomeKey;
|
||||
|
||||
private SurfaceRuleBuilder() {}
|
||||
|
||||
public static SurfaceRuleBuilder start() {
|
||||
INSTANCE.biomeKey = null;
|
||||
INSTANCE.rules.clear();
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts surface to only one biome.
|
||||
* @param biomeKey {@link ResourceKey} for the {@link Biome}.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder biome(ResourceKey<Biome> biomeKey) {
|
||||
this.biomeKey = biomeKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts surface to only one biome.
|
||||
* @param biome {@link Biome}.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder biome(Biome biome) {
|
||||
return biome(BiomeAPI.getBiomeKey(biome));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome surface with specified {@link BlockState}. Example - block of grass in the Overworld biomes
|
||||
* @param state {@link BlockState} for the ground cover.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder surface(BlockState state) {
|
||||
entryInstance = getFromCache("surface_" + state.toString(), () -> {
|
||||
RuleSource rule = SurfaceRules.state(state);
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, rule);
|
||||
return new SurfaceRuleEntry(2, rule);
|
||||
});
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome subsurface with specified {@link BlockState}. Example - dirt in the Overworld biomes.
|
||||
* @param state {@link BlockState} for the subterrain layer.
|
||||
* @param depth block layer depth.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder subsurface(BlockState state, int depth) {
|
||||
entryInstance = getFromCache("subsurface_" + depth + "_" + state.toString(), () -> {
|
||||
RuleSource rule = SurfaceRules.state(state);
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(depth, false, false, CaveSurface.FLOOR), rule);
|
||||
return new SurfaceRuleEntry(3, rule);
|
||||
});
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome filler with specified {@link BlockState}. Example - stone in the Overworld biomes.
|
||||
* @param state {@link BlockState} for filling.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder filler(BlockState state) {
|
||||
entryInstance = getFromCache("fill_" + state.toString(), () -> new SurfaceRuleEntry(3, SurfaceRules.state(state)));
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome ceiling with specified {@link BlockState}. Example - block of sandstone in the Overworld desert in air pockets.
|
||||
* @param state {@link BlockState} for the ground cover.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder ceil(BlockState state) {
|
||||
entryInstance = getFromCache("ceil_" + state.toString(), () -> {
|
||||
RuleSource rule = SurfaceRules.state(state);
|
||||
return new SurfaceRuleEntry(2, SurfaceRules.ifTrue(SurfaceRules.ON_CEILING, rule));
|
||||
});
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set biome ceiling material with specified {@link BlockState} and height. Example - sandstone in the Overworld deserts.
|
||||
* @param state {@link BlockState} for the subterrain layer.
|
||||
* @param height block layer height.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder aboveCeil(BlockState state, int height) {
|
||||
entryInstance = getFromCache("above_ceil_" + height + "_" + state.toString(), () -> {
|
||||
RuleSource rule = SurfaceRules.state(state);
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(height, false, false, CaveSurface.CEILING), rule);
|
||||
return new SurfaceRuleEntry(3, rule);
|
||||
});
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will cover steep areas (with large terrain angle). Example - Overworld mountains.
|
||||
* @param state {@link BlockState} for the steep layer.
|
||||
* @param depth layer depth
|
||||
* @return
|
||||
*/
|
||||
public SurfaceRuleBuilder steep(BlockState state, int depth) {
|
||||
entryInstance = getFromCache("steep_" + depth + "_" + state.toString(), () -> {
|
||||
RuleSource rule = SurfaceRules.state(state);
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(depth, false, false, CaveSurface.FLOOR), rule);
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.steep(), rule);
|
||||
int priority = depth < 1 ? 0 : 1;
|
||||
return new SurfaceRuleEntry(priority, rule);
|
||||
});
|
||||
rules.add(entryInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add custom rule.
|
||||
* @param priority rule priority, lower values = higher priority (rule will be applied before others).
|
||||
* @param rule custom {@link SurfaceRules.RuleSource}.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder rule(int priority, SurfaceRules.RuleSource rule) {
|
||||
rules.add(new SurfaceRuleEntry(priority, rule));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add custom rule.
|
||||
* @param rule custom {@link SurfaceRules.RuleSource}.
|
||||
* @return same {@link SurfaceRuleBuilder} instance.
|
||||
*/
|
||||
public SurfaceRuleBuilder rule(SurfaceRules.RuleSource rule) {
|
||||
return rule(7, rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise rule building process.
|
||||
* @return {@link SurfaceRules.RuleSource}.
|
||||
*/
|
||||
public SurfaceRules.RuleSource build() {
|
||||
Collections.sort(rules);
|
||||
List<SurfaceRules.RuleSource> ruleList = rules.stream().map(entry -> entry.getRule()).toList();
|
||||
SurfaceRules.RuleSource[] ruleArray = ruleList.toArray(new SurfaceRules.RuleSource[ruleList.size()]);
|
||||
SurfaceRules.RuleSource rule = SurfaceRules.sequence(ruleArray);
|
||||
if (biomeKey != null) {
|
||||
rule = SurfaceRules.ifTrue(SurfaceRules.isBiome(biomeKey), rule);
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function, will take entry from cache or create it if necessary.
|
||||
* @param name {@link String} entry internal name.
|
||||
* @param supplier {@link Supplier} for {@link SurfaceRuleEntry}.
|
||||
* @return new or existing {@link SurfaceRuleEntry}.
|
||||
*/
|
||||
private static SurfaceRuleEntry getFromCache(String name, Supplier<SurfaceRuleEntry> supplier) {
|
||||
SurfaceRuleEntry entry = RULES_CACHE.get(name);
|
||||
if (entry == null) {
|
||||
entry = supplier.get();
|
||||
RULES_CACHE.put(name, entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
24
src/main/java/ru/bclib/api/surface/SurfaceRuleEntry.java
Normal file
24
src/main/java/ru/bclib/api/surface/SurfaceRuleEntry.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package ru.bclib.api.surface;
|
||||
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SurfaceRuleEntry<M extends Mob> implements Comparable<SurfaceRuleEntry> {
|
||||
private final SurfaceRules.RuleSource rule;
|
||||
private final byte priority;
|
||||
|
||||
public SurfaceRuleEntry(int priority, SurfaceRules.RuleSource rule) {
|
||||
this.priority = (byte) priority;
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
protected SurfaceRules.RuleSource getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull SurfaceRuleEntry entry) {
|
||||
return Integer.compare(priority, entry.priority);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package ru.bclib.api.surface.rules;
|
||||
|
||||
import ru.bclib.interfaces.NumericProvider;
|
||||
import ru.bclib.mixin.common.SurfaceRulesContextAccessor;
|
||||
import ru.bclib.util.MHelper;
|
||||
|
||||
public record RandomIntProvider(int range) implements NumericProvider {
|
||||
@Override
|
||||
public int getNumber(SurfaceRulesContextAccessor context) {
|
||||
return MHelper.RANDOM.nextInt(range);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package ru.bclib.api.surface.rules;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.Condition;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.ConditionSource;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.Context;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.LazyXZCondition;
|
||||
import ru.bclib.mixin.common.SurfaceRulesContextAccessor;
|
||||
|
||||
public abstract class SurfaceNoiseCondition implements SurfaceRules.ConditionSource{
|
||||
@Override
|
||||
public Codec<? extends ConditionSource> codec() {
|
||||
return SurfaceRules.ConditionSource.CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Condition apply(Context context2) {
|
||||
final SurfaceNoiseCondition self = this;
|
||||
|
||||
class Generator extends LazyXZCondition {
|
||||
Generator() {
|
||||
super(context2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean compute() {
|
||||
final SurfaceRulesContextAccessor context = SurfaceRulesContextAccessor.class.cast(this.context);
|
||||
if (context==null) return false;
|
||||
return self.test(context);
|
||||
}
|
||||
}
|
||||
|
||||
return new Generator();
|
||||
}
|
||||
|
||||
public abstract boolean test(SurfaceRulesContextAccessor context);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package ru.bclib.api.surface.rules;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.Context;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules.SurfaceRule;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import ru.bclib.interfaces.NumericProvider;
|
||||
import ru.bclib.mixin.common.SurfaceRulesContextAccessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record SwitchRuleSource(NumericProvider selector, List<RuleSource> collection) implements RuleSource {
|
||||
@Override
|
||||
public Codec<? extends RuleSource> codec() {
|
||||
return RuleSource.CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceRule apply(Context context) {
|
||||
|
||||
return new SurfaceRule() {
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState tryApply(int x, int y, int z) {
|
||||
final SurfaceRulesContextAccessor ctx = SurfaceRulesContextAccessor.class.cast(context);
|
||||
int nr = Math.max(0, selector.getNumber(ctx)) % collection.size();
|
||||
|
||||
return collection.get(nr).apply(context).tryApply(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue