Merge branch '1.19' into 1.18.2-backported

# Conflicts:
#	src/main/java/org/betterx/bclib/api/v2/levelgen/biomes/BiomeAPI.java
#	src/main/java/org/betterx/bclib/api/v2/levelgen/structures/TemplatePiece.java
#	src/main/java/org/betterx/bclib/api/v3/levelgen/features/features/TemplateFeature.java
#	src/main/java/org/betterx/bclib/commands/DumpDatapack.java
#	src/main/java/org/betterx/bclib/util/MHelper.java
#	src/main/java/org/betterx/bclib/util/WeightedList.java
#	src/main/java/org/betterx/worlds/together/levelgen/WorldGenUtil.java
#	src/main/java/org/betterx/worlds/together/mixin/common/WorldGenPropertiesMixin.java
#	src/main/java/org/betterx/worlds/together/tag/v3/TagRegistry.java
#	src/main/java/org/betterx/worlds/together/worldPreset/client/WorldPresetsClient.java
#	src/main/resources/bclib.accesswidener
This commit is contained in:
Frank 2022-07-08 11:23:06 +02:00
commit cee6f167c7
81 changed files with 3162 additions and 799 deletions

View file

@ -8,7 +8,7 @@ minecraft_version=1.18.2
loader_version=0.14.8
fabric_version=0.57.0+1.19
# Mod Properties
mod_version=2.0.8
mod_version=2.0.11
maven_group=org.betterx.bclib
archives_base_name=bclib
# Dependencies

View file

@ -8,6 +8,7 @@ import org.betterx.bclib.api.v2.generator.GeneratorOptions;
import org.betterx.bclib.api.v2.levelgen.LevelGenEvents;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeBuilder;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.api.v2.levelgen.structures.TemplatePiece;
import org.betterx.bclib.api.v2.levelgen.surface.rules.Conditions;
@ -19,9 +20,9 @@ import org.betterx.bclib.recipes.AnvilRecipe;
import org.betterx.bclib.recipes.CraftingRecipes;
import org.betterx.bclib.registry.BaseBlockEntities;
import org.betterx.bclib.registry.BaseRegistry;
import org.betterx.bclib.util.Logger;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.tag.v3.TagManager;
import org.betterx.worlds.together.util.Logger;
import org.betterx.worlds.together.world.WorldConfig;
import net.minecraft.resources.ResourceLocation;
@ -38,11 +39,15 @@ public class BCLib implements ModInitializer {
public static final String MOD_ID = "bclib";
public static final Logger LOGGER = new Logger(MOD_ID);
public static final boolean RUNS_NULLSCAPE = FabricLoader.getInstance()
.getModContainer("nullscape")
.isPresent();
@Override
public void onInitialize() {
LevelGenEvents.register();
WorldsTogether.onInitialize();
BlockPredicates.ensureStaticInitialization();
BCLBiomeRegistry.ensureStaticallyLoaded();
BaseRegistry.register();
GeneratorOptions.init();
BaseBlockEntities.register();
@ -70,6 +75,8 @@ public class BCLib implements ModInitializer {
PlacementModifiers.ensureStaticInitialization();
Configs.save();
WorldsTogether.FORCE_SERVER_TO_BETTERX_PRESET = Configs.SERVER_CONFIG.forceBetterXPreset();
if (false && isDevEnvironment()) {
BCLBiome theYellow = BCLBiomeBuilder
.start(makeID("the_yellow"))

View file

@ -7,7 +7,7 @@ import org.betterx.bclib.client.gui.screens.LevelFixErrorScreen;
import org.betterx.bclib.client.gui.screens.LevelFixErrorScreen.Listener;
import org.betterx.bclib.client.gui.screens.ProgressScreen;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.util.Logger;
import org.betterx.worlds.together.util.Logger;
import org.betterx.worlds.together.world.WorldConfig;
import net.minecraft.Util;

View file

@ -1,7 +1,9 @@
package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry;
import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
import org.betterx.worlds.together.world.BiomeSourceWithSeed;
import net.minecraft.core.Holder;
@ -9,6 +11,7 @@ import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import com.google.common.collect.Sets;
@ -16,7 +19,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Set;
public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource<BCLBiomeSource> {
public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceWithSeed, MergeableBiomeSource<BCLBiomeSource>, BiomeSourceWithNoiseRelatedSettings, BiomeSourceFromRegistry {
protected final Registry<Biome> biomeRegistry;
protected long currentSeed;
protected int maxHeight;
@ -110,4 +113,12 @@ public abstract class BCLBiomeSource extends BiomeSource implements BiomeSourceW
final Set<Holder<Biome>> datapackBiomes = inputBiomeSource.possibleBiomes();
return this.createCopyForDatapack(datapackBiomes);
}
public void onLoadGeneratorSettings(NoiseGeneratorSettings generator) {
this.setMaxHeight(generator.noiseSettings().height());
}
public Registry<Biome> getBiomeRegistry() {
return biomeRegistry;
}
}

View file

@ -6,9 +6,11 @@ import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider;
import org.betterx.bclib.mixin.common.ChunkGeneratorAccessor;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.biomesource.MergeableBiomeSource;
import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
import org.betterx.worlds.together.chunkgenerator.EnforceableChunkGenerator;
import org.betterx.worlds.together.chunkgenerator.InjectableSurfaceRules;
import org.betterx.worlds.together.chunkgenerator.RestorableBiomeSource;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@ -71,8 +73,8 @@ public class BCLChunkGenerator extends NoiseBasedChunkGenerator implements Resto
) {
super(registry, registry2, biomeSource, holder);
initialBiomeSource = biomeSource;
if (biomeSource instanceof BCLBiomeSource bcl) {
bcl.setMaxHeight(holder.value().noiseSettings().height());
if (biomeSource instanceof BiomeSourceWithNoiseRelatedSettings bcl) {
bcl.onLoadGeneratorSettings(holder.value());
}
if (WorldsTogether.RUNS_TERRABLENDER) {
@ -109,6 +111,8 @@ public class BCLChunkGenerator extends NoiseBasedChunkGenerator implements Resto
if (this instanceof ChunkGeneratorAccessor acc) {
if (initialBiomeSource instanceof MergeableBiomeSource bs) {
acc.bcl_setBiomeSource(bs.mergeWithBiomeSource(getBiomeSource()));
} else if (initialBiomeSource instanceof ReloadableBiomeSource bs) {
bs.reloadBiomes();
}
rebuildFeaturesPerStep(getBiomeSource());

View file

@ -3,11 +3,12 @@ package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.generator.config.BCLEndBiomeSourceConfig;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.config.ConfigKeeper.StringArrayEntry;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.interfaces.BiomeMap;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@ -26,13 +27,14 @@ import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.levelgen.DensityFunction;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import org.jetbrains.annotations.NotNull;
public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWithConfig<BCLibEndBiomeSource, BCLEndBiomeSourceConfig> {
public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWithConfig<BCLibEndBiomeSource, BCLEndBiomeSourceConfig>, ReloadableBiomeSource {
public static Codec<BCLibEndBiomeSource> CODEC
= RecordCodecBuilder.create((instance) -> instance.group(
RegistryOps
@ -54,15 +56,18 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
instance.stable(BCLibEndBiomeSource::new)
)
);
private final Holder<Biome> centerBiome;
private final Holder<Biome> barrens;
private final Point pos;
private final BiFunction<Point, Integer, Boolean> endLandFunction;
private BiomeMap mapLand;
private BiomeMap mapVoid;
private BiomeMap mapCenter;
private BiomeMap mapBarrens;
private final BiomePicker endLandBiomePicker;
private final BiomePicker endVoidBiomePicker;
private BiomePicker endLandBiomePicker;
private BiomePicker endVoidBiomePicker;
private BiomePicker endCenterBiomePicker;
private BiomePicker endBarrensBiomePicker;
private List<BiomeDecider> deciders;
private BCLEndBiomeSourceConfig config;
@ -92,77 +97,7 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
) {
super(biomeRegistry, list, seed);
this.config = config;
endLandBiomePicker = new BiomePicker(biomeRegistry);
endVoidBiomePicker = new BiomePicker(biomeRegistry);
List<String> includeVoid = Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_void_biomes",
StringArrayEntry.class
).getValue();
List<String> includeLand = Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_land_biomes",
StringArrayEntry.class
).getValue();
this.possibleBiomes().forEach(biome -> {
ResourceKey<Biome> key = biome.unwrapKey().orElseThrow();
ResourceLocation biomeID = key.location();
if (!BiomeAPI.hasBiome(biomeID)) {
BCLBiome bclBiome = new BCLBiome(biomeID, biome.value());
if (includeVoid.contains(biomeID.toString())) {
endVoidBiomePicker.addBiome(bclBiome);
} else {
endLandBiomePicker.addBiome(bclBiome);
}
} else {
BCLBiome bclBiome = BiomeAPI.getBiome(biomeID);
if (bclBiome != BiomeAPI.EMPTY_BIOME) {
if (bclBiome.getParentBiome() == null) {
if (config.withVoidBiomes) {
if (BiomeAPI.wasRegisteredAsEndVoidBiome(biomeID)
|| TheEndBiomesHelper.isIntendedForEndBarrens(key)
|| includeVoid.contains(biomeID.toString())
) {
endVoidBiomePicker.addBiome(bclBiome);
} else if (BiomeAPI.wasRegisteredAsEndLandBiome(biomeID)
|| TheEndBiomesHelper.isIntendedForEndLand(key)
|| includeLand.contains(biomeID.toString())
) {
endLandBiomePicker.addBiome(bclBiome);
}
} else {
if (BiomeAPI.wasRegisteredAsEndLandBiome(biomeID)
|| TheEndBiomesHelper.isIntendedForEndLand(key)
|| includeLand.contains(biomeID.toString())
) {
endLandBiomePicker.addBiome(bclBiome);
endVoidBiomePicker.addBiome(bclBiome);
}
if (!biomeID.equals(Biomes.SMALL_END_ISLANDS.location()) && !biomeID.equals(Biomes.THE_END.location())
&& (BiomeAPI.wasRegisteredAsEndVoidBiome(biomeID) || includeVoid.contains(biomeID.toString()))
) {
endVoidBiomePicker.addBiome(bclBiome);
}
}
}
}
}
});
endLandBiomePicker.rebuild();
endVoidBiomePicker.rebuild();
this.centerBiome = biomeRegistry.getOrCreateHolderOrThrow(Biomes.THE_END);
this.barrens = biomeRegistry.getOrCreateHolderOrThrow(Biomes.END_BARRENS);
rebuildBiomePickers();
this.endLandFunction = GeneratorOptions.getEndLandFunction();
this.pos = new Point();
@ -172,11 +107,137 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
}
}
@NotNull
private void rebuildBiomePickers() {
var includeMap = Configs.BIOMES_CONFIG.getBiomeIncludeMap();
var excludeList = Configs.BIOMES_CONFIG.getExcludeMatching(BiomeAPI.BiomeType.END);
this.deciders = BiomeDecider.DECIDERS.stream()
.filter(d -> d.canProvideFor(this))
.map(d -> d.createInstance(this))
.toList();
this.endLandBiomePicker = new BiomePicker(biomeRegistry);
this.endVoidBiomePicker = new BiomePicker(biomeRegistry);
this.endCenterBiomePicker = new BiomePicker(biomeRegistry);
this.endBarrensBiomePicker = new BiomePicker(biomeRegistry);
Map<BiomeAPI.BiomeType, BiomePicker> pickerMap = new HashMap<>();
pickerMap.put(BiomeAPI.BiomeType.END_LAND, endLandBiomePicker);
pickerMap.put(BiomeAPI.BiomeType.END_VOID, endVoidBiomePicker);
pickerMap.put(BiomeAPI.BiomeType.END_CENTER, endCenterBiomePicker);
pickerMap.put(BiomeAPI.BiomeType.END_BARRENS, endBarrensBiomePicker);
this.possibleBiomes().forEach(biome -> {
ResourceKey<Biome> key = biome.unwrapKey().orElseThrow();
ResourceLocation biomeID = key.location();
String biomeStr = biomeID.toString();
//exclude everything that was listed
if (excludeList != null && excludeList.contains(biomeStr)) return;
if (!biome.isBound()) {
BCLib.LOGGER.warning("Biome " + biomeStr + " is requested but not yet bound.");
return;
}
final BCLBiome bclBiome;
if (!BiomeAPI.hasBiome(biomeID)) {
bclBiome = new BCLBiome(biomeID, biome.value());
} else {
bclBiome = BiomeAPI.getBiome(biomeID);
}
if (bclBiome != null || bclBiome != BCLBiomeRegistry.EMPTY_BIOME) {
if (bclBiome.getParentBiome() == null) {
//ignore small islands when void biomes are disabled
if (!config.withVoidBiomes) {
if (biomeID.equals(Biomes.SMALL_END_ISLANDS.location())) {
return;
}
}
//force include biomes
boolean didForceAdd = false;
for (var entry : pickerMap.entrySet()) {
var includeList = includeMap == null ? null : includeMap.get(entry.getKey());
if (includeList != null && includeList.contains(biomeStr)) {
entry.getValue().addBiome(bclBiome);
didForceAdd = true;
}
}
if (!didForceAdd) {
if (biomeID.equals(BCLBiomeRegistry.EMPTY_BIOME.getID())
|| bclBiome.getIntendedType().is(BiomeAPI.BiomeType.END_IGNORE)) {
//we should not add this biome anywhere, so just ignore it
} else {
didForceAdd = false;
for (BiomeDecider decider : deciders) {
if (decider.addToPicker(bclBiome)) {
didForceAdd = true;
break;
}
}
if (!didForceAdd) {
if (bclBiome.getIntendedType().is(BiomeAPI.BiomeType.END_CENTER)
|| TheEndBiomesHelper.canGenerateAsMainIslandBiome(key)) {
endCenterBiomePicker.addBiome(bclBiome);
} else if (bclBiome.getIntendedType().is(BiomeAPI.BiomeType.END_LAND)
|| TheEndBiomesHelper.canGenerateAsHighlandsBiome(key)) {
if (!config.withVoidBiomes) endVoidBiomePicker.addBiome(bclBiome);
endLandBiomePicker.addBiome(bclBiome);
} else if (bclBiome.getIntendedType().is(BiomeAPI.BiomeType.END_BARRENS)
|| TheEndBiomesHelper.canGenerateAsEndBarrens(key)) {
endBarrensBiomePicker.addBiome(bclBiome);
} else if (bclBiome.getIntendedType().is(BiomeAPI.BiomeType.END_VOID)
|| TheEndBiomesHelper.canGenerateAsSmallIslandsBiome(key)) {
endVoidBiomePicker.addBiome(bclBiome);
} else {
BCLib.LOGGER.info("Found End Biome " + biomeStr + " that was not registers with fabric or bclib. Assuming end-land Biome...");
endLandBiomePicker.addBiome(bclBiome);
}
}
}
}
}
}
});
endLandBiomePicker.rebuild();
endVoidBiomePicker.rebuild();
endBarrensBiomePicker.rebuild();
endCenterBiomePicker.rebuild();
for (BiomeDecider decider : deciders) {
decider.rebuild();
}
if (endVoidBiomePicker.isEmpty()) {
BCLib.LOGGER.info("No Void Biomes found. Disabling by using barrens");
endVoidBiomePicker = endBarrensBiomePicker;
}
if (endBarrensBiomePicker.isEmpty()) {
BCLib.LOGGER.info("No Barrens Biomes found. Disabling by using land Biomes");
endBarrensBiomePicker = endLandBiomePicker;
endVoidBiomePicker = endLandBiomePicker;
}
if (endCenterBiomePicker.isEmpty()) {
BCLib.LOGGER.warning("No Center Island Biomes found. Forcing use of vanilla center.");
endCenterBiomePicker.addBiome(BiomeAPI.THE_END);
endCenterBiomePicker.rebuild();
if (endCenterBiomePicker.isEmpty()) {
BCLib.LOGGER.error("Unable to force vanilla central Island. Falling back to land Biomes...");
endCenterBiomePicker = endLandBiomePicker;
}
}
}
protected BCLBiomeSource cloneForDatapack(Set<Holder<Biome>> datapackBiomes) {
datapackBiomes.addAll(getBclBiomes(this.biomeRegistry));
return new BCLibEndBiomeSource(
this.biomeRegistry,
datapackBiomes.stream().toList(),
datapackBiomes.stream()
.filter(b -> b.unwrapKey().orElse(null) != BCLBiomeRegistry.EMPTY_BIOME.getBiomeKey())
.toList(),
this.currentSeed,
this.config,
true
@ -184,51 +245,41 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
}
private static List<Holder<Biome>> getBclBiomes(Registry<Biome> biomeRegistry) {
List<String> include = Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_land_biomes",
StringArrayEntry.class
).getValue();
include.addAll(Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_void_biomes",
StringArrayEntry.class
).getValue());
return getBiomes(
biomeRegistry,
new ArrayList<>(0),
include,
Configs.BIOMES_CONFIG.getExcludeMatching(BiomeAPI.BiomeType.END),
Configs.BIOMES_CONFIG.getIncludeMatching(BiomeAPI.BiomeType.END),
BCLibEndBiomeSource::isValidNonVanillaEndBiome
);
}
private static List<Holder<Biome>> getBiomes(Registry<Biome> biomeRegistry) {
List<String> include = Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_land_biomes",
StringArrayEntry.class
).getValue();
include.addAll(Configs.BIOMES_CONFIG.getEntry(
"force_include",
"end_void_biomes",
StringArrayEntry.class
).getValue());
return getBiomes(biomeRegistry, new ArrayList<>(0), include, BCLibEndBiomeSource::isValidEndBiome);
return getBiomes(
biomeRegistry,
Configs.BIOMES_CONFIG.getExcludeMatching(BiomeAPI.BiomeType.END),
Configs.BIOMES_CONFIG.getIncludeMatching(BiomeAPI.BiomeType.END),
BCLibEndBiomeSource::isValidEndBiome
);
}
private static boolean isValidEndBiome(Holder<Biome> biome, ResourceLocation location) {
if (BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.END_IGNORE)) return false;
return biome.is(BiomeTags.IS_END) ||
BiomeAPI.wasRegisteredAsEndBiome(location) ||
TheEndBiomesHelper.isIntendedForAny(biome.unwrapKey().orElse(null));
TheEndBiomesHelper.canGenerateInEnd(biome.unwrapKey().orElse(null));
}
private static boolean isValidNonVanillaEndBiome(Holder<Biome> biome, ResourceLocation location) {
if (BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.END_IGNORE)) return false;
return biome.is(BiomeTags.IS_END) ||
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_LAND) ||
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_VOID) ||
TheEndBiomesHelper.isIntendedForAny(biome.unwrapKey().orElse(null));
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_CENTER) ||
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_BARRENS) ||
TheEndBiomesHelper.canGenerateInEnd(biome.unwrapKey().orElse(null));
}
public static void register() {
@ -237,17 +288,36 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
@Override
protected void onInitMap(long seed) {
this.mapLand = config.mapVersion.mapBuilder.apply(
for (BiomeDecider decider : deciders) {
decider.createMap((picker, size) -> config.mapVersion.mapBuilder.create(
seed,
size <= 0 ? config.landBiomesSize : size,
picker
));
}
this.mapLand = config.mapVersion.mapBuilder.create(
seed,
GeneratorOptions.getBiomeSizeEndLand(),
config.landBiomesSize,
endLandBiomePicker
);
this.mapVoid = config.mapVersion.mapBuilder.apply(
this.mapVoid = config.mapVersion.mapBuilder.create(
seed,
GeneratorOptions.getBiomeSizeEndVoid(),
config.voidBiomesSize,
endVoidBiomePicker
);
this.mapCenter = config.mapVersion.mapBuilder.create(
seed,
config.centerBiomesSize,
endCenterBiomePicker
);
this.mapBarrens = config.mapVersion.mapBuilder.create(
seed,
config.barrensBiomesSize,
endBarrensBiomePicker
);
}
@Override
@ -257,7 +327,7 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
@Override
public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.@NotNull Sampler sampler) {
if (mapLand == null || mapVoid == null)
if (mapLand == null || mapVoid == null || mapCenter == null || mapBarrens == null)
return this.possibleBiomes().stream().findFirst().orElseThrow();
int posX = QuartPos.toBlock(biomeX);
@ -268,39 +338,80 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
? ((long) config.innerVoidRadiusSquared + 1)
: (long) posX * (long) posX + (long) posZ * (long) posZ;
if ((biomeX & 63) == 0 && (biomeZ & 63) == 0) {
if ((biomeX & 63) == 0 || (biomeZ & 63) == 0) {
mapLand.clearCache();
mapVoid.clearCache();
mapCenter.clearCache();
mapVoid.clearCache();
for (BiomeDecider decider : deciders) {
decider.clearMapCache();
}
}
if (config.generatorVersion == BCLEndBiomeSourceConfig.EndBiomeGeneratorType.VANILLA || endLandFunction == null) {
if (dist <= (long) config.innerVoidRadiusSquared) {
return this.centerBiome;
}
BiomeAPI.BiomeType suggestedType;
if (config.generatorVersion == BCLEndBiomeSourceConfig.EndBiomeGeneratorType.VANILLA) {
int x = (SectionPos.blockToSectionCoord(posX) * 2 + 1) * 8;
int z = (SectionPos.blockToSectionCoord(posZ) * 2 + 1) * 8;
double d = sampler.erosion().compute(new DensityFunction.SinglePointContext(x, posY, z));
if (d > 0.25) {
return mapLand.getBiome(posX, biomeY << 2, posZ).biome;
} else if (d >= -0.0625) {
return mapLand.getBiome(posX, biomeY << 2, posZ).biome;
if (dist <= (long) config.innerVoidRadiusSquared) {
suggestedType = BiomeAPI.BiomeType.END_CENTER;
} else {
return d < -0.21875
? mapVoid.getBiome(posX, biomeY << 2, posZ).biome
: config.withVoidBiomes ? this.barrens : mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
if (d > 0.25) {
suggestedType = BiomeAPI.BiomeType.END_LAND; //highlands
} else if (d >= -0.0625) {
suggestedType = BiomeAPI.BiomeType.END_LAND; //midlands
} else {
suggestedType = d < -0.21875
? BiomeAPI.BiomeType.END_VOID //small islands
: (config.withVoidBiomes
? BiomeAPI.BiomeType.END_BARRENS
: BiomeAPI.BiomeType.END_LAND); //barrens
}
}
final BiomeAPI.BiomeType originalType = suggestedType;
for (BiomeDecider decider : deciders) {
suggestedType = decider
.suggestType(
originalType,
suggestedType,
d,
maxHeight,
posX,
posY,
posZ,
biomeX,
biomeY,
biomeZ
);
}
} else {
pos.setLocation(biomeX, biomeZ);
if (endLandFunction.apply(pos, maxHeight)) {
return dist <= (long) config.innerVoidRadiusSquared
? centerBiome : mapLand.getBiome(posX, biomeY << 2, posZ).biome;
} else {
return dist <= (long) config.innerVoidRadiusSquared
? barrens
: mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
final BiomeAPI.BiomeType originalType = (dist <= (long) config.innerVoidRadiusSquared
? BiomeAPI.BiomeType.END_CENTER
: BiomeAPI.BiomeType.END_LAND);
suggestedType = originalType;
for (BiomeDecider decider : deciders) {
suggestedType = decider
.suggestType(originalType, suggestedType, maxHeight, posX, posY, posZ, biomeX, biomeY, biomeZ);
}
}
BiomePicker.ActualBiome result;
for (BiomeDecider decider : deciders) {
if (decider.canProvideBiome(suggestedType)) {
result = decider.provideBiome(suggestedType, posX, posY, posZ);
if (result != null) return result.biome;
}
}
if (suggestedType.is(BiomeAPI.BiomeType.END_CENTER)) return mapCenter.getBiome(posX, posY, posZ).biome;
if (suggestedType.is(BiomeAPI.BiomeType.END_VOID)) return mapVoid.getBiome(posX, posY, posZ).biome;
if (suggestedType.is(BiomeAPI.BiomeType.END_BARRENS)) return mapBarrens.getBiome(posX, posY, posZ).biome;
return mapLand.getBiome(posX, posY, posZ).biome;
}
@ -324,4 +435,10 @@ public class BCLibEndBiomeSource extends BCLBiomeSource implements BiomeSourceWi
this.config = newConfig;
this.initMap(currentSeed);
}
@Override
public void reloadBiomes() {
rebuildBiomePickers();
this.initMap(currentSeed);
}
}

View file

@ -2,14 +2,15 @@ package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.generator.config.BCLNetherBiomeSourceConfig;
import org.betterx.bclib.api.v2.generator.config.MapBuilderFunction;
import org.betterx.bclib.api.v2.generator.map.MapStack;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.config.ConfigKeeper.StringArrayEntry;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.interfaces.BiomeMap;
import org.betterx.bclib.util.TriFunction;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@ -27,7 +28,7 @@ import net.fabricmc.fabric.api.biome.v1.NetherBiomes;
import java.util.List;
import java.util.Set;
public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourceWithConfig<BCLibNetherBiomeSource, BCLNetherBiomeSourceConfig> {
public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourceWithConfig<BCLibNetherBiomeSource, BCLNetherBiomeSourceConfig>, ReloadableBiomeSource {
public static final Codec<BCLibNetherBiomeSource> CODEC = RecordCodecBuilder
.create(instance -> instance
.group(
@ -50,7 +51,7 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
.apply(instance, instance.stable(BCLibNetherBiomeSource::new))
);
private BiomeMap biomeMap;
private final BiomePicker biomePicker;
private BiomePicker biomePicker;
private BCLNetherBiomeSourceConfig config;
public BCLibNetherBiomeSource(Registry<Biome> biomeRegistry, BCLNetherBiomeSourceConfig config) {
@ -79,18 +80,29 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
) {
super(biomeRegistry, list, seed);
this.config = config;
rebuildBiomePicker();
if (initMaps) {
initMap(seed);
}
}
private void rebuildBiomePicker() {
biomePicker = new BiomePicker(biomeRegistry);
this.possibleBiomes().forEach(biome -> {
ResourceLocation key = biome.unwrapKey().orElseThrow().location();
ResourceLocation biomeID = biome.unwrapKey().orElseThrow().location();
if (!biome.isBound()) {
BCLib.LOGGER.warning("Biome " + biomeID.toString() + " is requested but not yet bound.");
return;
}
if (!BiomeAPI.hasBiome(biomeID)) {
if (!BiomeAPI.hasBiome(key)) {
BCLBiome bclBiome = new BCLBiome(key, biome.value());
BCLBiome bclBiome = new BCLBiome(biomeID, biome.value());
biomePicker.addBiome(bclBiome);
} else {
BCLBiome bclBiome = BiomeAPI.getBiome(key);
BCLBiome bclBiome = BiomeAPI.getBiome(biomeID);
if (bclBiome != BiomeAPI.EMPTY_BIOME) {
if (bclBiome != BCLBiomeRegistry.EMPTY_BIOME) {
if (bclBiome.getParentBiome() == null) {
biomePicker.addBiome(bclBiome);
}
@ -99,9 +111,6 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
});
biomePicker.rebuild();
if (initMaps) {
initMap(seed);
}
}
protected BCLBiomeSource cloneForDatapack(Set<Holder<Biome>> datapackBiomes) {
@ -116,20 +125,16 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
}
private static List<Holder<Biome>> getBclBiomes(Registry<Biome> biomeRegistry) {
List<String> include = Configs.BIOMES_CONFIG.getEntry("force_include", "nether_biomes", StringArrayEntry.class)
.getValue();
List<String> exclude = Configs.BIOMES_CONFIG.getEntry("force_exclude", "nether_biomes", StringArrayEntry.class)
.getValue();
List<String> include = Configs.BIOMES_CONFIG.getIncludeMatching(BiomeAPI.BiomeType.NETHER);
List<String> exclude = Configs.BIOMES_CONFIG.getExcludeMatching(BiomeAPI.BiomeType.NETHER);
return getBiomes(biomeRegistry, exclude, include, BCLibNetherBiomeSource::isValidNonVanillaNetherBiome);
}
private static List<Holder<Biome>> getBiomes(Registry<Biome> biomeRegistry) {
List<String> include = Configs.BIOMES_CONFIG.getEntry("force_include", "nether_biomes", StringArrayEntry.class)
.getValue();
List<String> exclude = Configs.BIOMES_CONFIG.getEntry("force_exclude", "nether_biomes", StringArrayEntry.class)
.getValue();
List<String> include = Configs.BIOMES_CONFIG.getIncludeMatching(BiomeAPI.BiomeType.NETHER);
List<String> exclude = Configs.BIOMES_CONFIG.getExcludeMatching(BiomeAPI.BiomeType.NETHER);
return getBiomes(biomeRegistry, exclude, include, BCLibNetherBiomeSource::isValidNetherBiome);
}
@ -176,20 +181,20 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
@Override
protected void onInitMap(long seed) {
TriFunction<Long, Integer, BiomePicker, BiomeMap> mapConstructor = config.mapVersion.mapBuilder;
if (maxHeight > 128 && GeneratorOptions.useVerticalBiomes()) {
MapBuilderFunction mapConstructor = config.mapVersion.mapBuilder;
if (maxHeight > config.biomeSizeVertical * 1.5 && config.useVerticalBiomes) {
this.biomeMap = new MapStack(
seed,
GeneratorOptions.getBiomeSizeNether(),
config.biomeSize,
biomePicker,
GeneratorOptions.getVerticalBiomeSizeNether(),
config.biomeSizeVertical,
maxHeight,
mapConstructor
);
} else {
this.biomeMap = mapConstructor.apply(
this.biomeMap = mapConstructor.create(
seed,
GeneratorOptions.getBiomeSizeNether(),
config.biomeSize,
biomePicker
);
}
@ -215,4 +220,10 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource implements BiomeSourc
this.config = newConfig;
initMap(currentSeed);
}
@Override
public void reloadBiomes() {
rebuildBiomePicker();
initMap(currentSeed);
}
}

View file

@ -0,0 +1,264 @@
package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.interfaces.BiomeMap;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import java.util.LinkedList;
import java.util.List;
/**
* Used to extend the BiomePlacement in the {@link BCLBiomeSource}
*/
public abstract class BiomeDecider {
/**
* used to create new {@link BiomeMap} instances
*/
@FunctionalInterface
public interface BiomeMapBuilderFunction {
/**
* Constructs a new {@link BiomeMap}
*
* @param picker The picker the BiomeMap should use
* @param biomeSize The biomeSize the map will use or -1 for the default size
* @return a new {@link BiomeMap} instance
*/
BiomeMap create(BiomePicker picker, int biomeSize);
}
/**
* used to determine wether or not a decider can provide this biome
*/
@FunctionalInterface
public interface BiomePredicate {
boolean test(BCLBiome biome);
}
protected BiomePicker picker;
protected BiomeMap map;
private final BiomePredicate predicate;
static List<BiomeDecider> DECIDERS = new LinkedList<>();
/**
* Register a high priority Decider for the {@link BCLibEndBiomeSource}.
* Normally you should not need to register a high priority decider and instead use
* {@link BiomeDecider#registerDecider(ResourceLocation, BiomeDecider)}.
* BetterEnd (for example) will add
*
* @param location The {@link ResourceLocation} for the decider
* @param decider The initial decider Instance. Each Instance of the {@link BCLibEndBiomeSource}
* will call {@link BiomeDecider#createInstance(BCLBiomeSource)} to build a
* new instance of this decider
*/
public static void registerHighPriorityDecider(ResourceLocation location, BiomeDecider decider) {
if (DECIDERS.size() == 0) DECIDERS.add(decider);
else DECIDERS.add(0, decider);
}
/**
* Register a new Decider for the {@link BCLibEndBiomeSource}
*
* @param location The {@link ResourceLocation} for the decider
* @param decider The initial decider Instance. Each Instance of the {@link BCLibEndBiomeSource}
* will call {@link BiomeDecider#createInstance(BCLBiomeSource)} to build a
* new instance of this decider
*/
public static void registerDecider(ResourceLocation location, BiomeDecider decider) {
DECIDERS.add(decider);
}
protected BiomeDecider(BiomePredicate predicate) {
this(null, predicate);
}
/**
* @param biomeRegistry The biome registry assigned to the creating BiomeSource
* @param predicate A predicate that decides if a given Biome can be provided by this decider
*/
protected BiomeDecider(
Registry<Biome> biomeRegistry, BiomePredicate predicate
) {
this.predicate = predicate;
this.map = null;
if (biomeRegistry == null) {
this.picker = null;
} else {
this.picker = new BiomePicker(biomeRegistry);
}
}
/**
* Called to test, if a decider is suitable for the given BiomeSource.
*
* @param source The BiomeSource that wants to use the decider
* @return true, if this decider is usable by that source
*/
public abstract boolean canProvideFor(BiomeSource source);
/**
* Called from the BiomeSource whenever it needs to create a new instance of this decider.
* <p>
* Inheriting classes should overwrite this method and return Instances of the class. For
* the base {@link BiomeDecider} you would return <em>new BiomeDecider(biomeSource.biomeRegistry, this.predicate);</em>
*
* @param biomeSource The biome source this decider is used from
* @return A new instance
*/
public abstract BiomeDecider createInstance(BCLBiomeSource biomeSource);
/**
* Called when the BiomeSources needs to construct a new {@link BiomeMap} for the picker.
* <p>
* The default implementation creates a new map with the instances picker and a default biome size
*
* @param mapBuilder A function you can use to create a new {@link BiomeMap} that conforms to the settings
* of the current BiomeSource.
*/
public void createMap(BiomeMapBuilderFunction mapBuilder) {
this.map = mapBuilder.create(picker, -1);
}
/**
* called whenever the BiomeSource needs to clear caches
*/
public void clearMapCache() {
map.clearCache();
}
/**
* This method get's called whenever the BiomeSource populates the Biome Pickers. You need to
* determine if the passed Biome is valid for your picker.
* <p>
* If this method returns false, the Biome wil not get added to any other Deciders/Pickers.
* <p>
* The default implementation will use the instances {@link BiomeDecider#predicate} to determine if
* a biome should get added and return true if it was added.
*
* @param biome The biome that should get added if it matches the criteria of the picker
* @return false, if other pickers/deciders are allowed to use the biome as well
*/
public boolean addToPicker(BCLBiome biome) {
if (predicate.test(biome)) {
picker.addBiome(biome);
return true;
}
return false;
}
/**
* Called whenever the picker needs to rebuild it's contents
*/
public void rebuild() {
picker.rebuild();
}
/**
* Called from the BiomeSource to determine the type of Biome it needs to place.
*
* @param originalType The original biome type the source did select
* @param suggestedType The currently suggested type. This will differ from <em>originalType</em> if other
* {@link BiomeDecider} instances already had a new suggestion. You implementation should return the
* <em>suggestedType</em> if it does not want to provide the Biome for this location
* @param maxHeight The maximum terrain height for this world
* @param blockX The block coordinate where we are at
* @param blockY The block coordinate where we are at
* @param blockZ The block coordinate where we are at
* @param quarterX The quarter Block Coordinate (which is blockX/4)
* @param quarterY The quarter Block Coordinate (which is blockY/4)
* @param quarterZ The quarter Block Coordinate (which is blockZ/4)
* @return The <em>suggestedType</em> if this decider does not plan to provide a Biome, or a unique BiomeType.
* The Biome Source will call {@link BiomeDecider#canProvideBiome(BiomeAPI.BiomeType)} with the finally chosen type
* for all available Deciders.
*/
public BiomeAPI.BiomeType suggestType(
BiomeAPI.BiomeType originalType,
BiomeAPI.BiomeType suggestedType,
int maxHeight,
int blockX,
int blockY,
int blockZ,
int quarterX,
int quarterY,
int quarterZ
) {
return suggestType(
originalType,
suggestedType,
0,
maxHeight,
blockX,
blockY,
blockZ,
quarterX,
quarterY,
quarterZ
);
}
/**
* Called from the BiomeSource to determine the type of Biome it needs to place.
*
* @param originalType The original biome type the source did select
* @param suggestedType The currently suggested type. This will differ from <em>originalType</em> if other
* {@link BiomeDecider} instances already had a new suggestion. You implementation should return the
* <em>suggestedType</em> if it does not want to provide the Biome for this location
* @param density The terrain density at this location. Currently only valid if for {@link BCLibEndBiomeSource}
* that use the {@link org.betterx.bclib.api.v2.generator.config.BCLEndBiomeSourceConfig.EndBiomeGeneratorType#VANILLA}
* @param maxHeight The maximum terrain height for this world
* @param blockX The block coordinate where we are at
* @param blockY The block coordinate where we are at
* @param blockZ The block coordinate where we are at
* @param quarterX The quarter Block Coordinate (which is blockX/4)
* @param quarterY The quarter Block Coordinate (which is blockY/4)
* @param quarterZ The quarter Block Coordinate (which is blockZ/4)
* @param maxHeight
* @return The <em>suggestedType</em> if this decider does not plan to provide a Biome, or a unique BiomeType.
* The Biome Source will call {@link BiomeDecider#canProvideBiome(BiomeAPI.BiomeType)} with the finally chosen type
* for all available Deciders.
*/
public abstract BiomeAPI.BiomeType suggestType(
BiomeAPI.BiomeType originalType,
BiomeAPI.BiomeType suggestedType,
double density,
int maxHeight,
int blockX,
int blockY,
int blockZ,
int quarterX,
int quarterY,
int quarterZ
);
/**
* Called to check if this decider can place a biome for the specified type
*
* @param suggestedType The type of biome we need to place
* @return true, if this type of biome can be provided by the current picker. If true
* is returned, the BiomeSource will call {@link BiomeDecider#provideBiome(BiomeAPI.BiomeType, int, int, int)}
* next
*/
public abstract boolean canProvideBiome(BiomeAPI.BiomeType suggestedType);
/**
* Called to check if this decider can place a biome for the specified type
* <p>
* The default implementation will return <em>map.getBiome(posX, posY, posZ)</em>
*
* @param suggestedType The type of biome we need to place
* @return The methode should return a Biome from its {@link BiomeMap}. If null is returned, the next
* decider (or the default map) will provide the biome
*/
public BiomePicker.ActualBiome provideBiome(BiomeAPI.BiomeType suggestedType, int posX, int posY, int posZ) {
return map.getBiome(posX, posY, posZ);
}
}

View file

@ -1,7 +1,7 @@
package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.util.WeighTree;
import org.betterx.bclib.util.WeightedList;
@ -23,6 +23,7 @@ public class BiomePicker {
public final Registry<Biome> biomeRegistry;
private final List<ActualBiome> biomes = Lists.newArrayList();
private final List<String> allowedBiomes;
public final ActualBiome fallbackBiome;
private WeighTree<ActualBiome> tree;
public BiomePicker(Registry<Biome> biomeRegistry) {
@ -36,6 +37,7 @@ public class BiomePicker {
.map(h -> h.unwrapKey())
.filter(o -> o.isPresent())
.map(o -> o.get().location().toString()).toList() : null;
this.fallbackBiome = create(BCLBiomeRegistry.EMPTY_BIOME);
}
private boolean isAllowed(BCLBiome b) {
@ -54,18 +56,34 @@ public class BiomePicker {
}
public ActualBiome getBiome(WorldgenRandom random) {
return biomes.isEmpty() ? null : tree.get(random);
return biomes.isEmpty() ? fallbackBiome : tree.get(random);
}
public boolean isEmpty() {
return biomes.isEmpty();
}
public void rebuild() {
WeightedList<ActualBiome> list = new WeightedList<>();
if (biomes.isEmpty()) {
list.add(create(BiomeAPI.EMPTY_BIOME), 1);
} else {
biomes.forEach(biome -> {
if (biome.isValid)
list.add(biome, biome.bclBiome.getGenChance());
});
biomes.forEach(biome -> {
if (biome.isValid)
list.add(biome, biome.bclBiome.getGenChance());
});
//only a single biome, we need to add the edges as well
if (list.size() == 1) {
ActualBiome biome = list.get(0);
if (biome.getEdge() != null) {
float defaultBiomeSize = 128;
float edgeSize = (biome.bclBiome.getEdgeSize() * list.getWeight(0)) / defaultBiomeSize;
list.add(biome.getEdge(), edgeSize);
}
}
//no Biome, make sure we add at least one, otherwise bad things will happen
if (list.isEmpty()) {
list.add(create(BCLBiomeRegistry.EMPTY_BIOME), 1);
}
@ -88,7 +106,7 @@ public class BiomePicker {
this.key = biomeRegistry.getResourceKey(biomeRegistry.get(bclBiome.getID())).orElse(null);
this.biome = key != null ? biomeRegistry.getOrCreateHolderOrThrow(key) : null;
this.isValid = key != null;
this.isValid = key != null && biome != null && biome.isBound();
bclBiome.forEachSubBiome((b, w) -> {
if (isAllowed(b))
subbiomes.add(create(b), w);
@ -131,5 +149,25 @@ public class BiomePicker {
public boolean isSame(ActualBiome e) {
return bclBiome.isSame(e.bclBiome);
}
@Override
public String toString() {
return "ActualBiome{" +
"key=" + key.location() +
", subbiomes=" + subbiomes.size() +
", edge=" + (edge != null ? edge.key.location() : "null") +
", parent=" + (parent != null ? parent.key.location() : "null") +
", isValid=" + isValid +
'}';
}
}
@Override
public String toString() {
return "BiomePicker{" +
"biomes=" + biomes.size() + " (" + all.size() + ")" +
", biomeRegistry=" + biomeRegistry +
", type=" + super.toString() +
'}';
}
}

View file

@ -2,55 +2,38 @@ package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.config.Configs;
import net.minecraft.util.Mth;
import java.awt.*;
import java.util.function.BiFunction;
import java.util.function.Function;
public class GeneratorOptions {
private static int biomeSizeNether;
private static int biomeVSizeNether;
private static int biomeSizeEndLand;
private static int biomeSizeEndVoid;
private static BiFunction<Point, Integer, Boolean> endLandFunction;
private static boolean customNetherBiomeSource = true;
private static boolean customEndBiomeSource = true;
private static boolean verticalBiomes = true;
private static long farEndBiomesSqr = 1000000;
//private static BiFunction<Point, Integer, Boolean> endLandFunction;
private static boolean fixEndBiomeSource = true;
private static boolean fixNetherBiomeSource = true;
public static void init() {
biomeSizeNether = Configs.GENERATOR_CONFIG.getInt("nether.biomeMap", "biomeSize", 256);
biomeVSizeNether = Configs.GENERATOR_CONFIG.getInt(
"nether.biomeMap",
"biomeVerticalSize(onlyInTallNether)",
86
);
biomeSizeEndLand = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeLand", 256);
biomeSizeEndVoid = Configs.GENERATOR_CONFIG.getInt("end.biomeMap", "biomeSizeVoid", 256);
customNetherBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customNetherBiomeSource", true);
customEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customEndBiomeSource", true);
verticalBiomes = Configs.GENERATOR_CONFIG.getBoolean("options", "verticalBiomesInTallNether", true);
fixEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options.biomeSource", "fixEndBiomeSource", true);
fixNetherBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options.biomeSource", "fixNetherBiomeSource", true);
}
@Deprecated(forRemoval = true)
public static int getBiomeSizeNether() {
return Mth.clamp(biomeSizeNether, 1, 8192);
return 256;
}
@Deprecated(forRemoval = true)
public static int getVerticalBiomeSizeNether() {
return Mth.clamp(biomeVSizeNether, 1, 8192);
return 86;
}
@Deprecated(forRemoval = true)
public static int getBiomeSizeEndLand() {
return Mth.clamp(biomeSizeEndLand, 1, 8192);
return 256;
}
@Deprecated(forRemoval = true)
public static int getBiomeSizeEndVoid() {
return Mth.clamp(biomeSizeEndVoid, 1, 8192);
return 256;
}
/**
@ -59,19 +42,22 @@ public class GeneratorOptions {
*/
@Deprecated(forRemoval = true)
public static void setEndLandFunction(Function<Point, Boolean> endLandFunction) {
GeneratorOptions.endLandFunction = (p, h) -> endLandFunction.apply(p);
//GeneratorOptions.endLandFunction = (p, h) -> endLandFunction.apply(p);
}
@Deprecated(forRemoval = true)
public static void setEndLandFunction(BiFunction<Point, Integer, Boolean> endLandFunction) {
GeneratorOptions.endLandFunction = endLandFunction;
///GeneratorOptions.endLandFunction = endLandFunction;
}
@Deprecated(forRemoval = true)
public static BiFunction<Point, Integer, Boolean> getEndLandFunction() {
return endLandFunction;
return (a, b) -> true;//endLandFunction;
}
@Deprecated(forRemoval = true)
public static long getFarEndBiomes() {
return farEndBiomesSqr;
return 1000000;
}
/**
@ -79,8 +65,8 @@ public class GeneratorOptions {
*
* @param distance
*/
@Deprecated(forRemoval = true)
public static void setFarEndBiomes(int distance) {
GeneratorOptions.farEndBiomesSqr = (long) distance * (long) distance;
}
/**
@ -88,21 +74,25 @@ public class GeneratorOptions {
*
* @param distanceSqr the distance squared
*/
@Deprecated(forRemoval = true)
public static void setFarEndBiomesSqr(long distanceSqr) {
GeneratorOptions.farEndBiomesSqr = distanceSqr;
}
@Deprecated(forRemoval = true)
public static boolean customNetherBiomeSource() {
return customNetherBiomeSource;
return true;
}
@Deprecated(forRemoval = true)
public static boolean customEndBiomeSource() {
return customEndBiomeSource;
return true;
}
@Deprecated(forRemoval = true)
public static boolean useVerticalBiomes() {
return verticalBiomes;
return true;
}
public static boolean fixEndBiomeSource() {

View file

@ -1,96 +1,92 @@
package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.interfaces.TheEndBiomeDataAccessor;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.ApiStatus;
/**
* Helper class until FAPI integrates https://github.com/FabricMC/fabric/pull/2369
* Helper class until FAPI integrates <a href="https://github.com/FabricMC/fabric/pull/2369">this PR</a>
*/
public class TheEndBiomesHelper {
public static TheEndBiomeDataAccessor INSTANCE;
@ApiStatus.Internal
private static Map<BiomeAPI.BiomeType, Set<ResourceKey<Biome>>> END_BIOMES = new HashMap<>();
private static TheEndBiomeDataAccessor get() {
if (INSTANCE == null) {
try {
Class<TheEndBiomeData> cl = TheEndBiomeData.class;
Constructor constr = Arrays.stream(cl.getDeclaredConstructors())
.filter(c -> c.getParameterCount() == 0)
.findFirst()
.orElseThrow();
constr.setAccessible(true);
INSTANCE = (TheEndBiomeDataAccessor) constr.newInstance();
} catch (NoClassDefFoundError cnf) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
if (INSTANCE == null) {
BCLib.LOGGER.warning("Unable to access internal End-Biome API from Fabric. Using Fallback behaviour.");
INSTANCE = new TheEndBiomeDataAccessor() {
@Override
public boolean bcl_canGenerateAsEndBiome(ResourceKey<Biome> key) {
return true;
}
@Override
public boolean bcl_canGenerateAsEndMidlandBiome(ResourceKey<Biome> key) {
return false;
}
@Override
public boolean bcl_canGenerateAsEndBarrensBiome(ResourceKey<Biome> key) {
return false;
}
};
}
}
return INSTANCE;
@ApiStatus.Internal
public static void add(BiomeAPI.BiomeType type, ResourceKey<Biome> biome) {
if (biome == null) return;
END_BIOMES.computeIfAbsent(type, t -> new HashSet<>()).add(biome);
}
private static boolean has(BiomeAPI.BiomeType type, ResourceKey<Biome> biome) {
if (biome == null) return false;
Set<ResourceKey<Biome>> set = END_BIOMES.get(type);
if (set == null) return false;
return set.contains(biome);
}
/**
* Returns true if the given biome was added in the end, considering the Vanilla end biomes,
* Returns true if the given biome was added as a main end Biome in the end, considering the Vanilla end biomes,
* and any biomes added to the End by mods.
*
* @param biome The biome to search for
*/
public static boolean isIntendedForEndBiome(ResourceKey<Biome> biome) {
return get().bcl_canGenerateAsEndBiome(biome);
public static boolean canGenerateAsMainIslandBiome(ResourceKey<Biome> biome) {
return has(BiomeAPI.BiomeType.END_CENTER, biome);
}
/**
* Returns true if the given biome was added as a small end islands Biome in the end, considering the Vanilla end biomes,
* and any biomes added to the End by mods.
*
* @param biome The biome to search for
*/
public static boolean canGenerateAsSmallIslandsBiome(ResourceKey<Biome> biome) {
return has(BiomeAPI.BiomeType.END_VOID, biome);
}
/**
* Returns true if the given biome was added as a Highland Biome in the end, considering the Vanilla end biomes,
* and any biomes added to the End by mods.
*
* @param biome The biome to search for
*/
public static boolean canGenerateAsHighlandsBiome(ResourceKey<Biome> biome) {
return has(BiomeAPI.BiomeType.END_LAND, biome);
}
/**
* Returns true if the given biome was added as midland biome in the end, considering the Vanilla end biomes,
* and any biomes added to the End as midland biome by mods.
*
* @param biome The biome to search for
*/
public static boolean isIntendedForEndMidlands(ResourceKey<Biome> biome) {
return get().bcl_canGenerateAsEndMidlandBiome(biome);
public static boolean canGenerateAsEndMidlands(ResourceKey<Biome> biome) {
return false;
}
/**
* Returns true if the given biome was added as barrens biome in the end, considering the Vanilla end biomes,
* and any biomes added to the End as barrens biome by mods.
*
* @param biome The biome to search for
*/
public static boolean isIntendedForEndBarrens(ResourceKey<Biome> biome) {
return get().bcl_canGenerateAsEndBarrensBiome(biome);
public static boolean canGenerateAsEndBarrens(ResourceKey<Biome> biome) {
return has(BiomeAPI.BiomeType.END_BARRENS, biome);
}
public static boolean isIntendedForEndLand(ResourceKey<Biome> biome) {
return isIntendedForEndBiome(biome) || isIntendedForEndMidlands(biome);
}
public static boolean isIntendedForAny(ResourceKey<Biome> biome) {
return isIntendedForEndBiome(biome) || isIntendedForEndMidlands(biome) || isIntendedForEndBarrens(biome);
public static boolean canGenerateInEnd(ResourceKey<Biome> biome) {
return canGenerateAsHighlandsBiome(biome)
|| canGenerateAsEndBarrens(biome)
|| canGenerateAsEndMidlands(biome)
|| canGenerateAsSmallIslandsBiome(biome)
|| canGenerateAsMainIslandBiome(biome);
}
}

View file

@ -0,0 +1,24 @@
package org.betterx.bclib.api.v2.generator;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
public abstract class TypeBiomeDecider extends BiomeDecider {
protected final BiomeAPI.BiomeType assignedType;
public TypeBiomeDecider(BiomeAPI.BiomeType assignedType) {
this(null, assignedType);
}
protected TypeBiomeDecider(Registry<Biome> biomeRegistry, BiomeAPI.BiomeType assignedType) {
super(biomeRegistry, (biome) -> biome.getIntendedType().is(assignedType));
this.assignedType = assignedType;
}
@Override
public boolean canProvideBiome(BiomeAPI.BiomeType suggestedType) {
return suggestedType.equals(assignedType);
}
}

View file

@ -1,15 +1,14 @@
package org.betterx.bclib.api.v2.generator.config;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.generator.BCLibEndBiomeSource;
import org.betterx.bclib.api.v2.generator.BiomePicker;
import org.betterx.bclib.api.v2.generator.map.hex.HexBiomeMap;
import org.betterx.bclib.api.v2.generator.map.square.SquareBiomeMap;
import org.betterx.bclib.interfaces.BiomeMap;
import org.betterx.bclib.util.TriFunction;
import org.betterx.worlds.together.biomesource.config.BiomeSourceConfig;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.Mth;
import net.minecraft.util.StringRepresentable;
import java.util.Objects;
@ -20,19 +19,31 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
EndBiomeMapType.VANILLA,
EndBiomeGeneratorType.VANILLA,
true,
4096
4096,
128,
128,
128,
128
);
public static final BCLEndBiomeSourceConfig MINECRAFT_17 = new BCLEndBiomeSourceConfig(
EndBiomeMapType.SQUARE,
EndBiomeGeneratorType.PAULEVS,
true,
1000000
VANILLA.innerVoidRadiusSquared * 16 * 16,
256,
256,
256,
256
);
public static final BCLEndBiomeSourceConfig MINECRAFT_18 = new BCLEndBiomeSourceConfig(
EndBiomeMapType.HEX,
EndBiomeGeneratorType.PAULEVS,
false,
MINECRAFT_17.innerVoidRadiusSquared
BCLib.RUNS_NULLSCAPE ? EndBiomeGeneratorType.VANILLA : EndBiomeGeneratorType.PAULEVS,
BCLib.RUNS_NULLSCAPE ? false : true,
MINECRAFT_17.innerVoidRadiusSquared,
MINECRAFT_17.centerBiomesSize,
MINECRAFT_17.voidBiomesSize,
MINECRAFT_17.landBiomesSize,
MINECRAFT_17.barrensBiomesSize
);
public static final BCLEndBiomeSourceConfig DEFAULT = MINECRAFT_18;
@ -53,7 +64,23 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
Codec.INT
.fieldOf("inner_void_radius_squared")
.orElse(DEFAULT.innerVoidRadiusSquared)
.forGetter(o -> o.innerVoidRadiusSquared)
.forGetter(o -> o.innerVoidRadiusSquared),
Codec.INT
.fieldOf("center_biomes_size")
.orElse(DEFAULT.centerBiomesSize)
.forGetter(o -> o.centerBiomesSize),
Codec.INT
.fieldOf("void_biomes_size")
.orElse(DEFAULT.voidBiomesSize)
.forGetter(o -> o.voidBiomesSize),
Codec.INT
.fieldOf("land_biomes_size")
.orElse(DEFAULT.landBiomesSize)
.forGetter(o -> o.landBiomesSize),
Codec.INT
.fieldOf("barrens_biomes_size")
.orElse(DEFAULT.barrensBiomesSize)
.forGetter(o -> o.barrensBiomesSize)
)
.apply(instance, BCLEndBiomeSourceConfig::new));
@ -61,12 +88,20 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
@NotNull EndBiomeMapType mapVersion,
@NotNull EndBiomeGeneratorType generatorVersion,
boolean withVoidBiomes,
int innerVoidRadiusSquared
int innerVoidRadiusSquared,
int centerBiomesSize,
int voidBiomesSize,
int landBiomesSize,
int barrensBiomesSize
) {
this.mapVersion = mapVersion;
this.generatorVersion = generatorVersion;
this.withVoidBiomes = withVoidBiomes;
this.innerVoidRadiusSquared = innerVoidRadiusSquared;
this.barrensBiomesSize = Mth.clamp(barrensBiomesSize, 1, 8192);
this.voidBiomesSize = Mth.clamp(voidBiomesSize, 1, 8192);
this.centerBiomesSize = Mth.clamp(centerBiomesSize, 1, 8192);
this.landBiomesSize = Mth.clamp(landBiomesSize, 1, 8192);
}
public enum EndBiomeMapType implements StringRepresentable {
@ -76,9 +111,9 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
public static final Codec<EndBiomeMapType> CODEC = StringRepresentable.fromEnum(EndBiomeMapType::values);
public final String name;
public final @NotNull TriFunction<Long, Integer, BiomePicker, BiomeMap> mapBuilder;
public final @NotNull MapBuilderFunction mapBuilder;
EndBiomeMapType(String name, @NotNull TriFunction<Long, Integer, BiomePicker, BiomeMap> mapBuilder) {
EndBiomeMapType(String name, @NotNull MapBuilderFunction mapBuilder) {
this.name = name;
this.mapBuilder = mapBuilder;
}
@ -122,13 +157,22 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
public final boolean withVoidBiomes;
public final int innerVoidRadiusSquared;
public final int voidBiomesSize;
public final int centerBiomesSize;
public final int landBiomesSize;
public final int barrensBiomesSize;
@Override
public String toString() {
return "BCLibEndBiomeSourceConfig{" +
return "BCLEndBiomeSourceConfig{" +
"mapVersion=" + mapVersion +
", generatorVersion=" + generatorVersion +
", withVoidBiomes=" + withVoidBiomes +
", innerVoidRadiusSquared=" + innerVoidRadiusSquared +
", voidBiomesSize=" + voidBiomesSize +
", centerBiomesSize=" + centerBiomesSize +
", landBiomesSize=" + landBiomesSize +
", barrensBiomesSize=" + barrensBiomesSize +
'}';
}
@ -148,13 +192,22 @@ public class BCLEndBiomeSourceConfig implements BiomeSourceConfig<BCLibEndBiomeS
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BCLEndBiomeSourceConfig)) return false;
if (o == null || getClass() != o.getClass()) return false;
BCLEndBiomeSourceConfig that = (BCLEndBiomeSourceConfig) o;
return withVoidBiomes == that.withVoidBiomes && innerVoidRadiusSquared == that.innerVoidRadiusSquared && mapVersion == that.mapVersion && generatorVersion == that.generatorVersion;
return withVoidBiomes == that.withVoidBiomes && innerVoidRadiusSquared == that.innerVoidRadiusSquared && voidBiomesSize == that.voidBiomesSize && centerBiomesSize == that.centerBiomesSize && landBiomesSize == that.landBiomesSize && barrensBiomesSize == that.barrensBiomesSize && mapVersion == that.mapVersion && generatorVersion == that.generatorVersion;
}
@Override
public int hashCode() {
return Objects.hash(mapVersion, generatorVersion, withVoidBiomes, innerVoidRadiusSquared);
return Objects.hash(
mapVersion,
generatorVersion,
withVoidBiomes,
innerVoidRadiusSquared,
voidBiomesSize,
centerBiomesSize,
landBiomesSize,
barrensBiomesSize
);
}
}

View file

@ -1,15 +1,13 @@
package org.betterx.bclib.api.v2.generator.config;
import org.betterx.bclib.api.v2.generator.BCLibNetherBiomeSource;
import org.betterx.bclib.api.v2.generator.BiomePicker;
import org.betterx.bclib.api.v2.generator.map.hex.HexBiomeMap;
import org.betterx.bclib.api.v2.generator.map.square.SquareBiomeMap;
import org.betterx.bclib.interfaces.BiomeMap;
import org.betterx.bclib.util.TriFunction;
import org.betterx.worlds.together.biomesource.config.BiomeSourceConfig;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.Mth;
import net.minecraft.util.StringRepresentable;
import java.util.Objects;
@ -17,13 +15,22 @@ import org.jetbrains.annotations.NotNull;
public class BCLNetherBiomeSourceConfig implements BiomeSourceConfig<BCLibNetherBiomeSource> {
public static final BCLNetherBiomeSourceConfig VANILLA = new BCLNetherBiomeSourceConfig(
NetherBiomeMapType.VANILLA
NetherBiomeMapType.VANILLA,
256,
86,
false
);
public static final BCLNetherBiomeSourceConfig MINECRAFT_17 = new BCLNetherBiomeSourceConfig(
NetherBiomeMapType.SQUARE
NetherBiomeMapType.SQUARE,
256,
86,
true
);
public static final BCLNetherBiomeSourceConfig MINECRAFT_18 = new BCLNetherBiomeSourceConfig(
NetherBiomeMapType.HEX
NetherBiomeMapType.HEX,
MINECRAFT_17.biomeSize,
MINECRAFT_17.biomeSizeVertical,
MINECRAFT_17.useVerticalBiomes
);
public static final BCLNetherBiomeSourceConfig DEFAULT = MINECRAFT_18;
@ -32,13 +39,32 @@ public class BCLNetherBiomeSourceConfig implements BiomeSourceConfig<BCLibNether
BCLNetherBiomeSourceConfig.NetherBiomeMapType.CODEC
.fieldOf("map_type")
.orElse(DEFAULT.mapVersion)
.forGetter(o -> o.mapVersion)
.forGetter(o -> o.mapVersion),
Codec.INT.fieldOf("biome_size").orElse(DEFAULT.biomeSize).forGetter(o -> o.biomeSize),
Codec.INT.fieldOf("biome_size_vertical")
.orElse(DEFAULT.biomeSizeVertical)
.forGetter(o -> o.biomeSizeVertical),
Codec.BOOL.fieldOf("use_vertical_biomes")
.orElse(DEFAULT.useVerticalBiomes)
.forGetter(o -> o.useVerticalBiomes)
)
.apply(instance, BCLNetherBiomeSourceConfig::new));
public final @NotNull NetherBiomeMapType mapVersion;
public final int biomeSize;
public final int biomeSizeVertical;
public BCLNetherBiomeSourceConfig(@NotNull NetherBiomeMapType mapVersion) {
public final boolean useVerticalBiomes;
public BCLNetherBiomeSourceConfig(
@NotNull NetherBiomeMapType mapVersion,
int biomeSize,
int biomeSizeVertical,
boolean useVerticalBiomes
) {
this.mapVersion = mapVersion;
this.biomeSize = Mth.clamp(biomeSize, 1, 8192);
this.biomeSizeVertical = Mth.clamp(biomeSizeVertical, 1, 8192);
this.useVerticalBiomes = useVerticalBiomes;
}
@Override
@ -81,9 +107,9 @@ public class BCLNetherBiomeSourceConfig implements BiomeSourceConfig<BCLibNether
public static final Codec<NetherBiomeMapType> CODEC = StringRepresentable.fromEnum(NetherBiomeMapType::values);
public final String name;
public final TriFunction<Long, Integer, BiomePicker, BiomeMap> mapBuilder;
public final MapBuilderFunction mapBuilder;
NetherBiomeMapType(String name, TriFunction<Long, Integer, BiomePicker, BiomeMap> mapBuilder) {
NetherBiomeMapType(String name, MapBuilderFunction mapBuilder) {
this.name = name;
this.mapBuilder = mapBuilder;
}

View file

@ -0,0 +1,9 @@
package org.betterx.bclib.api.v2.generator.config;
import org.betterx.bclib.api.v2.generator.BiomePicker;
import org.betterx.bclib.interfaces.BiomeMap;
@FunctionalInterface
public interface MapBuilderFunction {
BiomeMap create(long seed, int biomeSize, BiomePicker picker);
}

View file

@ -1,11 +1,11 @@
package org.betterx.bclib.api.v2.generator.map;
import org.betterx.bclib.api.v2.generator.BiomePicker;
import org.betterx.bclib.api.v2.generator.config.MapBuilderFunction;
import org.betterx.bclib.interfaces.BiomeChunk;
import org.betterx.bclib.interfaces.BiomeMap;
import org.betterx.bclib.interfaces.TriConsumer;
import org.betterx.bclib.noise.OpenSimplexNoise;
import org.betterx.bclib.util.TriFunction;
import net.minecraft.util.Mth;
@ -26,7 +26,7 @@ public class MapStack implements BiomeMap {
BiomePicker picker,
int mapHeight,
int worldHeight,
TriFunction<Long, Integer, BiomePicker, BiomeMap> mapConstructor
MapBuilderFunction mapConstructor
) {
final int mapCount = Mth.ceil((float) worldHeight / mapHeight);
this.maxIndex = mapCount - 1;
@ -37,7 +37,7 @@ public class MapStack implements BiomeMap {
maps = new BiomeMap[mapCount];
Random random = new Random(seed);
for (int i = 0; i < mapCount; i++) {
maps[i] = mapConstructor.apply(random.nextLong(), size, picker);
maps[i] = mapConstructor.create(random.nextLong(), size, picker);
maps[i].setChunkProcessor(this::onChunkCreation);
}
noise = new OpenSimplexNoise(random.nextInt());

View file

@ -7,7 +7,10 @@ import org.betterx.bclib.api.v2.datafixer.DataFixerAPI;
import org.betterx.bclib.api.v2.generator.BCLibEndBiomeSource;
import org.betterx.bclib.api.v2.generator.config.BCLEndBiomeSourceConfig;
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
import org.betterx.bclib.api.v2.tag.TagAPI;
import org.betterx.bclib.registry.PresetsRegistry;
import org.betterx.worlds.together.tag.v3.TagManager;
import org.betterx.worlds.together.world.WorldConfig;
import org.betterx.worlds.together.world.event.WorldEvents;
import org.betterx.worlds.together.worldPreset.TogetherWorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPreset;
@ -15,11 +18,14 @@ import org.betterx.worlds.together.worldPreset.WorldPreset;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagLoader;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.storage.LevelStorageSource;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
@ -40,6 +46,21 @@ public class LevelGenEvents {
WorldEvents.PATCH_WORLD.on(LevelGenEvents::patchExistingWorld);
WorldEvents.ADAPT_WORLD_PRESET.on(LevelGenEvents::adaptWorldPresetSettings);
WorldEvents.BEFORE_ADDING_TAGS.on(LevelGenEvents::appplyTags);
}
private static void appplyTags(
String directory,
Map<ResourceLocation, List<TagLoader.EntryWithSource>> tagsMap
) {
//make sure we include Tags registered by the deprecated API
TagAPI.apply(directory, tagsMap);
if (directory.equals(TagManager.BIOMES.directory)) {
InternalBiomeAPI._runBiomeTagAdders();
}
}
@ -78,7 +99,11 @@ public class LevelGenEvents {
inputConfig.mapVersion,
BCLEndBiomeSourceConfig.EndBiomeGeneratorType.VANILLA,
false,
inputConfig.innerVoidRadiusSquared
inputConfig.innerVoidRadiusSquared,
inputConfig.centerBiomesSize,
inputConfig.voidBiomesSize,
inputConfig.landBiomesSize,
inputConfig.barrensBiomesSize
));
}
}
@ -99,6 +124,7 @@ public class LevelGenEvents {
) {
setupWorld();
if (isNewWorld) {
WorldConfig.saveFile(BCLib.MOD_ID);
DataFixerAPI.initializePatchData();
} else {
LevelGenUtil.migrateGeneratorSettings();
@ -113,6 +139,7 @@ public class LevelGenEvents {
setupWorld();
if (isNewWorld) {
WorldConfig.saveFile(BCLib.MOD_ID);
DataFixerAPI.initializePatchData();
} else {
LevelGenUtil.migrateGeneratorSettings();

View file

@ -1,39 +1,190 @@
package org.betterx.bclib.api.v2.levelgen.biomes;
import org.betterx.bclib.util.WeightedList;
import org.betterx.worlds.together.tag.v3.TagManager;
import com.mojang.datafixers.Products;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.levelgen.WorldgenRandom;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
public class BCLBiome extends BCLBiomeSettings {
private final Set<TagKey<Biome>> biomeTags = Sets.newHashSet();
private final WeightedList<BCLBiome> subbiomes = new WeightedList<>();
public class BCLBiome extends BCLBiomeSettings implements BiomeData {
public static final Codec<BCLBiome> CODEC = RecordCodecBuilder.create(instance -> codecWithSettings(instance).apply(
instance,
BCLBiome::new
));
public static final KeyDispatchDataCodec<BCLBiome> KEY_CODEC = KeyDispatchDataCodec.of(CODEC);
public KeyDispatchDataCodec<? extends BCLBiome> codec() {
return KEY_CODEC;
}
private static class CodecAttributes<T extends BCLBiome> {
public RecordCodecBuilder<T, Float> t0 = Codec.FLOAT.fieldOf("terrainHeight")
.orElse(0.1f)
.forGetter((T o1) -> o1.terrainHeight);
public RecordCodecBuilder<T, Float> t1 = Codec.FLOAT.fieldOf("fogDensity")
.orElse(1.0f)
.forGetter((T o1) -> o1.fogDensity);
public RecordCodecBuilder<T, Float> t2 = Codec.FLOAT.fieldOf("genChance")
.orElse(1.0f)
.forGetter((T o1) -> o1.genChance);
public RecordCodecBuilder<T, Integer> t3 = Codec.INT.fieldOf("edgeSize")
.orElse(0)
.forGetter((T o1) -> o1.edgeSize);
public RecordCodecBuilder<T, Boolean> t4 = Codec.BOOL.fieldOf("vertical")
.orElse(false)
.forGetter((T o1) -> o1.vertical);
public RecordCodecBuilder<T, Optional<ResourceLocation>> t5 =
ResourceLocation.CODEC
.optionalFieldOf("edge")
.orElse(Optional.empty())
.forGetter((T o1) -> o1.edge == null
? Optional.empty()
: Optional.of(o1.edge.biomeID));
public RecordCodecBuilder<T, ResourceLocation> t6 =
ResourceLocation.CODEC.fieldOf("biome")
.forGetter((T o) -> ((BCLBiome) o).biomeID);
public RecordCodecBuilder<T, Optional<List<Climate.ParameterPoint>>> t7 =
Climate.ParameterPoint.CODEC.listOf()
.optionalFieldOf("parameter_points")
.orElse(Optional.of(List.of()))
.forGetter((T o) ->
o.parameterPoints == null || o.parameterPoints.isEmpty()
? Optional.empty()
: Optional.of(o.parameterPoints));
public RecordCodecBuilder<T, Optional<ResourceLocation>> t8 =
ResourceLocation.CODEC.optionalFieldOf("parent")
.orElse(Optional.empty())
.forGetter(
(T o1) ->
((BCLBiome) o1).biomeParent == null
? Optional.empty()
: Optional.of(
((BCLBiome) o1).biomeParent.biomeID));
public RecordCodecBuilder<T, Optional<WeightedList<ResourceLocation>>> t9 =
WeightedList.listCodec(
ResourceLocation.CODEC,
"biomes",
"biome"
)
.optionalFieldOf("sub_biomes")
.forGetter(
(T o) -> {
if (o.subbiomes == null
|| o.subbiomes.isEmpty()
|| (o.subbiomes.size() == 1 && o.subbiomes.contains(
o))) {
return Optional.empty();
}
return Optional.of(
o.subbiomes.map(
b -> b.biomeID));
});
public RecordCodecBuilder<T, Optional<String>> t10 =
Codec.STRING.optionalFieldOf("intended_for")
.orElse(Optional.of(BiomeAPI.BiomeType.NONE.getName()))
.forGetter((T o) ->
((BCLBiome) o).intendedType == null
? Optional.empty()
: Optional.of(((BCLBiome) o).intendedType.getName()));
}
public static <T extends BCLBiome, P12> Products.P12<RecordCodecBuilder.Mu<T>, Float, Float, Float, Integer, Boolean, Optional<ResourceLocation>, ResourceLocation, Optional<List<Climate.ParameterPoint>>, Optional<ResourceLocation>, Optional<WeightedList<ResourceLocation>>, Optional<String>, P12> codecWithSettings(
RecordCodecBuilder.Instance<T> instance,
final RecordCodecBuilder<T, P12> p12
) {
CodecAttributes<T> a = new CodecAttributes<>();
return instance.group(a.t0, a.t1, a.t2, a.t3, a.t4, a.t5, a.t6, a.t7, a.t8, a.t9, a.t10, p12);
}
public static <T extends BCLBiome, P12, P13> Products.P13<RecordCodecBuilder.Mu<T>, Float, Float, Float, Integer, Boolean, Optional<ResourceLocation>, ResourceLocation, Optional<List<Climate.ParameterPoint>>, Optional<ResourceLocation>, Optional<WeightedList<ResourceLocation>>, Optional<String>, P12, P13> codecWithSettings(
RecordCodecBuilder.Instance<T> instance,
final RecordCodecBuilder<T, P12> p12,
final RecordCodecBuilder<T, P13> p13
) {
CodecAttributes<T> a = new CodecAttributes<>();
return instance.group(a.t0, a.t1, a.t2, a.t3, a.t4, a.t5, a.t6, a.t7, a.t8, a.t9, a.t10, p12, p13);
}
public static <T extends BCLBiome, P12, P13, P14> Products.P14<RecordCodecBuilder.Mu<T>, Float, Float, Float, Integer, Boolean, Optional<ResourceLocation>, ResourceLocation, Optional<List<Climate.ParameterPoint>>, Optional<ResourceLocation>, Optional<WeightedList<ResourceLocation>>, Optional<String>, P12, P13, P14> codecWithSettings(
RecordCodecBuilder.Instance<T> instance,
final RecordCodecBuilder<T, P12> p12,
final RecordCodecBuilder<T, P13> p13,
final RecordCodecBuilder<T, P14> p14
) {
CodecAttributes<T> a = new CodecAttributes<>();
return instance.group(a.t0, a.t1, a.t2, a.t3, a.t4, a.t5, a.t6, a.t7, a.t8, a.t9, a.t10, p12, p13, p14);
}
public static <T extends BCLBiome> Products.P11<RecordCodecBuilder.Mu<T>, Float, Float, Float, Integer, Boolean, Optional<ResourceLocation>, ResourceLocation, Optional<List<Climate.ParameterPoint>>, Optional<ResourceLocation>, Optional<WeightedList<ResourceLocation>>, Optional<String>> codecWithSettings(
RecordCodecBuilder.Instance<T> instance
) {
CodecAttributes<T> a = new CodecAttributes<>();
return instance.group(a.t0, a.t1, a.t2, a.t3, a.t4, a.t5, a.t6, a.t7, a.t8, a.t9, a.t10);
}
protected final WeightedList<BCLBiome> subbiomes = new WeightedList<>();
private final Map<String, Object> customData = Maps.newHashMap();
private final ResourceLocation biomeID;
private final Biome biome;
private final ResourceKey<Biome> biomeKey;
final Biome biomeToRegister;
private final List<Climate.ParameterPoint> parameterPoints = Lists.newArrayList();
protected final List<Climate.ParameterPoint> parameterPoints = Lists.newArrayList();
private BCLBiome biomeParent;
private BiomeAPI.BiomeType intendedType = BiomeAPI.BiomeType.NONE;
protected BCLBiome(
float terrainHeight,
float fogDensity,
float genChance,
int edgeSize,
boolean vertical,
Optional<ResourceLocation> edge,
ResourceLocation biomeID,
Optional<List<Climate.ParameterPoint>> parameterPoints,
Optional<ResourceLocation> biomeParent,
Optional<WeightedList<ResourceLocation>> subbiomes,
Optional<String> intendedType
) {
super(terrainHeight, fogDensity, genChance, edgeSize, vertical, edge.map(BiomeAPI::getBiome).orElse(null));
biomeToRegister = null;
this.biomeID = biomeID;
this.biomeKey = ResourceKey.create(Registry.BIOME_REGISTRY, biomeID);
if (subbiomes.isEmpty() || subbiomes.get().size() == 0) {
this.subbiomes.add(this, 1);
} else {
this.subbiomes.addAll(subbiomes.get().map(BiomeAPI::getBiome));
}
this.biomeParent = biomeParent.map(BiomeAPI::getBiome).orElse(null);
if (parameterPoints.isPresent()) this.parameterPoints.addAll(parameterPoints.get());
this.setIntendedType(intendedType.map(t -> BiomeAPI.BiomeType.create(t)).orElse(BiomeAPI.BiomeType.NONE));
}
/**
* Create wrapper for existing biome using its {@link ResourceLocation} identifier.
*
@ -49,49 +200,100 @@ public class BCLBiome extends BCLBiomeSettings {
* @param biomeID {@link ResourceLocation} biome ID.
*/
protected BCLBiome(ResourceLocation biomeID) {
this(biomeID, BuiltinRegistries.BIOME.get(biomeID), null);
this(ResourceKey.create(Registry.BIOME_REGISTRY, biomeID), null);
}
/**
* Create wrapper for existing biome using biome instance from {@link BuiltinRegistries}.
*
* @param biome {@link Biome} to wrap.
* @param biomeToRegister {@link Biome} to wrap.
*/
protected BCLBiome(Biome biome) {
this(biome, null);
@Deprecated(forRemoval = true)
protected BCLBiome(Biome biomeToRegister) {
this(biomeToRegister, null);
}
/**
* Create wrapper for existing biome using biome instance from {@link BuiltinRegistries}.
*
* @param biome {@link Biome} to wrap.
* @param settings The Settings for this Biome or {@code null} if you want to apply default settings
* @param biomeToRegister {@link Biome} to wrap.
* @param settings The Settings for this Biome or {@code null} if you want to apply default settings
*/
protected BCLBiome(Biome biome, VanillaBiomeSettings settings) {
this(BiomeAPI.getBiomeID(biome), biome, settings);
@Deprecated(forRemoval = true)
protected BCLBiome(Biome biomeToRegister, VanillaBiomeSettings settings) {
this(BiomeAPI.getBiomeID(biomeToRegister), biomeToRegister, settings);
}
public BCLBiome(ResourceLocation biomeID, Biome biome) {
this(biomeID, biome, null);
/**
* Create wrapper for existing biome using biome instance from {@link BuiltinRegistries}.
*
* @param biomeToRegister {@link Biome} to wrap.
* @param biomeID Teh ResoureLocation for this Biome
*/
@Deprecated(forRemoval = true)
//this constructor should become package private and not get removed
public BCLBiome(ResourceLocation biomeID, Biome biomeToRegister) {
this(biomeID, biomeToRegister, null);
}
/**
* Create a new Biome
*
* @param biomeID {@link ResourceLocation} biome ID.
* @param biome {@link Biome} to wrap.
* @param biomeID {@link ResourceLocation} biome ID.
* @param biomeToRegister {@link Biome} to wrap.
* @param defaults The Settings for this Biome or null if you want to apply the defaults
*/
protected BCLBiome(ResourceLocation biomeID, Biome biomeToRegister, BCLBiomeSettings defaults) {
this(ResourceKey.create(Registry.BIOME_REGISTRY, biomeID), biomeToRegister, defaults);
}
/**
* Create a new Biome
*
* @param biomeKey {@link ResourceKey<Biome>} of the wrapped Biome
* @param defaults The Settings for this Biome or null if you want to apply the defaults
*/
protected BCLBiome(ResourceLocation biomeID, Biome biome, BCLBiomeSettings defaults) {
protected BCLBiome(ResourceKey<Biome> biomeKey, BCLBiomeSettings defaults) {
this(biomeKey, null, defaults);
}
/**
* Create a new Biome
*
* @param biomeKey {@link ResourceKey<Biome>} of the wrapped Biome
* @param biomeToRegister The biome you want to use when this instance gets registered through the {@link BiomeAPI}
* @param defaults The Settings for this Biome or null if you want to apply the defaults
*/
protected BCLBiome(ResourceKey<Biome> biomeKey, Biome biomeToRegister, BCLBiomeSettings defaults) {
this.biomeToRegister = biomeToRegister;
this.subbiomes.add(this, 1.0F);
this.biomeID = biomeID;
this.biome = biome;
this.biomeID = biomeKey.location();
this.biomeKey = biomeKey;
if (defaults != null) {
defaults.applyWithDefaults(this);
}
}
/**
* Changes the intended Type for this Biome
*
* @param type the new type
* @return the same instance
*/
protected BCLBiome setIntendedType(BiomeAPI.BiomeType type) {
return _setIntendedType(type);
}
BCLBiome _setIntendedType(BiomeAPI.BiomeType type) {
this.intendedType = type;
return this;
}
public BiomeAPI.BiomeType getIntendedType() {
return this.intendedType;
}
/**
* Get current biome edge.
*
@ -114,6 +316,22 @@ public class BCLBiome extends BCLBiomeSettings {
return this;
}
/**
* Set biome edge for this biome instance. If there is already an edge, the
* biome is added as subBiome to the current edge-biome
*
* @param edge The new edge
* @return same {@link BCLBiome}.
*/
public BCLBiome addEdge(BCLBiome edge) {
if (this.edge != null) {
this.edge.addSubBiome(edge);
} else {
this.setEdge(edge);
}
return this;
}
/**
* Adds sub-biome into this biome instance. Biome chance will be interpreted as a sub-biome generation chance.
* Biome itself has chance 1.0 compared to all its sub-biomes.
@ -187,16 +405,30 @@ public class BCLBiome extends BCLBiomeSettings {
*
* @return {@link Biome}.
*/
@Deprecated(forRemoval = true)
public Biome getBiome() {
return biome;
if (biomeToRegister != null) return biomeToRegister;
return BiomeAPI.getFromBuiltinRegistry(biomeKey).value();
}
/**
* Getter for biomeKey
*
* @return {@link ResourceKey<Biome>}.
*/
public ResourceKey<Biome> getBiomeKey() {
return biomeKey;
}
public ResourceKey<BCLBiome> getBCLBiomeKey() {
return ResourceKey.create(BCLBiomeRegistry.BCL_BIOMES_REGISTRY, biomeID);
}
/**
* For internal use from BiomeAPI only
*/
void afterRegistration() {
ResourceKey<Biome> key = BuiltinRegistries.BIOME.getResourceKey(getBiome()).orElseThrow();
this.biomeTags.forEach(tagKey -> TagManager.BIOMES.add(tagKey, biome));
}
@ -233,6 +465,7 @@ public class BCLBiome extends BCLBiomeSettings {
* @param obj any data to add.
* @return same {@link BCLBiome}.
*/
@Deprecated(forRemoval = true)
public BCLBiome addCustomData(String name, Object obj) {
customData.put(name, obj);
return this;
@ -244,6 +477,7 @@ public class BCLBiome extends BCLBiomeSettings {
* @param data a {@link Map} with custom data.
* @return same {@link BCLBiome}.
*/
@Deprecated(forRemoval = true)
public BCLBiome addCustomData(Map<String, Object> data) {
customData.putAll(data);
return this;
@ -268,13 +502,6 @@ public class BCLBiome extends BCLBiomeSettings {
return biomeID.toString();
}
/**
* Adds structures to this biome. For internal use only.
* Used inside {@link BCLBiomeBuilder}.
*/
void addBiomeTags(Set<TagKey<Biome>> tags) {
biomeTags.addAll(tags);
}
/**
* Adds structures to this biome. For internal use only.

View file

@ -10,6 +10,7 @@ import org.betterx.bclib.util.ColorUtil;
import org.betterx.bclib.util.Pair;
import org.betterx.bclib.util.TriFunction;
import org.betterx.worlds.together.surfaceRules.SurfaceRuleRegistry;
import org.betterx.worlds.together.tag.v3.TagManager;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
@ -53,6 +54,7 @@ public class BCLBiomeBuilder {
public interface BiomeSupplier<T> extends TriFunction<ResourceLocation, Biome, BCLBiomeSettings, T> {
}
private static final BCLBiomeBuilder INSTANCE = new BCLBiomeBuilder();
private static final SurfaceRules.ConditionSource SURFACE_NOISE = SurfaceRules.noiseCondition(
Noises.SOUL_SAND_LAYER,
@ -72,7 +74,6 @@ public class BCLBiomeBuilder {
private final List<Climate.ParameterPoint> parameters = Lists.newArrayList();
//BiomeTags.IS_NETHER
private float temperature;
private float fogDensity;
private float genChance;
@ -82,6 +83,8 @@ public class BCLBiomeBuilder {
private BCLBiome edge;
private boolean vertical;
private BiomeAPI.BiomeType biomeType;
/**
* Starts new biome building process.
@ -106,6 +109,7 @@ public class BCLBiomeBuilder {
INSTANCE.carvers.clear();
INSTANCE.parameters.clear();
INSTANCE.tags.clear();
INSTANCE.biomeType = null;
return INSTANCE;
}
@ -114,6 +118,17 @@ public class BCLBiomeBuilder {
return this;
}
/**
* Set the type for this Biome. If the type was set, the Biome can be registered.
*
* @param type selected Type
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder type(BiomeAPI.BiomeType type) {
this.biomeType = type;
return this;
}
/**
* Set biome {@link Precipitation}. Affect biome visual effects (rain, snow, none).
*
@ -695,6 +710,64 @@ public class BCLBiomeBuilder {
return this;
}
/**
* Changes the type for the Biome. The intended Type defines in which Dimension a
* Biome is allowed to spawn. Currently each Biome can only spawn in one dimension
*
* @param type The intended type
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder intendedType(BiomeAPI.BiomeType type) {
this.biomeType = type;
return this;
}
/**
* Changes the intended type for the Biome to an EndLand Biome
*
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder endLandBiome() {
return intendedType(BiomeAPI.BiomeType.BCL_END_LAND);
}
/**
* Changes the intended type for the Biome to an EndVoid (aka small islands) Biome
*
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder endVoidBiome() {
return intendedType(BiomeAPI.BiomeType.BCL_END_VOID);
}
/**
* Changes the intended type for the Biome to an Endbarrens Biome
*
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder endBarrensBiome() {
return intendedType(BiomeAPI.BiomeType.BCL_END_BARRENS);
}
/**
* Changes the intended type for the Biome to an End Center Island Biome
*
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder endCenterBiome() {
return intendedType(BiomeAPI.BiomeType.BCL_END_CENTER);
}
/**
* Changes the intended type for the Biome to a Nether Biome
*
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder netherBiome() {
return intendedType(BiomeAPI.BiomeType.BCL_NETHER);
}
public BCLBiomeBuilder tag(TagKey<Biome>... tag) {
for (TagKey<Biome> t : tag) {
tags.add(t);
@ -724,26 +797,6 @@ public class BCLBiomeBuilder {
return this;
}
/**
* Finalize biome creation.
*
* @return created {@link BCLBiome} instance.
*/
public BCLBiome build() {
return build((BiomeSupplier<BCLBiome>) BCLBiome::new);
}
/**
* Finalize biome creation.
*
* @param biomeConstructor {@link BiFunction} biome constructor.
* @return created {@link BCLBiome} instance.
* @deprecated Replaced with {@link #build(BiomeSupplier)}
*/
@Deprecated(forRemoval = true)
public <T extends BCLBiome> T build(BiFunction<ResourceLocation, Biome, T> biomeConstructor) {
return build((id, biome, settings) -> biomeConstructor.apply(id, biome));
}
private static BiomeGenerationSettings fixGenerationSettings(BiomeGenerationSettings settings) {
//Fabric Biome Modification API can not handle an empty carver map, thus we will create one with
@ -760,43 +813,6 @@ public class BCLBiomeBuilder {
return settings;
}
/**
* Finalize biome creation.
*
* @param biomeConstructor {@link BiomeSupplier} biome constructor.
* @return created {@link BCLBiome} instance.
*/
public <T extends BCLBiome> T build(BiomeSupplier<T> biomeConstructor) {
BiomeBuilder builder = new BiomeBuilder()
.precipitation(precipitation)
.temperature(temperature)
.downfall(downfall);
builder.mobSpawnSettings(getSpawns().build());
builder.specialEffects(getEffects().build());
builder.generationSettings(fixGenerationSettings(getGeneration().build()));
BCLBiomeSettings settings = BCLBiomeSettings.createBCL()
.setTerrainHeight(height)
.setFogDensity(fogDensity)
.setGenChance(genChance)
.setEdgeSize(edgeSize)
.setEdge(edge)
.setVertical(vertical)
.build();
final Biome biome = builder.build();
final T res = biomeConstructor.apply(biomeID, biome, settings);
res.addBiomeTags(tags);
//res.setSurface(surfaceRule);
SurfaceRuleRegistry.registerRule(biomeID, surfaceRule, biomeID);
res.addClimateParameters(parameters);
//carvers.forEach(cfg -> BiomeAPI.addBiomeCarver(biome, cfg.second, cfg.first));
return res;
}
/**
* Get or create {@link BiomeSpecialEffects.Builder} for biome visual effects.
@ -837,4 +853,67 @@ public class BCLBiomeBuilder {
}
return generationSettings;
}
/**
* Finalize biome creation.
*
* @return created {@link BCLBiome} instance.
*/
public BCLBiome build() {
return build((BiomeSupplier<BCLBiome>) BCLBiome::new);
}
/**
* Finalize biome creation.
*
* @param biomeConstructor {@link BiFunction} biome constructor.
* @return created {@link BCLBiome} instance.
* @deprecated Replaced with {@link #build(BiomeSupplier)}
*/
@Deprecated(forRemoval = true)
public <T extends BCLBiome> T build(BiFunction<ResourceLocation, Biome, T> biomeConstructor) {
return build((id, biome, settings) -> biomeConstructor.apply(id, biome));
}
/**
* Finalize biome creation.
*
* @param biomeConstructor {@link BiomeSupplier} biome constructor.
* @return created {@link BCLBiome} instance.
*/
public <T extends BCLBiome> T build(BiomeSupplier<T> biomeConstructor) {
BiomeBuilder builder = new BiomeBuilder()
.precipitation(precipitation)
.temperature(temperature)
.downfall(downfall);
builder.mobSpawnSettings(getSpawns().build());
builder.specialEffects(getEffects().build());
builder.generationSettings(fixGenerationSettings(getGeneration().build()));
BCLBiomeSettings settings = BCLBiomeSettings.createBCL()
.setTerrainHeight(height)
.setFogDensity(fogDensity)
.setGenChance(genChance)
.setEdgeSize(edgeSize)
.setEdge(edge)
.setVertical(vertical)
.build();
final Biome biome = builder.build();
final T res = biomeConstructor.apply(biomeID, biome, settings);
tags.forEach(tagKey -> TagManager.BIOMES.add(tagKey, res.getBiomeKey()));
//res.addBiomeTags(tags);
//res.setSurface(surfaceRule);
SurfaceRuleRegistry.registerRule(biomeID, surfaceRule, biomeID);
res.addClimateParameters(parameters);
if (biomeType != null)
res._setIntendedType(biomeType);
//carvers.forEach(cfg -> BiomeAPI.addBiomeCarver(biome, cfg.second, cfg.first));
return res;
}
}

View file

@ -0,0 +1,145 @@
package org.betterx.bclib.api.v2.levelgen.biomes;
import org.betterx.bclib.BCLib;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.world.event.WorldBootstrap;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.world.level.biome.Biomes;
import java.util.Optional;
import java.util.stream.Stream;
import org.jetbrains.annotations.ApiStatus;
public class BCLBiomeRegistry {
public static final ResourceKey<Registry<BCLBiome>> BCL_BIOMES_REGISTRY =
createRegistryKey(WorldsTogether.makeID("worldgen/betterx/biome"));
public static final ResourceKey<Registry<Codec<? extends BCLBiome>>> BCL_BIOME_CODEC_REGISTRY =
createRegistryKey(WorldsTogether.makeID("worldgen/betterx/biome_codec"));
public static Registry<Codec<? extends BCLBiome>> BIOME_CODECS = Registry.registerSimple(
BCL_BIOME_CODEC_REGISTRY,
BCLBiomeRegistry::bootstrapCodecs
);
public static Registry<BCLBiome> BUILTIN_BCL_BIOMES = new MappedRegistry<>(
BCL_BIOMES_REGISTRY,
Lifecycle.stable(), null
);
/**
* Empty biome used as default value if requested biome doesn't exist or linked. Shouldn't be registered anywhere to prevent bugs.
* Have {@code Biomes.THE_VOID} as the reference biome.
**/
public static final BCLBiome EMPTY_BIOME = new BCLBiome(Biomes.THE_VOID.location());
public static Codec<? extends BCLBiome> registerBiomeCodec(
ResourceLocation location,
KeyDispatchDataCodec<? extends BCLBiome> codec
) {
Registry.register(BIOME_CODECS, location, codec.codec());
return codec.codec();
}
public static ResourceKey<BCLBiome> register(BCLBiome biome) {
Registry.register(BUILTIN_BCL_BIOMES, biome.getBCLBiomeKey(), biome);
return biome.getBCLBiomeKey();
}
private static <T> ResourceKey<Registry<T>> createRegistryKey(ResourceLocation location) {
return ResourceKey.createRegistryKey(location);
}
private static Codec<? extends BCLBiome> bootstrapCodecs(Registry<Codec<? extends BCLBiome>> registry) {
return Registry.register(registry, BCLib.makeID("biome"), BCLBiome.KEY_CODEC.codec());
}
@ApiStatus.Internal
public static Holder<BCLBiome> bootstrap(Registry<BCLBiome> registry) {
BuiltinRegistries.register(registry, BiomeAPI.SMALL_END_ISLANDS.getBCLBiomeKey(), BiomeAPI.SMALL_END_ISLANDS);
BuiltinRegistries.register(registry, BiomeAPI.END_BARRENS.getBCLBiomeKey(), BiomeAPI.END_BARRENS);
BuiltinRegistries.register(registry, BiomeAPI.END_HIGHLANDS.getBCLBiomeKey(), BiomeAPI.END_HIGHLANDS);
BuiltinRegistries.register(registry, BiomeAPI.END_MIDLANDS.getBCLBiomeKey(), BiomeAPI.END_MIDLANDS);
BuiltinRegistries.register(registry, BiomeAPI.THE_END.getBCLBiomeKey(), BiomeAPI.THE_END);
BuiltinRegistries.register(
registry,
BiomeAPI.BASALT_DELTAS_BIOME.getBCLBiomeKey(),
BiomeAPI.BASALT_DELTAS_BIOME
);
BuiltinRegistries.register(
registry,
BiomeAPI.SOUL_SAND_VALLEY_BIOME.getBCLBiomeKey(),
BiomeAPI.SOUL_SAND_VALLEY_BIOME
);
BuiltinRegistries.register(
registry,
BiomeAPI.WARPED_FOREST_BIOME.getBCLBiomeKey(),
BiomeAPI.WARPED_FOREST_BIOME
);
BuiltinRegistries.register(
registry,
BiomeAPI.CRIMSON_FOREST_BIOME.getBCLBiomeKey(),
BiomeAPI.CRIMSON_FOREST_BIOME
);
BuiltinRegistries.register(
registry,
BiomeAPI.NETHER_WASTES_BIOME.getBCLBiomeKey(),
BiomeAPI.NETHER_WASTES_BIOME
);
return BuiltinRegistries.register(registry, EMPTY_BIOME.getBCLBiomeKey(), EMPTY_BIOME);
}
public static BCLBiome get(ResourceLocation loc) {
return get(WorldBootstrap.getLastRegistryAccessOrElseBuiltin(), loc);
}
public static BCLBiome get(RegistryAccess access, ResourceLocation loc) {
return getBclBiomesRegistry(access).get(loc);
}
public static BCLBiome getOrElseEmpty(ResourceLocation loc) {
return getOrElseEmpty(WorldBootstrap.getLastRegistryAccessOrElseBuiltin(), loc);
}
public static BCLBiome getOrElseEmpty(RegistryAccess access, ResourceLocation loc) {
BCLBiome res = get(access, loc);
if (res == null) return EMPTY_BIOME;
return res;
}
public static Stream<ResourceKey<BCLBiome>> getAll(BiomeAPI.BiomeType dim) {
return getAll(WorldBootstrap.getLastRegistryAccessOrElseBuiltin(), dim);
}
public static Stream<ResourceKey<BCLBiome>> getAll(RegistryAccess access, BiomeAPI.BiomeType dim) {
return getBclBiomesRegistry(access)
.entrySet()
.stream()
.filter(e -> e.getValue().getIntendedType().is(BiomeAPI.BiomeType.END))
.map(e -> e.getKey());
}
private static Registry<BCLBiome> getBclBiomesRegistry(RegistryAccess access) {
if (access != null) {
return ((Optional<Registry<BCLBiome>>) access
.registry(BCLBiomeRegistry.BCL_BIOMES_REGISTRY))
.orElse(BUILTIN_BCL_BIOMES);
} else {
return BUILTIN_BCL_BIOMES;
}
}
public static void ensureStaticallyLoaded() {
}
}

View file

@ -103,6 +103,22 @@ public class BCLBiomeSettings {
}
}
BCLBiomeSettings(
float terrainHeight,
float fogDensity,
float genChance,
int edgeSize,
boolean vertical,
BCLBiome edge
) {
this.terrainHeight = terrainHeight;
this.fogDensity = fogDensity;
this.genChance = genChance;
this.edgeSize = edgeSize;
this.vertical = vertical;
this.edge = edge;
}
protected BCLBiomeSettings() {
this.terrainHeight = 0.1F;
this.fogDensity = 1.0F;

View file

@ -8,8 +8,10 @@ import org.betterx.bclib.mixin.common.MobSpawnSettingsAccessor;
import org.betterx.bclib.util.CollectionsUtil;
import org.betterx.worlds.together.tag.v3.CommonBiomeTags;
import org.betterx.worlds.together.tag.v3.TagManager;
import org.betterx.worlds.together.world.event.WorldBootstrap;
import net.minecraft.client.Minecraft;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
@ -26,7 +28,6 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData;
import net.minecraft.world.level.block.state.BlockState;
@ -38,52 +39,142 @@ import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.biome.v1.NetherBiomes;
import net.fabricmc.fabric.api.biome.v1.TheEndBiomes;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BiomeAPI {
public static class BiomeType {
public static final Codec<BiomeType> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.STRING.fieldOf("name")
.orElse("undefined")
.forGetter(o -> o.name)
).apply(instance, BiomeType::create));
public static final Codec<BiomeType> CODEC = RecordCodecBuilder.create(instance -> instance
.group(
Codec.STRING.fieldOf("name")
.orElse("undefined")
.forGetter(o -> o.name),
Codec.STRING.fieldOf("parent")
.orElse("none")
.forGetter(o -> o.parentOrNull == null ? "none" : o.parentOrNull.name)
).apply(instance, BiomeType::create));
private static final Map<String, BiomeType> KNOWN_TYPES = new HashMap<>();
public static final BiomeType NONE = new BiomeType("NONE");
public static final BiomeType OVERWORLD = new BiomeType("OVERWORLD");
public static final BiomeType NETHER = new BiomeType("NETHER");
public static final BiomeType BCL_NETHER = new BiomeType("BCL_NETHER", NETHER);
public static final BiomeType OTHER_NETHER = new BiomeType("OTHER_NETHER", NETHER);
public static final BiomeType BCL_NETHER = new BiomeType("BCL_NETHER", NETHER, (biome, ignored) -> {
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
biome.forEachClimateParameter(p -> NetherBiomes.addNetherBiome(key, p));
}
});
public static final BiomeType END = new BiomeType("END");
public static final BiomeType END_IGNORE = new BiomeType("END_IGNORE", END);
public static final BiomeType END_LAND = new BiomeType("END_LAND", END);
public static final BiomeType END_VOID = new BiomeType("END_VOID", END);
public static final BiomeType END_CENTER = new BiomeType("END_CENTER", END);
public static final BiomeType BCL_END_LAND = new BiomeType("BCL_END_LAND", END_LAND);
public static final BiomeType BCL_END_VOID = new BiomeType("BCL_END_VOID", END_VOID);
public static final BiomeType OTHER_END_LAND = new BiomeType("OTHER_END_LAND", END_LAND);
public static final BiomeType OTHER_END_VOID = new BiomeType("OTHER_END_VOID", END_VOID);
public static final BiomeType END_BARRENS = new BiomeType("END_BARRENS", END);
public static final BiomeType BCL_END_LAND = new BiomeType("BCL_END_LAND", END_LAND, (biome, ignored) -> {
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (biome.isEdgeBiome()) {
ResourceKey<Biome> parentKey = biome.getParentBiome().getBiomeKey();
TheEndBiomes.addMidlandsBiome(parentKey, key, weight);
} else {
TheEndBiomes.addHighlandsBiome(key, weight);
}
});
public static final BiomeType BCL_END_VOID = new BiomeType("BCL_END_VOID", END_VOID, (biome, ignored) -> {
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
TheEndBiomes.addSmallIslandsBiome(key, weight);
}
});
public static final BiomeType BCL_END_CENTER = new BiomeType("BCL_END_CENTER", END_CENTER, (biome, ignored) -> {
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
TheEndBiomes.addMainIslandBiome(key, weight);
}
});
public static final BiomeType BCL_END_BARRENS = new BiomeType(
"BCL_END_BARRENS",
END_BARRENS,
(biome, highlandBiome) -> {
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
ResourceKey<Biome> parentKey = highlandBiome.getBiomeKey();
TheEndBiomes.addBarrensBiome(parentKey, key, weight);
}
}
);
static final Map<ResourceLocation, BiomeType> BIOME_TYPE_MAP = Maps.newHashMap();
public final BiomeType parentOrNull;
private final String debugName;
private final String name;
public BiomeType(String debugName) {
this(debugName, null);
@FunctionalInterface
interface ExtraRegisterTaks {
void register(@NotNull BCLBiome biome, @Nullable BCLBiome parent);
}
public BiomeType(String debugName, BiomeType parentOrNull) {
final ExtraRegisterTaks extraRegisterTask;
private static BiomeType create(String name, String parentOrNull) {
BiomeType known = KNOWN_TYPES.get(name);
BiomeType parent = parentOrNull == null || "none".equals(parentOrNull)
? null
: KNOWN_TYPES.get(parentOrNull);
if (known != null) {
if (known.parentOrNull != parent) {
BCLib.LOGGER.warning("BiomeType " + name + " was deserialized with parent " + parent + " but already has " + known.parentOrNull);
}
return known;
}
return new BiomeType(name, parent);
}
static BiomeType create(String name) {
BiomeType known = KNOWN_TYPES.get(name);
if (known != null) {
return known;
}
return NONE;
}
public BiomeType(String name) {
this(name, null);
}
public BiomeType(String name, BiomeType parentOrNull) {
this(name, parentOrNull, (b, a) -> {
});
}
public BiomeType(String name, BiomeType parentOrNull, ExtraRegisterTaks extraRegisterTask) {
this.parentOrNull = parentOrNull;
this.debugName = debugName;
this.name = name;
this.extraRegisterTask = extraRegisterTask;
KNOWN_TYPES.put(name, this);
}
public boolean is(BiomeType d) {
@ -92,44 +183,101 @@ public class BiomeAPI {
return false;
}
public String getName() {
return name;
}
@Override
public String toString() {
String str = debugName;
String str = name;
if (parentOrNull != null) str += " -> " + parentOrNull;
return str;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BiomeType biomeType = (BiomeType) o;
return name.equals(biomeType.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
/**
* Empty biome used as default value if requested biome doesn't exist or linked. Shouldn't be registered anywhere to prevent bugs.
* Have {@code Biomes.THE_VOID} as the reference biome.
*
* @deprecated use {@link BCLBiomeRegistry#EMPTY_BIOME} instead
*/
public static final BCLBiome EMPTY_BIOME = new BCLBiome(Biomes.THE_VOID.location());
public static final BCLBiome EMPTY_BIOME = BCLBiomeRegistry.EMPTY_BIOME;
private static final Map<ResourceLocation, BCLBiome> ID_MAP = Maps.newHashMap();
public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES).value());
public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST).value());
public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST).value());
public static final BCLBiome SOUL_SAND_VALLEY_BIOME = registerNetherBiome(getFromRegistry(Biomes.SOUL_SAND_VALLEY).value());
public static final BCLBiome BASALT_DELTAS_BIOME = registerNetherBiome(getFromRegistry(Biomes.BASALT_DELTAS).value());
public static final BCLBiome THE_END = registerCenterBiome(getFromRegistry(Biomes.THE_END));
public static final BCLBiome END_MIDLANDS = registerSubBiome(
THE_END,
getFromRegistry(Biomes.END_MIDLANDS).value(),
0.5F
public static final BCLBiome NETHER_WASTES_BIOME = InternalBiomeAPI.wrapNativeBiome(
Biomes.NETHER_WASTES,
InternalBiomeAPI.OTHER_NETHER
);
public static final BCLBiome END_HIGHLANDS = registerSubBiome(
THE_END,
getFromRegistry(Biomes.END_HIGHLANDS).value(),
0.5F
public static final BCLBiome CRIMSON_FOREST_BIOME = InternalBiomeAPI.wrapNativeBiome(
Biomes.CRIMSON_FOREST,
InternalBiomeAPI.OTHER_NETHER
);
public static final BCLBiome WARPED_FOREST_BIOME = InternalBiomeAPI.wrapNativeBiome(
Biomes.WARPED_FOREST,
InternalBiomeAPI.OTHER_NETHER
);
public static final BCLBiome SOUL_SAND_VALLEY_BIOME = InternalBiomeAPI.wrapNativeBiome(
Biomes.SOUL_SAND_VALLEY,
InternalBiomeAPI.OTHER_NETHER
);
public static final BCLBiome BASALT_DELTAS_BIOME = InternalBiomeAPI.wrapNativeBiome(
Biomes.BASALT_DELTAS,
InternalBiomeAPI.OTHER_NETHER
);
public static final BCLBiome END_BARRENS = registerEndBiome(getFromRegistry(new ResourceLocation("end_barrens")));
public static final BCLBiome SMALL_END_ISLANDS = registerEndVoidBiome(getFromRegistry(new ResourceLocation(
"small_end_islands")));
public static final BCLBiome THE_END = InternalBiomeAPI.wrapNativeBiome(
Biomes.THE_END,
0.5F,
InternalBiomeAPI.OTHER_END_CENTER
);
public static final BCLBiome END_MIDLANDS = InternalBiomeAPI.wrapNativeBiome(
Biomes.END_MIDLANDS,
0.5F,
InternalBiomeAPI.OTHER_END_LAND
);
public static final BCLBiome END_HIGHLANDS = InternalBiomeAPI.wrapNativeBiome(
Biomes.END_HIGHLANDS,
END_MIDLANDS,
8,
0.5F,
InternalBiomeAPI.OTHER_END_LAND
);
public static final BCLBiome END_BARRENS = InternalBiomeAPI.wrapNativeBiome(
Biomes.END_BARRENS,
InternalBiomeAPI.OTHER_END_BARRENS
);
public static final BCLBiome SMALL_END_ISLANDS = InternalBiomeAPI.wrapNativeBiome(
Biomes.SMALL_END_ISLANDS,
InternalBiomeAPI.OTHER_END_VOID
);
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
*
* @param bclbiome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerBiome(BCLBiome bclbiome) {
return registerBiome(bclbiome, BuiltinRegistries.BIOME);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
@ -138,20 +286,46 @@ public class BiomeAPI {
* @param dim The Dimension fo rthis Biome
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
public static BCLBiome registerBiome(BCLBiome bclbiome, BiomeType dim) {
if (BuiltinRegistries.BIOME.get(bclbiome.getID()) == null) {
final Biome biome = bclbiome.getBiome();
ResourceLocation loc = bclbiome.getID();
Registry.register(BuiltinRegistries.BIOME, loc, biome);
return registerBiome(bclbiome, dim, BuiltinRegistries.BIOME);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
*
* @param bclbiome {@link BCLBiome}
* @param dim The Dimension fo rthis Biome
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
static BCLBiome registerBiome(BCLBiome bclbiome, BiomeType dim, Registry<Biome> registryOrNull) {
bclbiome._setIntendedType(dim);
return registerBiome(bclbiome, registryOrNull);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
*
* @param bclbiome {@link BCLBiome}
* @return {@link BCLBiome}
*/
static BCLBiome registerBiome(BCLBiome bclbiome, Registry<Biome> registryOrNull) {
BiomeType dim = bclbiome.getIntendedType();
if (registryOrNull != null
&& bclbiome.biomeToRegister != null
&& registryOrNull.get(bclbiome.getID()) == null) {
Registry.register(registryOrNull, bclbiome.getBiomeKey(), bclbiome.biomeToRegister);
BCLBiomeRegistry.register(bclbiome);
}
ID_MAP.put(bclbiome.getID(), bclbiome);
BiomeType.BIOME_TYPE_MAP.put(bclbiome.getID(), dim);
if (dim != null && dim.is(BiomeType.NETHER)) {
TagManager.BIOMES.add(BiomeTags.IS_NETHER, bclbiome.getBiome());
TagManager.BIOMES.add(CommonBiomeTags.IN_NETHER, bclbiome.getBiome());
TagManager.BIOMES.add(BiomeTags.IS_NETHER, bclbiome.getBiomeKey());
TagManager.BIOMES.add(CommonBiomeTags.IN_NETHER, bclbiome.getBiomeKey());
} else if (dim != null && dim.is(BiomeType.END)) {
TagManager.BIOMES.add(CommonBiomeTags.IN_END, bclbiome.getBiome());
TagManager.BIOMES.add(CommonBiomeTags.IN_END, bclbiome.getBiomeKey());
TagManager.BIOMES.add(CommonBiomeTags.IN_END, bclbiome.getBiomeKey());
}
bclbiome.afterRegistration();
@ -163,7 +337,7 @@ public class BiomeAPI {
return registerSubBiome(
parent,
subBiome,
BiomeType.BIOME_TYPE_MAP.getOrDefault(parent.getID(), BiomeType.NONE)
parent.getIntendedType()
);
}
@ -172,7 +346,7 @@ public class BiomeAPI {
parent,
subBiome,
genChance,
BiomeType.BIOME_TYPE_MAP.getOrDefault(parent.getID(), BiomeType.NONE)
parent.getIntendedType()
);
}
@ -188,36 +362,6 @@ public class BiomeAPI {
return registerSubBiome(parent, subBiome, dim);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API.
*
* @param bclBiome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerNetherBiome(BCLBiome bclBiome) {
registerBiome(bclBiome, BiomeType.BCL_NETHER);
ResourceKey<Biome> key = getBiomeKey(bclBiome.getBiome());
if (bclBiome.allowFabricRegistration()) {
bclBiome.forEachClimateParameter(p -> NetherBiomes.addNetherBiome(key, p));
}
return bclBiome;
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API.
*
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerNetherBiome(Biome biome) {
BCLBiome bclBiome = new BCLBiome(biome, null);
registerBiome(bclBiome, BiomeType.OTHER_NETHER);
return bclBiome;
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
@ -229,49 +373,18 @@ public class BiomeAPI {
registerBiome(biome, BiomeType.BCL_END_LAND);
float weight = biome.getGenChance();
ResourceKey<Biome> key = getBiomeKey(biome.getBiome());
if (biome.allowFabricRegistration()) {
ResourceKey<Biome> key = biome.getBiomeKey();
if (biome.isEdgeBiome()) {
ResourceKey<Biome> parentKey = biome.getParentBiome().getBiomeKey();
TheEndBiomes.addMidlandsBiome(parentKey, key, weight);
} else {
TheEndBiomes.addHighlandsBiome(key, weight);
TheEndBiomes.addMidlandsBiome(key, key, weight);
if (biome.isEdgeBiome()) {
ResourceKey<Biome> parentKey = getBiomeKey(biome.getParentBiome().getBiome());
TheEndBiomes.addMidlandsBiome(parentKey, key, weight);
}
}
return biome;
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerEndLandBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
registerBiome(bclBiome, BiomeType.OTHER_END_LAND);
return bclBiome;
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biome {@link BCLBiome};
* @param genChance float generation chance.
* @return {@link BCLBiome}
*/
public static BCLBiome registerEndLandBiome(Holder<Biome> biome, float genChance) {
BCLBiome bclBiome = new BCLBiome(
biome.value(),
VanillaBiomeSettings.createVanilla().setGenChance(genChance).build()
);
registerBiome(bclBiome, BiomeType.OTHER_END_LAND);
return bclBiome;
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
@ -284,8 +397,8 @@ public class BiomeAPI {
registerBiome(biome, BiomeType.BCL_END_VOID);
float weight = biome.getGenChance();
ResourceKey<Biome> key = getBiomeKey(biome.getBiome());
if (biome.allowFabricRegistration()) {
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
TheEndBiomes.addSmallIslandsBiome(key, weight);
}
return biome;
@ -293,61 +406,78 @@ public class BiomeAPI {
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands).
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a center island
* biome (will generate only on the center island).
*
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerEndVoidBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
public static BCLBiome registerEndCenterBiome(BCLBiome biome) {
registerBiome(biome, BiomeType.BCL_END_CENTER);
registerBiome(bclBiome, BiomeType.END_VOID);
return bclBiome;
}
public static BCLBiome registerEndBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
registerBiome(bclBiome, BiomeType.END);
return bclBiome;
}
public static BCLBiome registerCenterBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
registerBiome(bclBiome, BiomeType.END_CENTER);
return bclBiome;
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
TheEndBiomes.addMainIslandBiome(key, weight);
}
return biome;
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands).
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a barrens island
* biome (will generate on the edge of midland biomes on the larger islands).
*
* @param biome {@link BCLBiome}.
* @param genChance float generation chance.
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerEndVoidBiome(Holder<Biome> biome, float genChance) {
BCLBiome bclBiome = new BCLBiome(
biome.value(),
VanillaBiomeSettings.createVanilla().setGenChance(genChance).build()
);
public static BCLBiome registerEndBarrensBiome(BCLBiome highlandBiome, BCLBiome biome) {
registerBiome(biome, BiomeType.BCL_END_BARRENS);
registerBiome(bclBiome, BiomeType.END_VOID);
float weight = biome.getGenChance();
ResourceKey<Biome> key = biome.getBiomeKey();
if (!biome.isEdgeBiome()) {
ResourceKey<Biome> parentKey = highlandBiome.getBiomeKey();
TheEndBiomes.addBarrensBiome(parentKey, key, weight);
}
return biome;
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API.
*
* @param bclBiome {@link BCLBiome}
* @return {@link BCLBiome}
*/
public static BCLBiome registerNetherBiome(BCLBiome bclBiome) {
registerBiome(bclBiome, BiomeType.BCL_NETHER);
ResourceKey<Biome> key = bclBiome.getBiomeKey();
if (!bclBiome.isEdgeBiome()) {
bclBiome.forEachClimateParameter(p -> NetherBiomes.addNetherBiome(key, p));
}
return bclBiome;
}
/**
* Get {@link BCLBiome} from {@link Biome} instance on server. Used to convert world biomes to BCLBiomes.
*
* @param biome - {@link Holder<Biome>} from world.
* @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}.
*/
@Deprecated(forRemoval = true)
public static BCLBiome getFromBiome(Holder<Biome> biome) {
if (InternalBiomeAPI.biomeRegistry == null) {
return EMPTY_BIOME;
return BCLBiomeRegistry.EMPTY_BIOME;
}
return ID_MAP.getOrDefault(biome.unwrapKey().orElseThrow().location(), EMPTY_BIOME);
return BCLBiomeRegistry
.getOrElseEmpty(
InternalBiomeAPI.registryAccess,
biome.unwrapKey().orElseThrow().location()
);
}
/**
@ -356,15 +486,15 @@ public class BiomeAPI {
* @param biome - {@link Biome} from client world.
* @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}.
*/
@Environment(EnvType.CLIENT)
public static BCLBiome getRenderBiome(Biome biome) {
BCLBiome endBiome = InternalBiomeAPI.CLIENT.get(biome);
if (endBiome == null) {
Minecraft minecraft = Minecraft.getInstance();
ResourceLocation id = minecraft.level.registryAccess()
.registryOrThrow(Registry.BIOME_REGISTRY)
.getKey(biome);
endBiome = id == null ? EMPTY_BIOME : ID_MAP.getOrDefault(id, EMPTY_BIOME);
ResourceLocation id = WorldBootstrap.getLastRegistryAccessOrElseBuiltin()
.registryOrThrow(Registry.BIOME_REGISTRY)
.getKey(biome);
endBiome = id == null
? BCLBiomeRegistry.EMPTY_BIOME
: BCLBiomeRegistry.getOrElseEmpty(id);
InternalBiomeAPI.CLIENT.put(biome, endBiome);
}
return endBiome;
@ -404,7 +534,7 @@ public class BiomeAPI {
if (id == null) {
BCLib.LOGGER.error("Unable to get ID for " + biome + ". Falling back to empty Biome...");
id = EMPTY_BIOME.getID();
id = BCLBiomeRegistry.EMPTY_BIOME.getID();
}
return id;
@ -417,11 +547,10 @@ public class BiomeAPI {
* @return biome {@link ResourceLocation}.
*/
public static ResourceLocation getBiomeID(Holder<Biome> biome) {
var oKey = biome.unwrapKey();
if (oKey.isPresent()) {
return oKey.get().location();
}
return null;
return biome
.unwrapKey()
.map(h -> h.location())
.orElse(null);
}
public static ResourceKey getBiomeKey(Holder<Biome> biome) {
@ -433,23 +562,29 @@ public class BiomeAPI {
}
public static Holder<Biome> getBiomeHolder(BCLBiome biome) {
return getBiomeHolder(biome.getBiome());
return getBiomeHolder(biome.getBiomeKey());
}
public static Holder<Biome> getBiomeHolder(Biome biome) {
Optional<ResourceKey<Biome>> key = Optional.empty();
if (InternalBiomeAPI.biomeRegistry != null) {
Optional<ResourceKey<Biome>> key = InternalBiomeAPI.biomeRegistry.getResourceKey(biome);
if (key.isPresent()) return InternalBiomeAPI.biomeRegistry.getOrCreateHolder(key.get());
key = InternalBiomeAPI.biomeRegistry.getResourceKey(biome);
} else {
key = BuiltinRegistries.BIOME.getResourceKey(biome);
}
return BuiltinRegistries.BIOME.getOrCreateHolder(BiomeAPI.getBiomeKey(biome));
return getBiomeHolder(key.orElseThrow());
}
public static Holder<Biome> getBiomeHolder(ResourceKey<Biome> biomeKey) {
if (InternalBiomeAPI.biomeRegistry != null) {
return InternalBiomeAPI.biomeRegistry.getOrCreateHolderOrThrow(biomeKey);
}
return BuiltinRegistries.BIOME.getOrCreateHolderOrThrow(biomeKey);
}
public static Holder<Biome> getBiomeHolder(ResourceLocation biome) {
if (InternalBiomeAPI.biomeRegistry != null) {
return getBiomeHolder(InternalBiomeAPI.biomeRegistry.get(biome));
}
return getBiomeHolder(BuiltinRegistries.BIOME.get(biome));
return getBiomeHolder(ResourceKey.create(Registry.BIOME_REGISTRY, biome));
}
/**
@ -459,7 +594,8 @@ public class BiomeAPI {
* @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}.
*/
public static BCLBiome getBiome(ResourceLocation biomeID) {
return ID_MAP.getOrDefault(biomeID, EMPTY_BIOME);
if (biomeID == null) return BCLBiomeRegistry.EMPTY_BIOME;
return BCLBiomeRegistry.getOrElseEmpty(biomeID);
}
/**
@ -489,30 +625,54 @@ public class BiomeAPI {
* @return {@code true} if biome exists in API registry and {@code false} if not.
*/
public static boolean hasBiome(ResourceLocation biomeID) {
return ID_MAP.containsKey(biomeID);
return BCLBiomeRegistry.get(biomeID) != null;
}
@Nullable
public static Holder<Biome> getFromRegistry(ResourceLocation key) {
return BuiltinRegistries.BIOME.getHolder(ResourceKey.create(Registry.BIOME_REGISTRY, key)).orElseThrow();
public static Holder<Biome> getFromRegistry(ResourceLocation biomeID) {
if (InternalBiomeAPI.biomeRegistry != null)
return InternalBiomeAPI.biomeRegistry.getHolder(ResourceKey.create(Registry.BIOME_REGISTRY, biomeID))
.orElseThrow();
return getFromBuiltinRegistry(biomeID);
}
@Nullable
public static Holder<Biome> getFromRegistry(ResourceKey<Biome> key) {
return BuiltinRegistries.BIOME.getOrCreateHolder(key);
if (InternalBiomeAPI.biomeRegistry != null)
return InternalBiomeAPI.biomeRegistry.getHolder(key).orElseThrow();
return getFromBuiltinRegistry(key);
}
@Nullable
public static Holder<Biome> getFromBuiltinRegistry(ResourceLocation biomeID) {
return BuiltinRegistries.BIOME.getHolder(ResourceKey.create(Registry.BIOME_REGISTRY, biomeID)).orElse(null);
}
@Nullable
public static Holder<Biome> getFromBuiltinRegistry(ResourceKey<Biome> key) {
return BuiltinRegistries.BIOME.getHolder(key).orElse(null);
}
@Deprecated(forRemoval = true)
public static boolean registryContains(ResourceKey<Biome> key) {
if (InternalBiomeAPI.biomeRegistry != null)
return InternalBiomeAPI.biomeRegistry.containsKey(key);
return builtinRegistryContains(key);
}
@Nullable
@Deprecated(forRemoval = true)
public static boolean builtinRegistryContains(ResourceKey<Biome> key) {
return BuiltinRegistries.BIOME.containsKey(key);
}
public static boolean isDatapackBiome(ResourceLocation biomeID) {
return getFromRegistry(biomeID) == null;
return getFromBuiltinRegistry(biomeID) == null;
}
public static boolean wasRegisteredAs(ResourceLocation biomeID, BiomeType dim) {
if (BiomeType.BIOME_TYPE_MAP.containsKey(biomeID) && BiomeType.BIOME_TYPE_MAP.get(biomeID).is(dim)) return true;
BCLBiome biome = getBiome(biomeID);
if (biome != null && biome != BiomeAPI.EMPTY_BIOME && biome.getParentBiome() != null) {
return wasRegisteredAs(biome.getParentBiome().getID(), dim);
}
return false;
if (BCLBiomeRegistry.EMPTY_BIOME.getID().equals(biomeID))
return false;
return BCLBiomeRegistry.getOrElseEmpty(biomeID).getIntendedType().is(dim);
}
public static boolean wasRegisteredAsNetherBiome(ResourceLocation biomeID) {
@ -531,6 +691,14 @@ public class BiomeAPI {
return wasRegisteredAs(biomeID, BiomeType.END_VOID);
}
public static boolean wasRegisteredAsEndCenterBiome(ResourceLocation biomeID) {
return wasRegisteredAs(biomeID, BiomeType.END_CENTER);
}
public static boolean wasRegisteredAsEndBarrensBiome(ResourceLocation biomeID) {
return wasRegisteredAs(biomeID, BiomeType.END_BARRENS);
}
/**
* Registers new biome modification for specified dimension. Will work both for mod and datapack biomes.
*
@ -628,16 +796,16 @@ public class BiomeAPI {
}
static void sortBiomeFeatures(Biome biome) {
BiomeGenerationSettings settings = biome.getGenerationSettings();
BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) settings;
List<HolderSet<PlacedFeature>> featureList = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
final int size = featureList.size();
for (int i = 0; i < size; i++) {
List<Holder<PlacedFeature>> features = getFeaturesListCopy(featureList, i);
sortFeatures(features);
featureList.set(i, HolderSet.direct(features));
}
accessor.bclib_setFeatures(featureList);
// BiomeGenerationSettings settings = biome.getGenerationSettings();
// BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) settings;
// List<HolderSet<PlacedFeature>> featureList = CollectionsUtil.getMutable(accessor.bclib_getFeatures());
// final int size = featureList.size();
// for (int i = 0; i < size; i++) {
// List<Holder<PlacedFeature>> features = getFeaturesListCopy(featureList, i);
// sortFeatures(features);
// featureList.set(i, HolderSet.direct(features));
// }
// accessor.bclib_setFeatures(featureList);
}
/**
@ -840,4 +1008,86 @@ public class BiomeAPI {
}
return features.get(index).stream().collect(Collectors.toList());
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API.
*
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
public static BCLBiome registerNetherBiome(Biome biome) {
return InternalBiomeAPI.wrapNativeBiome(biome, -1, InternalBiomeAPI.OTHER_NETHER);
}
@Deprecated(forRemoval = true)
public static BCLBiome registerEndLandBiome(Holder<Biome> biome) {
return InternalBiomeAPI.wrapNativeBiome(biome.unwrapKey().orElseThrow(), InternalBiomeAPI.OTHER_END_LAND);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands).
*
* @param biome {@link BCLBiome}
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
public static BCLBiome registerEndVoidBiome(Holder<Biome> biome) {
return InternalBiomeAPI.wrapNativeBiome(biome.unwrapKey().orElseThrow(), InternalBiomeAPI.OTHER_END_VOID);
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biome {@link BCLBiome};
* @param genChance float generation chance.
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
public static BCLBiome registerEndLandBiome(Holder<Biome> biome, float genChance) {
return InternalBiomeAPI.wrapNativeBiome(
biome.unwrapKey().orElseThrow(),
genChance,
InternalBiomeAPI.OTHER_END_LAND
);
}
/**
* Register {@link BCLBiome} instance and its {@link Biome} if necessary.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands).
*
* @param biome {@link BCLBiome}.
* @param genChance float generation chance.
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
public static BCLBiome registerEndVoidBiome(Holder<Biome> biome, float genChance) {
return InternalBiomeAPI.wrapNativeBiome(
biome.unwrapKey().orElseThrow(),
genChance,
InternalBiomeAPI.OTHER_END_VOID
);
}
@Deprecated(forRemoval = true)
public static BCLBiome registerEndBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
registerBiome(bclBiome, BiomeType.END);
return bclBiome;
}
@Deprecated(forRemoval = true)
public static BCLBiome registerCenterBiome(Holder<Biome> biome) {
BCLBiome bclBiome = new BCLBiome(biome.value(), null);
registerBiome(bclBiome, BiomeType.END_CENTER);
return bclBiome;
}
}

View file

@ -0,0 +1,15 @@
package org.betterx.bclib.api.v2.levelgen.biomes;
import com.mojang.serialization.Codec;
import net.minecraft.util.KeyDispatchDataCodec;
import java.util.function.Function;
public interface BiomeData {
Codec<BCLBiome> CODEC = BCLBiomeRegistry
.BIOME_CODECS
.byNameCodec()
.dispatch(b -> b.codec().codec(), Function.identity());
KeyDispatchDataCodec<? extends BCLBiome> codec();
}

View file

@ -34,8 +34,30 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class InternalBiomeAPI {
public static final BiomeAPI.BiomeType OTHER_NETHER = new BiomeAPI.BiomeType(
"OTHER_NETHER",
BiomeAPI.BiomeType.NETHER
);
public static final BiomeAPI.BiomeType OTHER_END_LAND = new BiomeAPI.BiomeType(
"OTHER_END_LAND",
BiomeAPI.BiomeType.END_LAND
);
public static final BiomeAPI.BiomeType OTHER_END_VOID = new BiomeAPI.BiomeType(
"OTHER_END_VOID",
BiomeAPI.BiomeType.END_VOID
);
public static final BiomeAPI.BiomeType OTHER_END_CENTER = new BiomeAPI.BiomeType(
"OTHER_END_CENTER",
BiomeAPI.BiomeType.END_CENTER
);
public static final BiomeAPI.BiomeType OTHER_END_BARRENS = new BiomeAPI.BiomeType(
"OTHER_END_BARRENS",
BiomeAPI.BiomeType.END_BARRENS
);
static final Map<Biome, BCLBiome> CLIENT = Maps.newHashMap();
static final Map<Holder<PlacedFeature>, Integer> FEATURE_ORDER = Maps.newHashMap();
static final MutableInt FEATURE_ORDER_ID = new MutableInt(0);
@ -86,7 +108,7 @@ public class InternalBiomeAPI {
BIOMES_TO_SORT.forEach(id -> {
Biome b = biomeRegistry.get(id);
if (b != null) {
BCLib.LOGGER.info("Sorting Features in Biome: " + id + "(" + b + ")");
BCLib.LOGGER.info("Found non fabric/bclib Biome: " + id + "(" + b + ")");
BiomeAPI.sortBiomeFeatures(b);
} else {
BCLib.LOGGER.info("Unknown Biome: " + id);
@ -143,21 +165,17 @@ public class InternalBiomeAPI {
public static void _runBiomeTagAdders() {
for (var mod : TAG_ADDERS.entrySet()) {
Stream<ResourceLocation> s = null;
if (mod.getKey() == Level.NETHER) s = BiomeAPI.BiomeType.BIOME_TYPE_MAP.entrySet()
.stream()
.filter(e -> e.getValue()
.is(BiomeAPI.BiomeType.NETHER))
.map(e -> e.getKey());
else if (mod.getKey() == Level.END) s = BiomeAPI.BiomeType.BIOME_TYPE_MAP.entrySet()
.stream()
.filter(e -> e.getValue().is(
BiomeAPI.BiomeType.END))
.map(e -> e.getKey());
if (mod.getKey() == Level.NETHER)
s = BCLBiomeRegistry.getAll(BiomeAPI.BiomeType.NETHER).map(k -> k.location());
else if (mod.getKey() == Level.END)
s = BCLBiomeRegistry.getAll(BiomeAPI.BiomeType.END).map(k -> k.location());
if (s != null) {
s.forEach(id -> {
Holder<Biome> biomeHolder = BiomeAPI.getBiomeHolder(id);
if (biomeHolder.isBound()) {
Holder<Biome> biomeHolder = BiomeAPI.getFromRegistry(id);
if (biomeHolder != null && biomeHolder.isBound()) {
mod.getValue().forEach(c -> c.accept(id, biomeHolder));
} else {
BCLib.LOGGER.info("No Holder for " + id);
}
});
}
@ -246,6 +264,93 @@ public class InternalBiomeAPI {
private static final Set<ResourceLocation> BIOMES_TO_SORT = Sets.newHashSet();
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biomeKey The source biome to wrap
* @return {@link BCLBiome}
*/
public static BCLBiome wrapNativeBiome(ResourceKey<Biome> biomeKey, BiomeAPI.BiomeType type) {
return wrapNativeBiome(biomeKey, -1, type);
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biomeKey The source biome to wrap
* @param genChance generation chance. If &lt;0 the default genChance is used
* @return {@link BCLBiome}
*/
public static BCLBiome wrapNativeBiome(ResourceKey<Biome> biomeKey, float genChance, BiomeAPI.BiomeType type) {
return wrapNativeBiome(
biomeKey,
genChance < 0 ? null : VanillaBiomeSettings.createVanilla().setGenChance(genChance).build(),
type
);
}
public static BCLBiome wrapNativeBiome(
ResourceKey<Biome> biomeKey,
BCLBiome edgeBiome,
int edgeBiomeSize,
float genChance,
BiomeAPI.BiomeType type
) {
VanillaBiomeSettings.Builder settings = VanillaBiomeSettings.createVanilla();
if (genChance >= 0) settings.setGenChance(genChance);
settings.setEdge(edgeBiome);
settings.setEdgeSize(edgeBiomeSize);
return wrapNativeBiome(biomeKey, settings.build(), type);
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biomeKey The source biome to wrap
* @param setings the {@link VanillaBiomeSettings} to use
* @return {@link BCLBiome}
*/
private static BCLBiome wrapNativeBiome(
ResourceKey<Biome> biomeKey,
VanillaBiomeSettings setings,
BiomeAPI.BiomeType type
) {
BCLBiome bclBiome = BiomeAPI.getBiome(biomeKey.location());
if (bclBiome == BCLBiomeRegistry.EMPTY_BIOME) {
bclBiome = new BCLBiome(biomeKey, setings);
bclBiome._setIntendedType(type);
}
BiomeAPI.registerBiome(bclBiome);
return bclBiome;
}
/**
* Register {@link BCLBiome} wrapper for {@link Biome}.
* After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands).
*
* @param biome The source biome to wrap
* @param genChance generation chance.
* @return {@link BCLBiome}
*/
@Deprecated(forRemoval = true)
static BCLBiome wrapNativeBiome(Biome biome, float genChance, BiomeAPI.BiomeType type) {
BCLBiome bclBiome = BiomeAPI.getBiome(biome);
if (bclBiome == BCLBiomeRegistry.EMPTY_BIOME) {
bclBiome = new BCLBiome(
biome,
genChance < 0 ? null : VanillaBiomeSettings.createVanilla().setGenChance(genChance).build()
);
}
BiomeAPI.registerBiome(bclBiome, type, null);
return bclBiome;
}
static {
DynamicRegistrySetupCallback.EVENT.register(registryManager -> {
Optional<? extends Registry<Biome>> oBiomeRegistry = registryManager.registry(Registry.BIOME_REGISTRY);
@ -253,11 +358,21 @@ public class InternalBiomeAPI {
.event(oBiomeRegistry.get())
.register((rawId, id, biome) -> {
BCLBiome b = BiomeAPI.getBiome(id);
if (!"minecraft".equals(id.getNamespace()) && (b == null || b == BiomeAPI.EMPTY_BIOME)) {
if (!"minecraft".equals(id.getNamespace()) && (b == null || b == BCLBiomeRegistry.EMPTY_BIOME)) {
//BCLib.LOGGER.info(" #### " + rawId + ", " + biome + ", " + id);
BIOMES_TO_SORT.add(id);
}
});
});
}
public static boolean registryContainsBound(ResourceKey<Biome> key) {
Registry<Biome> reg = biomeRegistry;
if (reg == null) reg = BuiltinRegistries.BIOME;
if (reg.containsKey(key)) {
return reg.getOrCreateHolderOrThrow(key).isBound();
}
return false;
}
}

View file

@ -10,6 +10,7 @@ import java.util.List;
/**
* @deprecated Please use {@link org.betterx.bclib.api.v3.levelgen.features.config.TemplateFeatureConfig} instead
*/
@Deprecated(forRemoval = true)
public class TemplateFeatureConfig extends org.betterx.bclib.api.v3.levelgen.features.config.TemplateFeatureConfig {
public TemplateFeatureConfig(ResourceLocation location, int offsetY, StructurePlacementType type) {

View file

@ -11,8 +11,8 @@ import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
public abstract class DefaultFeature extends Feature<NoneFeatureConfiguration> {
protected static final BlockState AIR = Blocks.AIR.defaultBlockState();
protected static final BlockState WATER = Blocks.WATER.defaultBlockState();
public static final BlockState AIR = Blocks.AIR.defaultBlockState();
public static final BlockState WATER = Blocks.WATER.defaultBlockState();
public DefaultFeature() {
super(NoneFeatureConfiguration.CODEC);

View file

@ -1,14 +1,24 @@
package org.betterx.bclib.api.v2.levelgen.structures;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.bclib.util.MHelper;
import org.betterx.bclib.util.StructureErode;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.TemplateStructurePiece;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
@ -21,6 +31,8 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import java.util.Random;
public class TemplatePiece extends TemplateStructurePiece {
private final int erosion;
private final boolean cover;
public static final StructurePieceType INSTANCE = setTemplatePieceId(
TemplatePiece::new,
"template_piece"
@ -42,7 +54,6 @@ public class TemplatePiece extends TemplateStructurePiece {
public static void ensureStaticInitialization() {
}
public TemplatePiece(
StructureManager structureTemplateManager,
ResourceLocation resourceLocation,
@ -50,6 +61,19 @@ public class TemplatePiece extends TemplateStructurePiece {
Rotation rotation,
Mirror mirror,
BlockPos halfSize
) {
this(structureTemplateManager, resourceLocation, centerPos, rotation, mirror, halfSize, 0, false);
}
public TemplatePiece(
StructureTemplateManager structureTemplateManager,
ResourceLocation resourceLocation,
BlockPos centerPos,
Rotation rotation,
Mirror mirror,
BlockPos halfSize,
int erosion,
boolean cover
) {
super(
INSTANCE,
@ -60,6 +84,8 @@ public class TemplatePiece extends TemplateStructurePiece {
makeSettings(rotation, mirror, halfSize),
shiftPos(rotation, mirror, halfSize, centerPos)
);
this.erosion = erosion;
this.cover = cover;
}
public TemplatePiece(StructureManager structureTemplateManager, CompoundTag compoundTag) {
@ -69,6 +95,15 @@ public class TemplatePiece extends TemplateStructurePiece {
structureTemplateManager,
(ResourceLocation resourceLocation) -> makeSettings(compoundTag)
);
if (compoundTag.contains("E"))
this.erosion = compoundTag.getInt("E");
else
this.erosion = 0;
if (compoundTag.contains("C"))
this.cover = compoundTag.getBoolean("C");
else
this.cover = true;
}
private static BlockPos shiftPos(
@ -108,6 +143,8 @@ public class TemplatePiece extends TemplateStructurePiece {
tag.putInt("RX", this.placeSettings.getRotationPivot().getX());
tag.putInt("RY", this.placeSettings.getRotationPivot().getY());
tag.putInt("RZ", this.placeSettings.getRotationPivot().getZ());
tag.putInt("E", this.erosion);
tag.putBoolean("C", this.cover);
}
@Override
@ -120,4 +157,54 @@ public class TemplatePiece extends TemplateStructurePiece {
) {
}
@Override
public void postProcess(
WorldGenLevel world,
StructureManager structureManager,
ChunkGenerator chunkGenerator,
RandomSource random,
BoundingBox boundingBox,
ChunkPos chunkPos,
BlockPos blockPos
) {
BlockState coverState = null;
if (cover) {
BlockPos.MutableBlockPos mPos = new BlockPos(
this.boundingBox.minX() - 1,
blockPos.getY(),
this.boundingBox.minZ() - 1
).mutable();
if (BlocksHelper.findOnSurroundingSurface(
world,
mPos,
Direction.DOWN,
8,
s -> s.is(CommonBlockTags.TERRAIN)
)) {
mPos.move(Direction.DOWN);
coverState = world.getBlockState(mPos);
}
}
super.postProcess(world, structureManager, chunkGenerator, random, boundingBox, chunkPos, blockPos);
BoundingBox bounds = BoundingBox.fromCorners(new Vec3i(
boundingBox.minX(),
this.boundingBox.minY(),
boundingBox.minZ()
), new Vec3i(boundingBox.maxX(), this.boundingBox.maxY(), boundingBox.maxZ()));
if (erosion > 0) {
int x1 = MHelper.min(bounds.maxX(), this.boundingBox.maxX());
int x0 = MHelper.max(bounds.minX(), this.boundingBox.minX());
int z1 = MHelper.min(bounds.maxZ(), this.boundingBox.maxZ());
int z0 = MHelper.max(bounds.minZ(), this.boundingBox.minZ());
bounds = BoundingBox.fromCorners(new Vec3i(x0, bounds.minY(), z0), new Vec3i(x1, bounds.maxY(), z1));
StructureErode.erode(world, bounds, erosion, random);
}
if (cover) {
//System.out.println("CoverState:" + coverState + ", " + blockPos + " " + boundingBox.getCenter());
StructureErode.cover(world, bounds, random, coverState);
}
}
}

View file

@ -24,7 +24,6 @@ import java.util.Optional;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
public abstract class TemplateStructure extends StructureFeature {
protected final List<Config> configs;
@ -84,6 +83,14 @@ public abstract class TemplateStructure extends StructureFeature {
return (state == null || state.is(Blocks.AIR)) && before.getMaterial().isSolid();
}
protected int erosion(RandomSource rnd) {
return 0;
}
protected boolean cover(RandomSource rnd) {
return false;
}
@Override
public Optional<GenerationStub> findGenerationPoint(GenerationContext ctx) {
WorldGenerationContext worldGenerationContext = new WorldGenerationContext(
@ -153,8 +160,7 @@ public abstract class TemplateStructure extends StructureFeature {
blockPos.getZ(),
ctx.heightAccessor(),
ctx.randomState()
))
.collect(Collectors.toList());
)).toList();
int y = noiseColumns
.stream()
@ -185,6 +191,8 @@ public abstract class TemplateStructure extends StructureFeature {
centerPos.setY(y - (searchStep == 1 ? 0 : (structureTemplate.getSize(Rotation.NONE).getY())));
int erosion = erosion(ctx.random());
boolean cover = cover(ctx.random());
// if (!structure.canGenerate(ctx.chunkGenerator()., centerPos))
return Optional.of(new GenerationStub(
centerPos,
@ -200,7 +208,9 @@ public abstract class TemplateStructure extends StructureFeature {
),
rotation,
mirror,
halfSize
halfSize,
erosion,
cover
))
));

View file

@ -1,7 +1,5 @@
package org.betterx.bclib.api.v3.levelgen.features.features;
import org.betterx.bclib.api.v2.levelgen.features.BCLFeature;
import org.betterx.bclib.api.v2.levelgen.features.BCLFeatureBuilder;
import org.betterx.bclib.api.v2.levelgen.structures.StructureNBT;
import org.betterx.bclib.api.v2.levelgen.structures.StructureWorldNBT;
import org.betterx.bclib.api.v3.levelgen.features.config.TemplateFeatureConfig;
@ -15,51 +13,11 @@ import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import java.util.Random;
public class TemplateFeature<FC extends TemplateFeatureConfig> extends Feature<FC> {
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegisterRare(
ResourceLocation location,
TemplateFeatureConfig configuration,
int onceEveryChunk
) {
return BCLFeatureBuilder
.start(location, org.betterx.bclib.api.v3.levelgen.features.BCLFeature.TEMPLATE)
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
.onceEvery(onceEveryChunk) //discard neighboring chunks
.count(16) //try 16 placements in chunk
.squarePlacement() //randomize x/z in chunk
.randomHeight10FromFloorCeil() //randomize height 10 above and 10 below max vertical
.findSolidFloor(12) //cast downward ray to find solid surface
.isEmptyAbove4() //make sure we have 4 free blocks above
.onlyInBiome() //ensure that we still are in the correct biome
.buildAndRegister(configuration);
}
public static <T extends TemplateFeatureConfig> BCLFeature createAndRegister(
ResourceLocation location,
TemplateFeatureConfig configuration,
int count
) {
return BCLFeatureBuilder
.start(location, org.betterx.bclib.api.v3.levelgen.features.BCLFeature.TEMPLATE)
.decoration(GenerationStep.Decoration.SURFACE_STRUCTURES)
.count(count)
.squarePlacement()
.randomHeight10FromFloorCeil()
.findSolidFloor(12) //cast downward ray to find solid surface
.isEmptyAbove4()
.onlyInBiome()
.buildAndRegister(configuration);
}
public TemplateFeature(Codec<FC> codec) {
super(codec);
}
protected StructureWorldNBT randomStructure(TemplateFeatureConfig cfg, Random random) {
if (cfg.structures.size() > 1) {
final float chanceSum = cfg.structures.parallelStream().map(c -> c.chance).reduce(0.0f, (p, c) -> p + c);
float rnd = random.nextFloat() * chanceSum;

View file

@ -6,8 +6,8 @@ import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
import org.betterx.bclib.client.models.CustomModelBakery;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.registry.BaseBlockEntityRenders;
import org.betterx.bclib.registry.PresetsRegistryClient;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.client.WorldsTogetherClient;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.UnbakedModel;
@ -31,7 +31,7 @@ public class BCLibClient implements ClientModInitializer, ModelResourceProvider,
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> this);
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> this);
WorldsTogetherClient.onInitializeClient();
PresetsRegistryClient.onLoad();
WorldsTogether.SURPRESS_EXPERIMENTAL_DIALOG = Configs.CLIENT_CONFIG.suppressExperimentalDialog();
//dumpDatapack();
}

View file

@ -185,7 +185,11 @@ public class WorldSetupScreen extends BCLibScreen {
? BCLEndBiomeSourceConfig.EndBiomeGeneratorType.PAULEVS
: BCLEndBiomeSourceConfig.EndBiomeGeneratorType.VANILLA,
generateEndVoid.isChecked(),
BCLEndBiomeSourceConfig.DEFAULT.innerVoidRadiusSquared
BCLEndBiomeSourceConfig.DEFAULT.innerVoidRadiusSquared,
BCLEndBiomeSourceConfig.DEFAULT.centerBiomesSize,
BCLEndBiomeSourceConfig.DEFAULT.voidBiomesSize,
BCLEndBiomeSourceConfig.DEFAULT.landBiomesSize,
BCLEndBiomeSourceConfig.DEFAULT.barrensBiomesSize
);
ChunkGenerator endGenerator = betterxDimensions.get(LevelStem.END);
@ -201,7 +205,10 @@ public class WorldSetupScreen extends BCLibScreen {
BCLNetherBiomeSourceConfig netherConfig = new BCLNetherBiomeSourceConfig(
netherLegacy.isChecked()
? BCLNetherBiomeSourceConfig.NetherBiomeMapType.SQUARE
: BCLNetherBiomeSourceConfig.NetherBiomeMapType.HEX
: BCLNetherBiomeSourceConfig.NetherBiomeMapType.HEX,
BCLNetherBiomeSourceConfig.DEFAULT.biomeSize,
BCLNetherBiomeSourceConfig.DEFAULT.biomeSizeVertical,
BCLNetherBiomeSourceConfig.DEFAULT.useVerticalBiomes
);
ChunkGenerator netherGenerator = betterxDimensions.get(LevelStem.NETHER);

View file

@ -1,6 +1,7 @@
package org.betterx.bclib.client.render;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.config.Configs;
import org.betterx.bclib.util.BackgroundInfo;
@ -116,7 +117,7 @@ public class CustomFogRenderer {
private static boolean shouldIgnore(Level level, int x, int y, int z) {
Biome biome = level.getBiome(MUT_POS.set(x, y, z)).value();
return BiomeAPI.getRenderBiome(biome) == BiomeAPI.EMPTY_BIOME;
return BiomeAPI.getRenderBiome(biome) == BCLBiomeRegistry.EMPTY_BIOME;
}
private static float getFogDensityI(Level level, int x, int y, int z) {

View file

@ -0,0 +1,111 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import java.util.*;
public class BiomesConfig extends PathConfig {
private Map<BiomeAPI.BiomeType, List<String>> BIOME_INCLUDE_LIST = null;
private Map<BiomeAPI.BiomeType, List<String>> BIOME_EXCLUDE_LIST = null;
public static final BiomeAPI.BiomeType[] endTypes = {
BiomeAPI.BiomeType.END_LAND,
BiomeAPI.BiomeType.END_VOID,
BiomeAPI.BiomeType.END_CENTER,
BiomeAPI.BiomeType.END_BARRENS
};
public static final BiomeAPI.BiomeType[] netherTypes = {
BiomeAPI.BiomeType.NETHER
};
private static final BiomeAPI.BiomeType[] includeTypes = all();
private static final BiomeAPI.BiomeType[] excludeTypes = {BiomeAPI.BiomeType.NETHER, BiomeAPI.BiomeType.END};
public BiomesConfig() {
super(BCLib.MOD_ID, "biomes", false);
for (var type : includeTypes) {
keeper.registerEntry(
new ConfigKey(type.getName(), "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
}
for (var type : excludeTypes) {
keeper.registerEntry(
new ConfigKey(type.getName(), "force_exclude"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
}
}
private static BiomeAPI.BiomeType[] all() {
BiomeAPI.BiomeType[] res = new BiomeAPI.BiomeType[endTypes.length + netherTypes.length];
System.arraycopy(netherTypes, 0, res, 0, netherTypes.length);
System.arraycopy(endTypes, 0, res, netherTypes.length, endTypes.length);
return res;
}
private List<String> getBiomeIncludeList(BiomeAPI.BiomeType type) {
var entry = getEntry(
"force_include",
type.getName(),
ConfigKeeper.StringArrayEntry.class
);
if (entry == null)
return List.of();
return entry.getValue();
}
private List<String> getBiomeExcludeList(BiomeAPI.BiomeType type) {
var entry = getEntry(
"force_exclude",
type.getName(),
ConfigKeeper.StringArrayEntry.class
);
if (entry == null)
return List.of();
return entry.getValue();
}
public List<String> getIncludeMatching(BiomeAPI.BiomeType type) {
return getBiomeIncludeMap().entrySet()
.stream()
.filter(e -> e.getKey().is(type))
.map(e -> e.getValue())
.flatMap(Collection::stream)
.toList();
}
public List<String> getExcludeMatching(BiomeAPI.BiomeType type) {
return getBiomeExcludeMap().entrySet()
.stream()
.filter(e -> e.getKey().is(type))
.map(e -> e.getValue())
.flatMap(Collection::stream)
.toList();
}
public Map<BiomeAPI.BiomeType, List<String>> getBiomeIncludeMap() {
if (BIOME_INCLUDE_LIST == null) {
BIOME_INCLUDE_LIST = new HashMap<>();
for (BiomeAPI.BiomeType type : includeTypes) {
BIOME_INCLUDE_LIST.put(type, getBiomeIncludeList(type));
}
}
return BIOME_INCLUDE_LIST;
}
public Map<BiomeAPI.BiomeType, List<String>> getBiomeExcludeMap() {
if (BIOME_EXCLUDE_LIST == null) {
BIOME_EXCLUDE_LIST = new HashMap<>();
for (BiomeAPI.BiomeType type : excludeTypes) {
BIOME_EXCLUDE_LIST.put(type, getBiomeExcludeList(type));
}
}
return BIOME_EXCLUDE_LIST;
}
}

View file

@ -5,8 +5,6 @@ import org.betterx.bclib.BCLib;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import java.util.Collections;
public class Configs {
// Client and Server-Config must be the first entries. They are not part of the Auto-Sync process
// But will be needed by other Auto-Sync Config-Files
@ -18,7 +16,7 @@ public class Configs {
public static final MainConfig MAIN_CONFIG = new MainConfig();
public static final PathConfig RECIPE_CONFIG = new PathConfig(BCLib.MOD_ID, "recipes");
public static final PathConfig BIOMES_CONFIG = new PathConfig(BCLib.MOD_ID, "biomes", false);
public static final BiomesConfig BIOMES_CONFIG = new BiomesConfig();
public static final String MAIN_PATCH_CATEGORY = "patches";
@ -28,23 +26,4 @@ public class Configs {
GENERATOR_CONFIG.saveChanges();
BIOMES_CONFIG.saveChanges();
}
static {
BIOMES_CONFIG.keeper.registerEntry(
new ConfigKey("end_land_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
BIOMES_CONFIG.keeper.registerEntry(
new ConfigKey("end_void_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
BIOMES_CONFIG.keeper.registerEntry(
new ConfigKey("nether_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
BIOMES_CONFIG.keeper.registerEntry(
new ConfigKey("nether_biomes", "force_exclude"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST)
);
}
}

View file

@ -55,6 +55,11 @@ public class ServerConfig extends NamedPathConfig {
"excludeMods",
AutoSync.SYNC_CATEGORY
);
public static final ConfigToken<Boolean> FORCE_BETTERX_PRESET = ConfigToken.Boolean(
true,
"forceBetterXPreset",
AutoSync.SYNC_CATEGORY
);
public ServerConfig() {
@ -85,4 +90,8 @@ public class ServerConfig extends NamedPathConfig {
return get(SEND_ALL_MOD_INFO) /*&& isAllowingAutoSync()*/;
}
public boolean forceBetterXPreset() {
return get(FORCE_BETTERX_PRESET);
}
}

View file

@ -3,7 +3,7 @@ package org.betterx.bclib.interfaces;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
public interface TheEndBiomeDataAccessor {
public interface TheEndBiomesAccessor {
boolean bcl_canGenerateAsEndBiome(ResourceKey<Biome> key);
boolean bcl_canGenerateAsEndMidlandBiome(ResourceKey<Biome> key);

View file

@ -0,0 +1,40 @@
package org.betterx.bclib.mixin.common;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BuiltinRegistries.class)
public abstract class BuiltinRegistriesMixin {
@Shadow
protected static <T, R extends WritableRegistry<T>> R internalRegister(
ResourceKey<? extends Registry<T>> resourceKey,
R writableRegistry,
BuiltinRegistries.RegistryBootstrap<T> registryBootstrap,
Lifecycle lifecycle
) {
throw new RuntimeException("Shadowed Call");
}
//this needs to be added BEFORE the WORLD_PRESET-Registry. Otherwise decoding will fail!
@Inject(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/data/BuiltinRegistries;registerSimple(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/data/BuiltinRegistries$RegistryBootstrap;)Lnet/minecraft/core/Registry;", ordinal = 0))
private static void bcl_registerBuiltin(CallbackInfo ci) {
BCLBiomeRegistry.BUILTIN_BCL_BIOMES = internalRegister(
BCLBiomeRegistry.BCL_BIOMES_REGISTRY,
(MappedRegistry) BCLBiomeRegistry.BUILTIN_BCL_BIOMES,
BCLBiomeRegistry::bootstrap,
Lifecycle.stable()
);
}
}

View file

@ -1,18 +0,0 @@
package org.betterx.bclib.mixin.common;
import org.betterx.worlds.together.worldPreset.WorldPresets;
import net.minecraft.server.dedicated.DedicatedServerProperties;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(DedicatedServerProperties.class)
public class DedicatedServerPropertiesMixin {
//Make sure the default server properties use our Default World Preset
@ModifyArg(method = "<init>", index = 3, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/DedicatedServerProperties$WorldGenProperties;<init>(Ljava/lang/String;Lcom/google/gson/JsonObject;ZLjava/lang/String;)V"))
private String bcl_init(String levelType) {
return WorldPresets.getDEFAULT().location().toString();
}
}

View file

@ -0,0 +1,48 @@
package org.betterx.bclib.mixin.common;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiomeRegistry;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeData;
import com.mojang.serialization.Codec;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import com.google.common.collect.ImmutableMap;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.Map;
import java.util.function.Supplier;
@Mixin(RegistryAccess.class)
public interface RegistryAccessMixin {
@ModifyArg(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;make(Ljava/util/function/Supplier;)Ljava/lang/Object;"))
private static Supplier<ImmutableMap<ResourceKey<Registry<?>>, RegistryAccess.RegistryData<?>>> together_addRegistry(
Supplier<ImmutableMap<ResourceKey<Registry<?>>, RegistryAccess.RegistryData<?>>> supplier
) {
return () -> {
ImmutableMap.Builder<ResourceKey<Registry<?>>, RegistryAccess.RegistryData<?>> builder = ImmutableMap.builder();
//Make sure this gets added before WORLD_PRESETS
put(builder, BCLBiomeRegistry.BCL_BIOMES_REGISTRY, BiomeData.CODEC);
Map<ResourceKey<Registry<?>>, RegistryAccess.RegistryData<?>> res = supplier.get();
builder.putAll(res);
return builder.build();
};
}
@Shadow
static <E> void put(
ImmutableMap.Builder<ResourceKey<Registry<?>>, RegistryAccess.RegistryData<?>> builder,
ResourceKey<? extends Registry<E>> resourceKey,
Codec<E> codec
) {
throw new RuntimeException("Shadowed Call");
}
}

View file

@ -1,7 +1,8 @@
package org.betterx.bclib.mixin.common;
import org.betterx.bclib.api.v2.LifeCycleAPI;
import org.betterx.bclib.api.v2.generator.BCLBiomeSource;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
import org.betterx.worlds.together.world.BiomeSourceWithSeed;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
@ -12,6 +13,7 @@ import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess;
import net.minecraft.world.level.storage.ServerLevelData;
import net.minecraft.world.level.storage.WritableLevelData;
@ -73,10 +75,15 @@ public abstract class ServerLevelMixin extends Level {
bl2
);
if (levelStem.generator().getBiomeSource() instanceof BCLBiomeSource source) {
if (levelStem.generator().getBiomeSource() instanceof BiomeSourceWithSeed source) {
source.setSeed(level.getSeed());
}
if (levelStem.generator().getBiomeSource() instanceof BiomeSourceWithNoiseRelatedSettings bcl
&& levelStem.generator() instanceof NoiseBasedChunkGenerator noiseGenerator) {
bcl.onLoadGeneratorSettings(noiseGenerator.generatorSettings().value());
}
if (bclib_lastWorld != null && bclib_lastWorld.equals(levelStorageAccess.getLevelId())) {
return;
}

View file

@ -1,40 +0,0 @@
package org.betterx.bclib.mixin.common;
import org.betterx.bclib.interfaces.TheEndBiomeDataAccessor;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
import net.fabricmc.fabric.impl.biome.WeightedPicker;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
@Mixin(value = TheEndBiomeData.class, remap = false)
public class TheEndBiomeDataMixin implements TheEndBiomeDataAccessor {
@Shadow
@Final
private static Map<ResourceKey<Biome>, WeightedPicker<ResourceKey<Biome>>> END_BIOMES_MAP;
@Shadow
@Final
private static Map<ResourceKey<Biome>, WeightedPicker<ResourceKey<Biome>>> END_MIDLANDS_MAP;
@Shadow
@Final
private static Map<ResourceKey<Biome>, WeightedPicker<ResourceKey<Biome>>> END_BARRENS_MAP;
public boolean bcl_canGenerateAsEndBiome(ResourceKey<Biome> key) {
return END_BIOMES_MAP != null && END_BIOMES_MAP.containsKey(key);
}
public boolean bcl_canGenerateAsEndMidlandBiome(ResourceKey<Biome> key) {
return END_MIDLANDS_MAP != null && END_MIDLANDS_MAP.containsKey(key);
}
public boolean bcl_canGenerateAsEndBarrensBiome(ResourceKey<Biome> key) {
return END_BARRENS_MAP != null && END_BARRENS_MAP.containsKey(key);
}
}

View file

@ -0,0 +1,64 @@
package org.betterx.bclib.mixin.common;
import org.betterx.bclib.api.v2.generator.TheEndBiomesHelper;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.fabricmc.fabric.api.biome.v1.TheEndBiomes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = TheEndBiomes.class, remap = false)
public class TheEndBiomesMixin {
@Inject(method = "addBarrensBiome", at = @At("HEAD"))
private static void bcl_registerBarrens(
ResourceKey<Biome> highlands,
ResourceKey<Biome> barrens,
double weight,
CallbackInfo ci
) {
TheEndBiomesHelper.add(InternalBiomeAPI.OTHER_END_BARRENS, barrens);
}
@Inject(method = "addMidlandsBiome", at = @At("HEAD"))
private static void bcl_registerMidlands(
ResourceKey<Biome> highlands,
ResourceKey<Biome> midlands,
double weight,
CallbackInfo ci
) {
BCLBiome highland = InternalBiomeAPI.wrapNativeBiome(highlands, InternalBiomeAPI.OTHER_END_LAND);
BCLBiome midland = InternalBiomeAPI.wrapNativeBiome(midlands, InternalBiomeAPI.OTHER_END_LAND);
if (highland != null) {
highland.addEdge(midland);
}
TheEndBiomesHelper.add(InternalBiomeAPI.OTHER_END_LAND, midlands);
}
@Inject(method = "addSmallIslandsBiome", at = @At("HEAD"))
private static void bcl_registerSmallIslands(
ResourceKey<Biome> biome, double weight, CallbackInfo ci
) {
TheEndBiomesHelper.add(InternalBiomeAPI.OTHER_END_VOID, biome);
}
@Inject(method = "addHighlandsBiome", at = @At("HEAD"))
private static void bcl_registerHighlands(
ResourceKey<Biome> biome, double weight, CallbackInfo ci
) {
TheEndBiomesHelper.add(InternalBiomeAPI.OTHER_END_LAND, biome);
}
@Inject(method = "addMainIslandBiome", at = @At("HEAD"))
private static void bcl_registerMainIsnalnd(
ResourceKey<Biome> biome, double weight, CallbackInfo ci
) {
TheEndBiomesHelper.add(InternalBiomeAPI.OTHER_END_CENTER, biome);
}
}

View file

@ -4,6 +4,7 @@ import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.generator.config.BCLEndBiomeSourceConfig;
import org.betterx.bclib.api.v2.generator.config.BCLNetherBiomeSourceConfig;
import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
import org.betterx.worlds.together.entrypoints.WorldPresetBootstrap;
import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.worldPreset.TogetherWorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPreset;
@ -14,11 +15,11 @@ import net.minecraft.world.level.dimension.LevelStem;
import java.util.Map;
public class PresetsRegistry {
public class PresetsRegistry implements WorldPresetBootstrap {
public static ResourceKey<WorldPreset> BCL_WORLD;
public static ResourceKey<WorldPreset> BCL_WORLD_17;
public static void onLoad() {
public void bootstrapWorldPresets() {
BCL_WORLD =
WorldPresets.register(
BCLib.makeID("normal"),

View file

@ -3,10 +3,20 @@ package org.betterx.bclib.util;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
/**
* @deprecated Please use {@link org.betterx.worlds.together.util.Logger} instead
*/
@Deprecated(forRemoval = true)
public final class Logger {
private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger();
private final String modPref;
/**
* @deprecated Please use {@link org.betterx.worlds.together.util.Logger#Logger(String)} instead
*/
@Deprecated(forRemoval = true)
public Logger(String modID) {
this.modPref = "[" + modID + "] ";
}

View file

@ -4,16 +4,75 @@ import com.mojang.math.Vector3f;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.RandomSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.PositionalRandomFactory;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class MHelper {
static class ThreadLocalRandomSource implements RandomSource {
ThreadLocalRandomSource(long seed) {
}
@Override
public RandomSource fork() {
return this;
}
@Override
public PositionalRandomFactory forkPositional() {
return null;
}
@Override
public void setSeed(long l) {
ThreadLocalRandom.current().setSeed(l);
}
@Override
public int nextInt() {
return ThreadLocalRandom.current().nextInt();
}
@Override
public int nextInt(int i) {
return ThreadLocalRandom.current().nextInt(i);
}
@Override
public long nextLong() {
return ThreadLocalRandom.current().nextLong();
}
@Override
public boolean nextBoolean() {
return ThreadLocalRandom.current().nextBoolean();
}
@Override
public float nextFloat() {
return ThreadLocalRandom.current().nextFloat();
}
@Override
public double nextDouble() {
return ThreadLocalRandom.current().nextDouble();
}
@Override
public double nextGaussian() {
return ThreadLocalRandom.current().nextGaussian();
}
}
private static final Vec3i[] RANDOM_OFFSETS = new Vec3i[3 * 3 * 3 - 1];
private static final float RAD_TO_DEG = 57.295779513082320876798154814105F;
public static final float PHI = (float) (Math.PI * (3 - Math.sqrt(5)));
public static final float PI2 = (float) (Math.PI * 2);
public static final Random RANDOM = new Random();
public static final RandomSource RANDOM_SOURCE = new LegacyRandomSource(RANDOM.nextLong());
public static final RandomSource RANDOM_SOURCE = new ThreadLocalRandomSource(RANDOM.nextLong());
public static int randRange(int min, int max, Random random) {
return min + random.nextInt(max - min + 1);

View file

@ -1,8 +1,20 @@
package org.betterx.bclib.util;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Objects;
public class Pair<A, B> {
public static <A, B> Codec<Pair<A, B>> pairCodec(Codec<A> a, Codec<B> b, String first, String second) {
return RecordCodecBuilder.create(instance -> instance
.group(
a.fieldOf(first).forGetter(o -> o.first),
b.fieldOf(second).forGetter(o -> o.second)
)
.apply(instance, Pair::new));
}
public final A first;
public final B second;

View file

@ -0,0 +1,277 @@
package org.betterx.bclib.util;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.worlds.together.tag.v3.CommonBlockTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.material.Material;
import com.google.common.collect.Sets;
import java.util.Set;
public class StructureErode {
private static final Direction[] DIR = BlocksHelper.makeHorizontal();
public static void erode(WorldGenLevel world, BoundingBox bounds, int iterations, RandomSource random) {
MutableBlockPos mut = new MutableBlockPos();
boolean canDestruct = true;
for (int i = 0; i < iterations; i++) {
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
for (int y = bounds.maxY(); y >= bounds.minY(); y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
boolean ignore = ignore(state, world, mut);
if (canDestruct && BlocksHelper.isInvulnerable(
state,
world,
mut
) && random.nextInt(8) == 0 && world.isEmptyBlock(
mut.below(2))) {
int r = MHelper.randRange(1, 4, random);
int cx = mut.getX();
int cy = mut.getY();
int cz = mut.getZ();
int x1 = cx - r;
int y1 = cy - r;
int z1 = cz - r;
int x2 = cx + r;
int y2 = cy + r;
int z2 = cz + r;
for (int px = x1; px <= x2; px++) {
int dx = px - cx;
dx *= dx;
mut.setX(px);
for (int py = y1; py <= y2; py++) {
int dy = py - cy;
dy *= dy;
mut.setY(py);
for (int pz = z1; pz <= z2; pz++) {
int dz = pz - cz;
dz *= dz;
mut.setZ(pz);
if (dx + dy + dz <= r && BlocksHelper.isInvulnerable(
world.getBlockState(mut),
world,
mut
)) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
mut.setX(cx);
mut.setY(cy);
mut.setZ(cz);
canDestruct = false;
continue;
} else if (ignore) {
continue;
}
if (!state.isAir() && random.nextBoolean()) {
MHelper.shuffle(DIR, random);
for (Direction dir : DIR) {
if (world.isEmptyBlock(mut.relative(dir)) && world.isEmptyBlock(mut.below()
.relative(dir))) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
mut.move(dir).move(Direction.DOWN);
for (int py = mut.getY(); y >= bounds.minY() - 10; y--) {
mut.setY(py - 1);
if (!world.isEmptyBlock(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
break;
} else if (random.nextInt(8) == 0 && !BlocksHelper.isInvulnerable(
world.getBlockState(mut.above()),
world,
mut
)) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
}
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
for (int y = bounds.maxY(); y >= bounds.minY(); y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state, world, mut) && world.isEmptyBlock(mut.below())) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
for (int py = mut.getY(); py >= bounds.minY() - 10; py--) {
mut.setY(py - 1);
if (!world.isEmptyBlock(mut)) {
mut.setY(py);
BlocksHelper.setWithoutUpdate(world, mut, state);
break;
}
}
}
}
}
}
}
public static void erodeIntense(WorldGenLevel world, BoundingBox bounds, RandomSource random) {
MutableBlockPos mut = new MutableBlockPos();
MutableBlockPos mut2 = new MutableBlockPos();
int minY = bounds.minY() - 10;
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
for (int y = bounds.maxY(); y >= bounds.minY(); y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state, world, mut)) {
if (random.nextInt(6) == 0) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
if (random.nextBoolean()) {
int px = MHelper.floor(random.nextGaussian() * 2 + x + 0.5);
int pz = MHelper.floor(random.nextGaussian() * 2 + z + 0.5);
mut2.set(px, y, pz);
while (world.getBlockState(mut2).getMaterial().isReplaceable() && mut2.getY() > minY) {
mut2.setY(mut2.getY() - 1);
}
if (!world.getBlockState(mut2).isAir() && state.canSurvive(world, mut2)) {
mut2.setY(mut2.getY() + 1);
BlocksHelper.setWithoutUpdate(world, mut2, state);
}
}
} else if (random.nextInt(8) == 0) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
}
}
}
}
}
drop(world, bounds);
}
private static void drop(WorldGenLevel world, BoundingBox bounds) {
MutableBlockPos mut = new MutableBlockPos();
Set<BlockPos> blocks = Sets.newHashSet();
Set<BlockPos> edge = Sets.newHashSet();
Set<BlockPos> add = Sets.newHashSet();
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
for (int y = bounds.minY(); y <= bounds.maxY(); y++) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state, world, mut) && isTerrainNear(world, mut)) {
edge.add(mut.immutable());
}
}
}
}
if (edge.isEmpty()) {
return;
}
while (!edge.isEmpty()) {
for (BlockPos center : edge) {
for (Direction dir : BlocksHelper.DIRECTIONS) {
BlockState state = world.getBlockState(center);
if (state.isCollisionShapeFullBlock(world, center)) {
mut.set(center).move(dir);
if (bounds.isInside(mut)) {
state = world.getBlockState(mut);
if (!ignore(state, world, mut) && !blocks.contains(mut)) {
add.add(mut.immutable());
}
}
}
}
}
blocks.addAll(edge);
edge.clear();
edge.addAll(add);
add.clear();
}
int minY = bounds.minY() - 10;
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
for (int y = bounds.minY(); y <= bounds.maxY(); y++) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (!ignore(state, world, mut) && !blocks.contains(mut)) {
BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR);
while (world.getBlockState(mut).getMaterial().isReplaceable() && mut.getY() > minY) {
mut.setY(mut.getY() - 1);
}
if (mut.getY() > minY) {
mut.setY(mut.getY() + 1);
BlocksHelper.setWithoutUpdate(world, mut, state);
}
}
}
}
}
}
private static boolean ignore(BlockState state, WorldGenLevel world, BlockPos pos) {
if (state.is(CommonBlockTags.GEN_END_STONES) || state.is(BlockTags.NYLIUM)) {
return true;
}
return !state.getMaterial().equals(Material.STONE) || BlocksHelper.isInvulnerable(state, world, pos);
}
private static boolean isTerrainNear(WorldGenLevel world, BlockPos pos) {
for (Direction dir : BlocksHelper.DIRECTIONS) {
if (world.getBlockState(pos.relative(dir)).is(CommonBlockTags.GEN_END_STONES)) {
return true;
}
}
return false;
}
public static void cover(WorldGenLevel world, BoundingBox bounds, RandomSource random, BlockState defaultBlock) {
MutableBlockPos mut = new MutableBlockPos();
for (int x = bounds.minX(); x <= bounds.maxX(); x++) {
mut.setX(x);
for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) {
mut.setZ(z);
BlockState top = BiomeAPI.findTopMaterial(world.getBiome(mut)).orElse(defaultBlock);
if (top == null) continue;
for (int y = bounds.maxY(); y >= bounds.minY(); y--) {
mut.setY(y);
BlockState state = world.getBlockState(mut);
if (state.is(CommonBlockTags.TERRAIN) && !world.getBlockState(mut.above())
.getMaterial()
.isSolidBlocking()) {
BlocksHelper.setWithoutUpdate(world, mut, top);
}
}
}
}
}
}

View file

@ -4,12 +4,64 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
public class WeightedList<T> {
private final List<Float> weights = new ArrayList<Float>();
private final List<T> values = new ArrayList<T>();
private float maxWeight;
public static <T> Codec<Pair<Float, T>> pairCodec(Codec<T> elementCodec, String fieldName) {
return Pair.pairCodec(Codec.FLOAT, elementCodec, "weight", fieldName);
}
public static <T> Codec<WeightedList<T>> listCodec(Codec<T> elementCodec, String fieldName, String elementName) {
return RecordCodecBuilder.create(instance -> instance
.group(
pairCodec(elementCodec, elementName).listOf()
.fieldOf(fieldName)
.forGetter(WeightedList::pairs)
)
.apply(instance, WeightedList::new)
);
}
private List<Pair<Float, T>> pairs() {
List<Pair<Float, T>> pairs = new ArrayList<>(weights.size());
for (int i = 0; i < weights.size(); i++) {
pairs.add(new Pair<>(weights.get(i), values.get(i)));
}
return pairs;
}
private WeightedList(List<Pair<Float, T>> pairs) {
maxWeight = 0;
for (var pair : pairs) {
maxWeight += pair.first;
weights.add(pair.first);
values.add(pair.second);
}
}
public WeightedList() {
}
public <R> WeightedList<R> map(Function<T, R> map) {
List<Pair<Float, R>> pairs = new ArrayList<>(weights.size());
for (int i = 0; i < weights.size(); i++) {
pairs.add(new Pair<>(weights.get(i), map.apply(values.get(i))));
}
return new WeightedList<>(pairs);
}
public void addAll(WeightedList<T> other) {
weights.addAll(other.weights);
values.addAll(other.values);
maxWeight += other.maxWeight;
}
/**
* Adds value with specified weight to the list
*
@ -37,6 +89,7 @@ public class WeightedList<T> {
if (weight <= weights.get(i)) {
return values.get(i);
}
weight -= weights.get(i);
}
return null;
}

View file

@ -1,17 +1,19 @@
package org.betterx.worlds.together;
import org.betterx.bclib.util.Logger;
import org.betterx.worlds.together.surfaceRules.SurfaceRuleRegistry;
import org.betterx.worlds.together.tag.v3.TagManager;
import org.betterx.worlds.together.util.Logger;
import org.betterx.worlds.together.world.WorldConfig;
import org.betterx.worlds.together.worldPreset.WorldPresets;
import net.minecraft.resources.ResourceLocation;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
public class WorldsTogether {
public class WorldsTogether implements ModInitializer {
public static boolean SURPRESS_EXPERIMENTAL_DIALOG = false;
public static boolean FORCE_SERVER_TO_BETTERX_PRESET = false;
public static final String MOD_ID = "worlds_together";
public static final Logger LOGGER = new Logger(MOD_ID);
public static final boolean RUNS_TERRABLENDER = FabricLoader.getInstance()
@ -22,7 +24,7 @@ public class WorldsTogether {
return FabricLoader.getInstance().isDevelopmentEnvironment();
}
public static void onInitialize() {
public void onInitialize() {
TagManager.ensureStaticallyLoaded();
SurfaceRuleRegistry.ensureStaticallyLoaded();

View file

@ -0,0 +1,26 @@
package org.betterx.worlds.together.biomesource;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import java.util.Set;
public interface BiomeSourceFromRegistry {
Registry<Biome> getBiomeRegistry();
Set<Holder<Biome>> possibleBiomes();
default boolean sameRegistryButDifferentBiomes(BiomeSourceFromRegistry other) {
if (other.getBiomeRegistry() == getBiomeRegistry()) {
Set<Holder<Biome>> mySet = this.possibleBiomes();
Set<Holder<Biome>> otherSet = other.possibleBiomes();
if (otherSet.size() != mySet.size()) return true;
for (Holder<Biome> b : mySet) {
if (!otherSet.contains(b))
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,5 @@
package org.betterx.worlds.together.biomesource;
public interface ReloadableBiomeSource {
void reloadBiomes();
}

View file

@ -1,5 +1,6 @@
package org.betterx.worlds.together.chunkgenerator;
import org.betterx.worlds.together.biomesource.BiomeSourceFromRegistry;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import net.minecraft.core.RegistryAccess;
@ -28,8 +29,14 @@ public interface EnforceableChunkGenerator<G extends ChunkGenerator> {
if (one == two) return false;
if (one instanceof BiomeSourceWithConfig<?, ?> ba && two instanceof BiomeSourceWithConfig<?, ?> bb) {
return !ba.getTogetherConfig().couldSetWithoutRepair(bb.getTogetherConfig());
if (!ba.getTogetherConfig().couldSetWithoutRepair(bb.getTogetherConfig()))
return true;
}
if (one instanceof BiomeSourceFromRegistry ba && two instanceof BiomeSourceFromRegistry bb) {
if (ba.sameRegistryButDifferentBiomes(bb))
return true;
}
return !one.getClass().isAssignableFrom(two.getClass()) && !two.getClass().isAssignableFrom(one.getClass());
}
}

View file

@ -4,6 +4,6 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.dimension.LevelStem;
public interface RestorableBiomeSource<G extends ChunkGenerator> {
public interface RestorableBiomeSource<B extends ChunkGenerator> {
void restoreInitialBiomeSource(ResourceKey<LevelStem> dimensionKey);
}

View file

@ -2,8 +2,10 @@ package org.betterx.worlds.together.client;
import org.betterx.worlds.together.worldPreset.client.WorldPresetsClient;
public class WorldsTogetherClient {
public static void onInitializeClient() {
import net.fabricmc.api.ClientModInitializer;
public class WorldsTogetherClient implements ClientModInitializer {
public void onInitializeClient() {
WorldPresetsClient.setupClientside();
}
}

View file

@ -0,0 +1,29 @@
package org.betterx.worlds.together.entrypoints;
import net.fabricmc.loader.api.FabricLoader;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class EntrypointUtil {
private static <T extends WorldsTogetherEntrypoint> List<T> getEntryPoints(boolean client, Class<T> select) {
return FabricLoader.getInstance()
.getEntrypoints(
client ? "worlds_together_client" : "worlds_together",
WorldsTogetherEntrypoint.class
)
.stream()
.filter(o -> select.isAssignableFrom(o.getClass()))
.map(e -> (T) e)
.toList();
}
public static <T extends WorldsTogetherEntrypoint> List<T> getCommon(Class<T> select) {
return getEntryPoints(false, select);
}
public static <T extends WorldsTogetherEntrypoint> List<T> getClient(Class<T> select) {
return getEntryPoints(true, select);
}
}

View file

@ -0,0 +1,5 @@
package org.betterx.worlds.together.entrypoints;
public interface WorldPresetBootstrap extends WorldsTogetherEntrypoint {
void bootstrapWorldPresets();
}

View file

@ -0,0 +1,4 @@
package org.betterx.worlds.together.entrypoints;
public interface WorldsTogetherEntrypoint {
}

View file

@ -3,9 +3,12 @@ package org.betterx.worlds.together.levelgen;
import org.betterx.bclib.util.MHelper;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.biomesource.BiomeSourceWithConfig;
import org.betterx.worlds.together.biomesource.ReloadableBiomeSource;
import org.betterx.worlds.together.chunkgenerator.EnforceableChunkGenerator;
import org.betterx.worlds.together.world.BiomeSourceWithNoiseRelatedSettings;
import org.betterx.worlds.together.world.BiomeSourceWithSeed;
import org.betterx.worlds.together.world.WorldConfig;
import org.betterx.worlds.together.world.event.WorldBootstrap;
import org.betterx.worlds.together.worldPreset.TogetherWorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPresets;
@ -20,6 +23,7 @@ import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.levelgen.structure.StructureSet;
@ -46,6 +50,11 @@ public class WorldGenUtil {
if (stem.generator().getBiomeSource() instanceof BiomeSourceWithSeed bcl) {
bcl.setSeed(seed);
}
if (stem.generator().getBiomeSource() instanceof BiomeSourceWithNoiseRelatedSettings bcl
&& stem.generator() instanceof NoiseBasedChunkGenerator noiseGenerator) {
bcl.onLoadGeneratorSettings(noiseGenerator.generatorSettings().value());
}
}
return settings;
@ -132,6 +141,7 @@ public class WorldGenUtil {
) {
var dimensions = TogetherWorldPreset.loadWorldDimensions();
for (var entry : settings.dimensions().entrySet()) {
boolean didRepair = false;
ResourceKey<LevelStem> key = entry.getKey();
LevelStem loadedStem = entry.getValue();
@ -147,6 +157,7 @@ public class WorldGenUtil {
loadedChunkGenerator,
settings
);
didRepair = true;
} else if (loadedChunkGenerator.getBiomeSource() instanceof BiomeSourceWithConfig bs) {
if (referenceGenerator.getBiomeSource() instanceof BiomeSourceWithConfig refbs) {
if (!refbs.getTogetherConfig().sameConfig(bs.getTogetherConfig())) {
@ -155,7 +166,26 @@ public class WorldGenUtil {
}
}
}
if (!didRepair) {
if (loadedStem.generator().getBiomeSource() instanceof ReloadableBiomeSource reload) {
reload.reloadBiomes();
}
}
}
return settings;
}
public static ResourceLocation getBiomeID(Biome biome) {
ResourceLocation id = null;
RegistryAccess access = WorldBootstrap.getLastRegistryAccessOrElseBuiltin();
id = access.registryOrThrow(Registry.BIOME_REGISTRY).getKey(biome);
if (id == null) {
WorldsTogether.LOGGER.error("Unable to get ID for " + biome + ".");
}
return id;
}
}

View file

@ -34,7 +34,7 @@ public class CreateWorldScreenMixin {
public WorldGenSettingsComponent worldGenSettingsComponent;
@Inject(method = "<init>", at = @At("TAIL"))
private void bcl_init(
private void wt_init(
Screen screen,
DataPackConfig dataPackConfig,
WorldGenSettingsComponent worldGenSettingsComponent,
@ -45,13 +45,13 @@ public class CreateWorldScreenMixin {
//Change the WorldPreset that is selected by default on the Create World Screen
@ModifyArg(method = "openFresh", index = 1, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/worldselection/WorldGenSettingsComponent;<init>(Lnet/minecraft/client/gui/screens/worldselection/WorldCreationContext;Ljava/util/Optional;Ljava/util/OptionalLong;)V"))
private static Optional<ResourceKey<WorldPreset>> bcl_NewDefault(Optional<ResourceKey<WorldPreset>> preset) {
private static Optional<ResourceKey<WorldPreset>> wt_NewDefault(Optional<ResourceKey<WorldPreset>> preset) {
return Optional.of(WorldPresets.getDEFAULT());
}
//Make sure the WorldGenSettings used to populate the create screen match the default WorldPreset
@ModifyArg(method = "openFresh", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/WorldLoader;load(Lnet/minecraft/server/WorldLoader$InitConfig;Lnet/minecraft/server/WorldLoader$WorldDataSupplier;Lnet/minecraft/server/WorldLoader$ResultFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
private static WorldLoader.WorldDataSupplier<WorldGenSettings> bcl_NewDefaultSettings(WorldLoader.WorldDataSupplier<WorldGenSettings> worldDataSupplier) {
private static WorldLoader.WorldDataSupplier<WorldGenSettings> wt_NewDefaultSettings(WorldLoader.WorldDataSupplier<WorldGenSettings> worldDataSupplier) {
return (resourceManager, dataPackConfig) -> {
Pair<WorldGenSettings, RegistryAccess.Frozen> res = worldDataSupplier.get(resourceManager, dataPackConfig);
return WorldGenUtil.defaultWorldDataSupplier(res.getSecond());
@ -60,7 +60,7 @@ public class CreateWorldScreenMixin {
//this is called when a new world is first created
@Inject(method = "createNewWorldDirectory", at = @At("RETURN"))
void bcl_createNewWorld(CallbackInfoReturnable<Optional<LevelStorageSource.LevelStorageAccess>> cir) {
void wt_createNewWorld(CallbackInfoReturnable<Optional<LevelStorageSource.LevelStorageAccess>> cir) {
WorldBootstrap.InGUI.registryReadyOnNewWorld(this.worldGenSettingsComponent);
WorldBootstrap.InGUI.setupNewWorld(cir.getReturnValue(), this.worldGenSettingsComponent);
}

View file

@ -32,7 +32,7 @@ public abstract class WorldOpenFlowsMixin {
protected abstract void doLoadLevel(Screen screen, String levelID, boolean safeMode, boolean canAskForBackup);
@Inject(method = "loadLevel", cancellable = true, at = @At("HEAD"))
private void bcl_callFixerOnLoad(Screen screen, String levelID, CallbackInfo ci) {
private void wt_callFixerOnLoad(Screen screen, String levelID, CallbackInfo ci) {
WorldBootstrap.InGUI.setupLoadedWorld(levelID, this.levelSource);
//if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> {
@ -53,7 +53,7 @@ public abstract class WorldOpenFlowsMixin {
}
@Inject(method = "createFreshLevel", at = @At("HEAD"))
public void bcl_createFreshLevel(
public void wt_createFreshLevel(
String levelID,
LevelSettings levelSettings,
RegistryAccess registryAccess,
@ -64,7 +64,7 @@ public abstract class WorldOpenFlowsMixin {
}
@Inject(method = "createLevelFromExistingSettings", at = @At("HEAD"))
public void bcl_createLevelFromExistingSettings(
public void wt_createLevelFromExistingSettings(
LevelStorageSource.LevelStorageAccess levelStorageAccess,
ReloadableServerResources reloadableServerResources,
RegistryAccess.Frozen frozen,

View file

@ -0,0 +1,35 @@
package org.betterx.worlds.together.mixin.common;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.worldPreset.WorldPresets;
import net.minecraft.server.dedicated.DedicatedServerProperties;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.Properties;
@Mixin(DedicatedServerProperties.class)
public class DedicatedServerPropertiesMixin {
//Make sure the default server properties use our Default World Preset by default (read from "level-type")
@ModifyArg(method = "<init>", index = 3, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/DedicatedServerProperties$WorldGenProperties;<init>(Ljava/lang/String;Lcom/google/gson/JsonObject;ZLjava/lang/String;)V"))
protected String wt_defaultPreset(String string) {
if (WorldsTogether.FORCE_SERVER_TO_BETTERX_PRESET) {
return WorldPresets.getDEFAULT().location().toString();
}
return string;
}
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/Settings;<init>(Ljava/util/Properties;)V"))
private static Properties wt_defaultPreset(Properties property) {
//init default value level preset in server.properties
property.setProperty(
"level-type",
property.getProperty("level-type", WorldPresets.getDEFAULT().location().toString())
);
return property;
}
}

View file

@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(Main.class)
@Mixin(value = Main.class, priority = 200)
abstract public class MainMixin {
@ModifyVariable(method = "main", ordinal = 0, at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;getSummary()Lnet/minecraft/world/level/storage/LevelSummary;"))
private static LevelStorageSource.LevelStorageAccess bc_createAccess(LevelStorageSource.LevelStorageAccess levelStorageAccess) {

View file

@ -15,14 +15,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(DedicatedServerProperties.WorldGenProperties.class)
public class WorldGenPropertiesMixin {
@Inject(method = "<init>", at = @At(value = "TAIL"))
private static void bcl_create(String seed, JsonObject jsonObject, boolean bl, String string2, CallbackInfo ci) {
return seed;
}
// @ModifyArg(method = "create", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/presets/WorldPreset;createWorldGenSettings(JZZ)Lnet/minecraft/world/level/levelgen/WorldGenSettings;"))
// public long bcl_create(long seed) {
// return seed;
// }
//Make sure Servers use our Default World Preset
@ModifyArg(method = "create", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/core/Registry;getHolder(Lnet/minecraft/resources/ResourceKey;)Ljava/util/Optional;"))
private ResourceKey<WorldPreset> bcl_foo(ResourceKey<WorldPreset> resourceKey) {
private ResourceKey<WorldPreset> wt_returnDefault(ResourceKey<WorldPreset> resourceKey) {
return WorldPresets.getDEFAULT();
}
}

View file

@ -0,0 +1,22 @@
package org.betterx.worlds.together.mixin.common;
import org.betterx.worlds.together.world.event.WorldBootstrap;
import net.minecraft.core.RegistryAccess;
import net.minecraft.server.WorldLoader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(WorldLoader.class)
public class WorldLoaderMixin {
//this is the place a new Registry access gets first istantiated
//either when a new Datapack was added to a world on the create-screen
//or because we did start world loading
@ModifyArg(method = "load", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ReloadableServerResources;loadResources(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/core/RegistryAccess$Frozen;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
private static RegistryAccess.Frozen wt_newRegistry(RegistryAccess.Frozen frozen) {
WorldBootstrap.InGUI.registryReady(frozen);
return frozen;
}
}

View file

@ -16,7 +16,7 @@ import org.jetbrains.annotations.ApiStatus;
public class SurfaceRuleRegistry {
public static final ResourceKey<Registry<AssignedSurfaceRule>> SURFACE_RULES_REGISTRY =
createRegistryKey(WorldsTogether.makeID("worldgen/surface_rules"));
createRegistryKey(WorldsTogether.makeID("worldgen/betterx/surface_rules"));
public static final Predicate<ResourceKey<LevelStem>> NON_MANAGED_DIMENSIONS = dim -> dim != LevelStem.NETHER && dim != LevelStem.END;
public static final Predicate<ResourceKey<LevelStem>> ALL_DIMENSIONS = dim -> true;

View file

@ -1,8 +1,8 @@
package org.betterx.worlds.together.tag.v3;
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
import org.betterx.bclib.api.v2.tag.TagAPI;
import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.mixin.common.DiggerItemAccessor;
import org.betterx.worlds.together.world.event.WorldEventsImpl;
import net.minecraft.core.DefaultedRegistry;
import net.minecraft.core.Registry;
@ -61,7 +61,7 @@ public class TagManager {
"tags/worldgen/biome",
(dir) -> new TagRegistry.Biomes(
dir,
b -> BiomeAPI.getBiomeID(b)
b -> WorldGenUtil.getBiomeID(b)
)
);
}
@ -104,7 +104,7 @@ public class TagManager {
String directory,
Map<ResourceLocation, Tag.Builder> tagsMap
) {
tagsMap = TagAPI.apply(directory, tagsMap);
WorldEventsImpl.BEFORE_ADDING_TAGS.emit(e -> e.apply(directory, tagsMap));
TagRegistry<?> type = TYPES.get(directory);
if (type != null) {

View file

@ -1,7 +1,7 @@
package org.betterx.worlds.together.tag.v3;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
import org.betterx.bclib.api.v2.levelgen.biomes.BCLBiome;
import org.betterx.worlds.together.WorldsTogether;
import net.minecraft.core.DefaultedRegistry;
import net.minecraft.core.Registry;
@ -188,7 +188,7 @@ public class TagRegistry<T> {
}
public void addUntyped(TagKey<T> tagID, ResourceLocation... elements) {
if (isFrozen) BCLib.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
if (isFrozen) WorldsTogether.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
Set<Tag.Entry> set = getSetForTag(tagID);
for (ResourceLocation id : elements) {
if (id != null) {
@ -204,7 +204,7 @@ public class TagRegistry<T> {
}
public void addOtherTags(TagKey<T> tagID, TagKey<T>... tags) {
if (isFrozen) BCLib.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
if (isFrozen) WorldsTogether.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
Set<Tag.Entry> set = getSetForTag(tagID);
for (TagKey<T> tag : tags) {
ResourceLocation id = tag.location();
@ -221,7 +221,7 @@ public class TagRegistry<T> {
* @param elements array of Elements to add into tag.
*/
protected void add(TagKey<T> tagID, T... elements) {
if (isFrozen) BCLib.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
if (isFrozen) WorldsTogether.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
Set<Tag.Entry> set = getSetForTag(tagID);
for (T element : elements) {
ResourceLocation id = locationProvider.apply(element);
@ -239,7 +239,7 @@ public class TagRegistry<T> {
@Deprecated(forRemoval = true)
protected void add(ResourceLocation tagID, T... elements) {
if (isFrozen) BCLib.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
if (isFrozen) WorldsTogether.LOGGER.warning("Adding Tag " + tagID + " after the API was frozen.");
Set<Tag.Entry> set = getSetForTag(tagID);
for (T element : elements) {
ResourceLocation id = locationProvider.apply(element);
@ -271,7 +271,7 @@ public class TagRegistry<T> {
Tag.Builder builder,
Set<Tag.Entry> ids
) {
ids.forEach(value -> builder.add(new Tag.BuilderEntry(value, BCLib.MOD_ID)));
ids.forEach(value -> builder.add(new Tag.BuilderEntry(value, WorldsTogether.MOD_ID)));
return builder;
}
}

View file

@ -0,0 +1,62 @@
package org.betterx.worlds.together.util;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
public final class Logger {
private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger();
private final String modPref;
public Logger(String modID) {
this.modPref = "[" + modID + "] ";
}
public void log(Level level, String message) {
LOGGER.log(level, modPref + message);
}
public void log(Level level, String message, Object... params) {
LOGGER.log(level, modPref + message, params);
}
public void debug(Object message) {
this.log(Level.DEBUG, message.toString());
}
public void debug(Object message, Object... params) {
this.log(Level.DEBUG, message.toString(), params);
}
public void catching(Throwable ex) {
this.error(ex.getLocalizedMessage());
LOGGER.catching(ex);
}
public void info(String message) {
this.log(Level.INFO, message);
}
public void info(String message, Object... params) {
this.log(Level.INFO, message, params);
}
public void warning(String message, Object... params) {
this.log(Level.WARN, message, params);
}
public void warning(String message, Object obj, Exception ex) {
LOGGER.warn(modPref + message, obj, ex);
}
public void error(String message) {
this.log(Level.ERROR, message);
}
public void error(String message, Object obj, Exception ex) {
LOGGER.error(modPref + message, obj, ex);
}
public void error(String message, Exception ex) {
LOGGER.error(modPref + message, ex);
}
}

View file

@ -1,6 +1,5 @@
package org.betterx.worlds.together.util;
import org.betterx.bclib.BCLib;
import org.betterx.worlds.together.WorldsTogether;
import net.fabricmc.loader.api.*;
@ -261,8 +260,6 @@ public class ModUtil {
* @return The version of the locally installed Mod
*/
public static String getModVersion(String modID) {
if (modID == WorldsTogether.MOD_ID) modID = BCLib.MOD_ID;
Optional<ModContainer> optional = FabricLoader.getInstance()
.getModContainer(modID);
if (optional.isPresent()) {

View file

@ -0,0 +1,7 @@
package org.betterx.worlds.together.world;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
public interface BiomeSourceWithNoiseRelatedSettings {
void onLoadGeneratorSettings(NoiseGeneratorSettings generator);
}

View file

@ -0,0 +1,14 @@
package org.betterx.worlds.together.world.event;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagLoader;
import java.util.List;
import java.util.Map;
public interface BeforeAddingTags {
void apply(
String directory,
Map<ResourceLocation, List<TagLoader.EntryWithSource>> tagsMap
);
}

View file

@ -4,7 +4,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
class EventImpl<T> implements Event<T> {
public class EventImpl<T> implements Event<T> {
final List<T> handlers = new LinkedList<>();
public final boolean on(T handler) {

View file

@ -1,6 +1,5 @@
package org.betterx.worlds.together.world.event;
import org.betterx.bclib.BCLib;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.mixin.common.RegistryOpsAccessor;
@ -55,10 +54,6 @@ public class WorldBootstrap {
private static void initializeWorldConfig(File levelBaseDir, boolean newWorld) {
WorldConfig.load(new File(levelBaseDir, "data"));
if (newWorld) {
WorldConfig.saveFile(BCLib.MOD_ID);
}
}
private static void onRegistryReady(RegistryAccess a) {
@ -114,7 +109,7 @@ public class WorldBootstrap {
public static void setupWorld(LevelStorageSource.LevelStorageAccess levelStorageAccess) {
File levelDat = levelStorageAccess.getLevelPath(LevelResource.LEVEL_DATA_FILE).toFile();
if (!levelDat.exists()) {
BCLib.LOGGER.info("Creating a new World, no fixes needed");
WorldsTogether.LOGGER.info("Creating a new World, no fixes needed");
final Map<ResourceKey<LevelStem>, ChunkGenerator> settings = Helpers.defaultServerDimensions();
Helpers.initializeWorldConfig(levelStorageAccess, true);
@ -158,6 +153,10 @@ public class WorldBootstrap {
}
}
public static void registryReady(RegistryAccess access) {
Helpers.onRegistryReady(access);
}
public static void setupNewWorld(
Optional<LevelStorageSource.LevelStorageAccess> levelStorageAccess,
WorldGenSettingsComponent worldGenSettingsComponent
@ -240,11 +239,11 @@ public class WorldBootstrap {
false
));
} catch (Exception e) {
BCLib.LOGGER.error("Failed to initialize data in world", e);
WorldsTogether.LOGGER.error("Failed to initialize data in world", e);
}
levelStorageAccess.close();
} catch (Exception e) {
BCLib.LOGGER.error("Failed to acquire storage access", e);
WorldsTogether.LOGGER.error("Failed to acquire storage access", e);
}
}
@ -259,7 +258,7 @@ public class WorldBootstrap {
result = WorldEventsImpl.PATCH_WORLD.applyPatches(levelStorageAccess, onResume);
levelStorageAccess.close();
} catch (Exception e) {
BCLib.LOGGER.error("Failed to initialize data in world", e);
WorldsTogether.LOGGER.error("Failed to initialize data in world", e);
}
return result;
@ -286,7 +285,7 @@ public class WorldBootstrap {
InGUI.setupNewWorldCommon(levelStorageAccess, worldPreset, worldGenSettings);
levelStorageAccess.close();
} catch (Exception e) {
BCLib.LOGGER.error("Failed to initialize data in world", e);
WorldsTogether.LOGGER.error("Failed to initialize data in world", e);
}
}
}
@ -314,7 +313,7 @@ public class WorldBootstrap {
return WorldGenUtil.repairBiomeSourceInAllDimensions(acc.bcl_getRegistryAccess(), worldGenSettings);
//.repairSettingsOnLoad(LAST_REGISTRY_ACCESS, worldGenSettings);
} else {
BCLib.LOGGER.error("Unable to obtain registryAccess when enforcing generators.");
WorldsTogether.LOGGER.error("Unable to obtain registryAccess when enforcing generators.");
}
return worldGenSettings;
}

View file

@ -8,4 +8,6 @@ public class WorldEvents {
public static final Event<OnFinalizeLevelStem> ON_FINALIZE_LEVEL_STEM = WorldEventsImpl.ON_FINALIZE_LEVEL_STEM;
public static final Event<OnWorldPatch> PATCH_WORLD = WorldEventsImpl.PATCH_WORLD;
public static final Event<OnAdaptWorldPresetSettings> ADAPT_WORLD_PRESET = WorldEventsImpl.ADAPT_WORLD_PRESET;
public static final Event<BeforeAddingTags> BEFORE_ADDING_TAGS = WorldEventsImpl.BEFORE_ADDING_TAGS;
}

View file

@ -1,6 +1,9 @@
package org.betterx.worlds.together.world.event;
class WorldEventsImpl {
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class WorldEventsImpl {
public static final EventImpl<OnWorldRegistryReady> WORLD_REGISTRY_READY = new EventImpl<>();
public static final EventImpl<BeforeWorldLoad> BEFORE_WORLD_LOAD = new EventImpl<>();
public static final EventImpl<BeforeServerWorldLoad> BEFORE_SERVER_WORLD_LOAD = new EventImpl<>();
@ -10,4 +13,6 @@ class WorldEventsImpl {
public static final PatchWorldEvent PATCH_WORLD = new PatchWorldEvent();
public static final AdaptWorldPresetSettingEvent ADAPT_WORLD_PRESET = new AdaptWorldPresetSettingEvent();
public static final EventImpl<BeforeAddingTags> BEFORE_ADDING_TAGS = new EventImpl<>();
}

View file

@ -1,7 +1,8 @@
package org.betterx.worlds.together.worldPreset;
import org.betterx.bclib.registry.PresetsRegistry;
import org.betterx.worlds.together.WorldsTogether;
import org.betterx.worlds.together.entrypoints.EntrypointUtil;
import org.betterx.worlds.together.entrypoints.WorldPresetBootstrap;
import org.betterx.worlds.together.levelgen.WorldGenUtil;
import org.betterx.worlds.together.tag.v3.TagManager;
import org.betterx.worlds.together.tag.v3.TagRegistry;
@ -109,7 +110,8 @@ public class WorldPresets {
WorldGenUtil.Context netherContext,
WorldGenUtil.Context endContext
) {
PresetsRegistry.onLoad();
EntrypointUtil.getCommon(WorldPresetBootstrap.class)
.forEach(e -> e.bootstrapWorldPresets());
for (Map.Entry<ResourceKey<WorldPreset>, PresetBuilder> e : BUILDERS.entrySet()) {
TogetherWorldPreset preset = e.getValue().create(overworldStem, netherContext, endContext);

View file

@ -1,8 +1,7 @@
package org.betterx.worlds.together.worldPreset.client;
import org.betterx.bclib.registry.PresetsRegistryClient;
import org.betterx.worlds.together.worldPreset.WorldPreset;
import org.betterx.worlds.together.worldPreset.WorldPreset;
import net.minecraft.resources.ResourceKey;
import net.fabricmc.api.EnvType;
@ -19,6 +18,5 @@ public class WorldPresetsClient {
}
public static void setupClientside() {
PresetsRegistryClient.onLoad();
}
}

View file

@ -9,6 +9,8 @@ accessible class net/minecraft/world/level/levelgen/SurfaceRules$LazyXZCondition
accessible class net/minecraft/world/level/levelgen/SurfaceRules$LazyCondition
accessible class net/minecraft/world/level/levelgen/SurfaceRules$SequenceRuleSource
extendable class net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator
accessible class net/minecraft/data/BuiltinRegistries$RegistryBootstrap
accessible class net/minecraft/core/Registry$RegistryBootstrap
accessible class net/minecraft/world/level/levelgen/SurfaceRules$SequenceRuleSource
accessible class net/minecraft/core/Registry$RegistryBootstrap
accessible class net/minecraft/tags/Tag$ElementEntry
@ -27,3 +29,5 @@ accessible field net/minecraft/client/gui/screens/worldselection/WorldPreset SIN
accessible field net/minecraft/client/gui/screens/worldselection/WorldPreset PRESETS Ljava/util/List;
accessible field net/minecraft/client/gui/screens/worldselection/WorldPreset EDITORS Ljava/util/Map;
accessible method net/minecraft/core/Registry registerSimple (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/Registry$RegistryBootstrap;)Lnet/minecraft/core/Registry;

View file

@ -10,12 +10,12 @@
"BiomeMixin",
"BiomeSourceMixin",
"BoneMealItemMixin",
"BuiltinRegistriesMixin",
"ChunkGeneratorAccessor",
"ChunkGeneratorMixin",
"ChunkGeneratorsMixin",
"ComposterBlockAccessor",
"CraftingMenuMixin",
"DedicatedServerPropertiesMixin",
"DiggerItemMixin",
"EnchantingTableBlockMixin",
"ItemStackMixin",
@ -29,11 +29,12 @@
"PotionBrewingAccessor",
"RecipeManagerAccessor",
"RecipeManagerMixin",
"RegistryAccessMixin",
"ServerLevelMixin",
"ShovelItemAccessor",
"StructuresAccessor",
"SurfaceRulesContextAccessor",
"TheEndBiomeDataMixin",
"TheEndBiomesMixin",
"WorldGenRegionMixin",
"elytra.LivingEntityMixin",
"shears.BeehiveBlockMixin",

View file

@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"id": "bclib",
"version": "2.0.8",
"version": "2.0.11",
"name": "BCLib",
"description": "A library for BetterX team mods",
"authors": [
@ -29,6 +29,9 @@
],
"modmenu": [
"org.betterx.bclib.integration.modmenu.ModMenuEntryPoint"
],
"worlds_together": [
"org.betterx.bclib.registry.PresetsRegistry"
]
},
"accessWidener": "bclib.accesswidener",

View file

@ -5,6 +5,7 @@
"compatibilityLevel": "JAVA_17",
"mixins": [
"BuiltinRegistriesMixin",
"DedicatedServerPropertiesMixin",
"DiggerItemAccessor",
"MainMixin",
"MinecraftServerMixin",
@ -16,6 +17,7 @@
"RegistryOpsAccessor",
"TagLoaderMixin",
"WorldGenPropertiesMixin",
"WorldLoaderMixin",
"WorldPresetAccessor",
"WorldPresetMixin",
"WorldPresetsBootstrapMixin"