[Feature] Auto Detect End-Datapacks and disable custom Terrain Generation
This commit is contained in:
parent
c93a942eee
commit
def4fc3566
8 changed files with 140 additions and 42 deletions
|
@ -24,7 +24,7 @@ import java.util.Optional;
|
||||||
* <p>
|
* <p>
|
||||||
* This class provides the ability for mod to store persistent data inside a world. The Storage for the world is
|
* This class provides the ability for mod to store persistent data inside a world. The Storage for the world is
|
||||||
* currently initialized as part of the {@link org.betterx.bclib.presets.worldgen.WorldBootstrap} in
|
* currently initialized as part of the {@link org.betterx.bclib.presets.worldgen.WorldBootstrap} in
|
||||||
* {@link org.betterx.bclib.presets.worldgen.WorldBootstrap#initializeWorldDataAPI(File, boolean)}
|
* org.betterx.bclib.presets.worldgen.WorldBootstrap.Helpers#initializeWorldDataAPI(File, boolean)
|
||||||
*/
|
*/
|
||||||
public class WorldDataAPI {
|
public class WorldDataAPI {
|
||||||
private static final Map<String, CompoundTag> TAGS = Maps.newHashMap();
|
private static final Map<String, CompoundTag> TAGS = Maps.newHashMap();
|
||||||
|
|
|
@ -16,7 +16,9 @@ import org.betterx.bclib.presets.worldgen.BCLWorldPresetSettings;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.QuartPos;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.resources.RegistryOps;
|
import net.minecraft.resources.RegistryOps;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.tags.BiomeTags;
|
import net.minecraft.tags.BiomeTags;
|
||||||
|
@ -25,6 +27,7 @@ import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.Biomes;
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
import net.minecraft.world.level.biome.Climate;
|
import net.minecraft.world.level.biome.Climate;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
||||||
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
||||||
import net.minecraft.world.level.levelgen.synth.SimplexNoise;
|
import net.minecraft.world.level.levelgen.synth.SimplexNoise;
|
||||||
|
@ -235,6 +238,7 @@ public class BCLibEndBiomeSource extends BCLBiomeSource {
|
||||||
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_VOID);
|
BiomeAPI.wasRegisteredAs(location, BiomeAPI.BiomeType.BCL_END_VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static float getLegacyHeightValue(SimplexNoise simplexNoise, int i, int j) {
|
public static float getLegacyHeightValue(SimplexNoise simplexNoise, int i, int j) {
|
||||||
int k = i / 2;
|
int k = i / 2;
|
||||||
int l = j / 2;
|
int l = j / 2;
|
||||||
|
@ -298,46 +302,72 @@ public class BCLibEndBiomeSource extends BCLBiomeSource {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Holder<Biome> getNoiseBiomeVanilla(int biomeX, int biomeY, int biomeZ, Climate.Sampler sampler) {
|
||||||
|
int posX = QuartPos.toBlock(biomeX);
|
||||||
|
int posY = QuartPos.toBlock(biomeY);
|
||||||
|
int posZ = QuartPos.toBlock(biomeZ);
|
||||||
|
int sectionX = SectionPos.blockToSectionCoord(posX);
|
||||||
|
int sectionZ = SectionPos.blockToSectionCoord(posZ);
|
||||||
|
long farEndBiomes = GeneratorOptions.getFarEndBiomes();
|
||||||
|
|
||||||
|
if ((long) sectionX * (long) sectionX + (long) sectionZ * (long) sectionZ <= 4096L) {
|
||||||
|
return this.centerBiome;
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
return d < -0.21875 ? mapVoid.getBiome(posX, biomeY << 2, posZ).biome : this.barrens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler sampler) {
|
public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler sampler) {
|
||||||
if (mapLand == null || mapVoid == null)
|
if (mapLand == null || mapVoid == null)
|
||||||
return this.possibleBiomes().stream().findFirst().get();
|
return this.possibleBiomes().stream().findFirst().get();
|
||||||
long posX = biomeX << 2;
|
|
||||||
long posZ = biomeZ << 2;
|
|
||||||
long farEndBiomes = GeneratorOptions.getFarEndBiomes();
|
|
||||||
long dist = posX * posX + posZ * posZ;
|
|
||||||
|
|
||||||
if ((biomeX & 63) == 0 && (biomeZ & 63) == 0) {
|
return getNoiseBiomeVanilla(biomeX, biomeY, biomeZ, sampler);
|
||||||
mapLand.clearCache();
|
|
||||||
mapVoid.clearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endLandFunction == null) {
|
// long posX = biomeX << 2;
|
||||||
if (dist <= farEndBiomes) return centerBiome;
|
// long posZ = biomeZ << 2;
|
||||||
float height = getLegacyHeightValue(
|
// long farEndBiomes = GeneratorOptions.getFarEndBiomes();
|
||||||
noise,
|
// long dist = posX * posX + posZ * posZ;
|
||||||
(biomeX >> 1) + 1,
|
//
|
||||||
(biomeZ >> 1) + 1
|
// if ((biomeX & 63) == 0 && (biomeZ & 63) == 0) {
|
||||||
) + (float) SMALL_NOISE.eval(biomeX, biomeZ) * 5;
|
// mapLand.clearCache();
|
||||||
|
// mapVoid.clearCache();
|
||||||
if (height > -20F && height < -5F) {
|
// }
|
||||||
return barrens;
|
//
|
||||||
}
|
// if (endLandFunction == null) {
|
||||||
|
// if (dist <= farEndBiomes) return centerBiome;
|
||||||
if (height < -10F) {
|
// float height = getLegacyHeightValue(
|
||||||
return mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
|
// noise,
|
||||||
} else {
|
// (biomeX >> 1) + 1,
|
||||||
return mapLand.getBiome(posX, biomeY << 2, posZ).biome;
|
// (biomeZ >> 1) + 1
|
||||||
}
|
// ) + (float) SMALL_NOISE.eval(biomeX, biomeZ) * 5;
|
||||||
} else {
|
//
|
||||||
pos.setLocation(biomeX, biomeZ);
|
// if (height > -20F && height < -5F) {
|
||||||
if (endLandFunction.apply(pos, maxHeight)) {
|
// return barrens;
|
||||||
return dist <= farEndBiomes ? centerBiome : mapLand.getBiome(posX, biomeY << 2, posZ).biome;
|
// }
|
||||||
} else {
|
//
|
||||||
return dist <= farEndBiomes ? barrens : mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
|
// if (height < -10F) {
|
||||||
}
|
// return mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
|
||||||
}
|
// } else {
|
||||||
|
// return mapLand.getBiome(posX, biomeY << 2, posZ).biome;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// pos.setLocation(biomeX, biomeZ);
|
||||||
|
// if (endLandFunction.apply(pos, maxHeight)) {
|
||||||
|
// return dist <= farEndBiomes ? centerBiome : mapLand.getBiome(posX, biomeY << 2, posZ).biome;
|
||||||
|
// } else {
|
||||||
|
// return dist <= farEndBiomes ? barrens : mapVoid.getBiome(posX, biomeY << 2, posZ).biome;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -353,6 +353,7 @@ public class LevelGenUtil {
|
||||||
BCLWorldPreset.writeWorldPresetSettings(new BCLWorldPresetSettings(
|
BCLWorldPreset.writeWorldPresetSettings(new BCLWorldPresetSettings(
|
||||||
biomeSourceVersion,
|
biomeSourceVersion,
|
||||||
biomeSourceVersion,
|
biomeSourceVersion,
|
||||||
|
true,
|
||||||
true
|
true
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
private GridCheckboxCell bclibNether;
|
private GridCheckboxCell bclibNether;
|
||||||
GridCheckboxCell endLegacy;
|
GridCheckboxCell endLegacy;
|
||||||
GridCheckboxCell endCustomTerrain;
|
GridCheckboxCell endCustomTerrain;
|
||||||
|
GridCheckboxCell generateEndVoid;
|
||||||
GridCheckboxCell netherLegacy;
|
GridCheckboxCell netherLegacy;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,6 +49,7 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
final int netherVersion;
|
final int netherVersion;
|
||||||
final int endVersion;
|
final int endVersion;
|
||||||
final boolean customEndGen;
|
final boolean customEndGen;
|
||||||
|
final boolean haveEndVoid;
|
||||||
if (createWorldScreen.worldGenSettingsComponent instanceof WorldGenSettingsComponentAccessor acc
|
if (createWorldScreen.worldGenSettingsComponent instanceof WorldGenSettingsComponentAccessor acc
|
||||||
&& acc.bcl_getPreset()
|
&& acc.bcl_getPreset()
|
||||||
.isPresent() && acc.bcl_getPreset()
|
.isPresent() && acc.bcl_getPreset()
|
||||||
|
@ -57,6 +59,7 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
netherVersion = settings.netherVersion;
|
netherVersion = settings.netherVersion;
|
||||||
endVersion = settings.endVersion;
|
endVersion = settings.endVersion;
|
||||||
customEndGen = settings.useEndTerrainGenerator;
|
customEndGen = settings.useEndTerrainGenerator;
|
||||||
|
haveEndVoid = settings.generateEndVoid;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("The WorldSetup Screen is only valid for BetterX Presets.");
|
throw new IllegalStateException("The WorldSetup Screen is only valid for BetterX Presets.");
|
||||||
}
|
}
|
||||||
|
@ -114,7 +117,18 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
(state) -> {
|
(state) -> {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
row = colEnd.addRow();
|
||||||
|
row.addSpacer(20);
|
||||||
|
generateEndVoid = row.addCheckbox(
|
||||||
|
Component.translatable("title.screen.bclib.worldgen.end_void"),
|
||||||
|
haveEndVoid,
|
||||||
|
1.0,
|
||||||
|
GridLayout.GridValueType.PERCENTAGE,
|
||||||
|
(state) -> {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
row = colEnd.addRow();
|
row = colEnd.addRow();
|
||||||
row.addSpacer(20);
|
row.addSpacer(20);
|
||||||
endLegacy = row.addCheckbox(
|
endLegacy = row.addCheckbox(
|
||||||
|
@ -135,6 +149,7 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
(state) -> {
|
(state) -> {
|
||||||
endLegacy.setEnabled(state);
|
endLegacy.setEnabled(state);
|
||||||
endCustomTerrain.setEnabled(state);
|
endCustomTerrain.setEnabled(state);
|
||||||
|
generateEndVoid.setEnabled(state);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -174,7 +189,8 @@ public class WorldSetupScreen extends BCLibScreen {
|
||||||
acc.bcl_setPreset(Optional.of(Holder.direct(worldPreset.withSettings(new BCLWorldPresetSettings(
|
acc.bcl_setPreset(Optional.of(Holder.direct(worldPreset.withSettings(new BCLWorldPresetSettings(
|
||||||
netherVersion,
|
netherVersion,
|
||||||
endVersion,
|
endVersion,
|
||||||
endCustomTerrain.isChecked()
|
endCustomTerrain.isChecked(),
|
||||||
|
generateEndVoid.isChecked()
|
||||||
)))));
|
)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,22 +43,33 @@ public class BCLWorldPresetSettings extends WorldPresetSettings {
|
||||||
Codec.BOOL
|
Codec.BOOL
|
||||||
.fieldOf("custom_end_terrain")
|
.fieldOf("custom_end_terrain")
|
||||||
.orElse(true)
|
.orElse(true)
|
||||||
.forGetter(o -> o.useEndTerrainGenerator)
|
.forGetter(o -> o.useEndTerrainGenerator),
|
||||||
|
Codec.BOOL
|
||||||
|
.fieldOf("generate_end_void")
|
||||||
|
.orElse(true)
|
||||||
|
.forGetter(o -> o.generateEndVoid)
|
||||||
)
|
)
|
||||||
.apply(builderInstance, builderInstance.stable(BCLWorldPresetSettings::new));
|
.apply(builderInstance, builderInstance.stable(BCLWorldPresetSettings::new));
|
||||||
});
|
});
|
||||||
public final int netherVersion;
|
public final int netherVersion;
|
||||||
public final int endVersion;
|
public final int endVersion;
|
||||||
public final boolean useEndTerrainGenerator;
|
public final boolean useEndTerrainGenerator;
|
||||||
|
public final boolean generateEndVoid;
|
||||||
|
|
||||||
public BCLWorldPresetSettings(int version) {
|
public BCLWorldPresetSettings(int version) {
|
||||||
this(version, version, true);
|
this(version, version, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BCLWorldPresetSettings(int netherVersion, int endVersion, boolean useEndTerrainGenerator) {
|
public BCLWorldPresetSettings(
|
||||||
|
int netherVersion,
|
||||||
|
int endVersion,
|
||||||
|
boolean useEndTerrainGenerator,
|
||||||
|
boolean generateEndVoid
|
||||||
|
) {
|
||||||
this.netherVersion = netherVersion;
|
this.netherVersion = netherVersion;
|
||||||
this.endVersion = endVersion;
|
this.endVersion = endVersion;
|
||||||
this.useEndTerrainGenerator = endVersion != BCLibEndBiomeSource.BIOME_SOURCE_VERSION_VANILLA && useEndTerrainGenerator;
|
this.useEndTerrainGenerator = endVersion != BCLibEndBiomeSource.BIOME_SOURCE_VERSION_VANILLA && useEndTerrainGenerator;
|
||||||
|
this.generateEndVoid = generateEndVoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.betterx.bclib.api.v2.LifeCycleAPI;
|
||||||
import org.betterx.bclib.api.v2.WorldDataAPI;
|
import org.betterx.bclib.api.v2.WorldDataAPI;
|
||||||
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
|
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
|
||||||
import org.betterx.bclib.api.v2.datafixer.DataFixerAPI;
|
import org.betterx.bclib.api.v2.datafixer.DataFixerAPI;
|
||||||
|
import org.betterx.bclib.api.v2.generator.BCLibEndBiomeSource;
|
||||||
import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
|
import org.betterx.bclib.api.v2.levelgen.LevelGenUtil;
|
||||||
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
|
import org.betterx.bclib.api.v2.levelgen.biomes.InternalBiomeAPI;
|
||||||
import org.betterx.bclib.interfaces.WorldGenSettingsComponentAccessor;
|
import org.betterx.bclib.interfaces.WorldGenSettingsComponentAccessor;
|
||||||
|
@ -14,6 +15,8 @@ import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.resources.RegistryOps;
|
import net.minecraft.resources.RegistryOps;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||||
import net.minecraft.world.level.levelgen.presets.WorldPreset;
|
import net.minecraft.world.level.levelgen.presets.WorldPreset;
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
|
@ -92,7 +95,7 @@ public class WorldBootstrap {
|
||||||
Helpers.initializeWorldDataAPI(levelStorageAccess.get(), true);
|
Helpers.initializeWorldDataAPI(levelStorageAccess.get(), true);
|
||||||
|
|
||||||
if (worldGenSettingsComponent instanceof WorldGenSettingsComponentAccessor acc) {
|
if (worldGenSettingsComponent instanceof WorldGenSettingsComponentAccessor acc) {
|
||||||
BCLWorldPreset.writeWorldPresetSettings(acc.bcl_getPreset());
|
BCLWorldPreset.writeWorldPresetSettings(adaptPresetForDatapacks(acc, worldGenSettingsComponent));
|
||||||
}
|
}
|
||||||
|
|
||||||
DataFixerAPI.initializePatchData();
|
DataFixerAPI.initializePatchData();
|
||||||
|
@ -138,6 +141,41 @@ public class WorldBootstrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Optional<Holder<WorldPreset>> adaptPresetForDatapacks(
|
||||||
|
WorldGenSettingsComponentAccessor accessor,
|
||||||
|
WorldGenSettingsComponent component
|
||||||
|
) {
|
||||||
|
LevelStem endStem = component.settings().worldGenSettings().dimensions().get(LevelStem.END);
|
||||||
|
Optional<Holder<WorldPreset>> currentPreset = accessor.bcl_getPreset();
|
||||||
|
|
||||||
|
//We probably loaded a Datapack for the End
|
||||||
|
if (!(endStem.generator().getBiomeSource() instanceof BCLibEndBiomeSource)) {
|
||||||
|
BCLib.LOGGER.info("Detected Datapack for END.");
|
||||||
|
|
||||||
|
if (currentPreset.isPresent()) {
|
||||||
|
if (currentPreset.get().value() instanceof BCLWorldPreset worldPreset) {
|
||||||
|
ResourceKey key = currentPreset.get().unwrapKey().orElse(null);
|
||||||
|
//user did not configure the Preset!
|
||||||
|
if (BCLWorldPresets.BCL_WORLD.equals(key) || BCLWorldPresets.BCL_WORLD_17.equals(key)) {
|
||||||
|
if (worldPreset.settings instanceof BCLWorldPresetSettings settings) {
|
||||||
|
BCLib.LOGGER.info("Changing Default WorldPreset Settings for Datapack use.");
|
||||||
|
|
||||||
|
worldPreset = worldPreset.withSettings(new BCLWorldPresetSettings(
|
||||||
|
settings.netherVersion,
|
||||||
|
settings.endVersion,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
));
|
||||||
|
currentPreset = Optional.of(Holder.direct(worldPreset));
|
||||||
|
accessor.bcl_setPreset(currentPreset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currentPreset;
|
||||||
|
}
|
||||||
|
|
||||||
public static WorldGenSettings enforceInNewWorld(WorldGenSettings worldGenSettings) {
|
public static WorldGenSettings enforceInNewWorld(WorldGenSettings worldGenSettings) {
|
||||||
worldGenSettings = LevelGenUtil
|
worldGenSettings = LevelGenUtil
|
||||||
.getWorldSettings()
|
.getWorldSettings()
|
||||||
|
|
|
@ -56,5 +56,6 @@
|
||||||
"title.bclib.the_end": "Das Ende",
|
"title.bclib.the_end": "Das Ende",
|
||||||
"title.screen.bclib.worldgen.custom_biome_source": "Benutzerdefinierte Biomquelle verwenden",
|
"title.screen.bclib.worldgen.custom_biome_source": "Benutzerdefinierte Biomquelle verwenden",
|
||||||
"title.screen.bclib.worldgen.legacy_square": "Legacy-Verteilung (1.17)",
|
"title.screen.bclib.worldgen.legacy_square": "Legacy-Verteilung (1.17)",
|
||||||
"title.screen.bclib.worldgen.custom_end_terrain": "Angepasster End-Terrain-Generator"
|
"title.screen.bclib.worldgen.custom_end_terrain": "Angepasster End-Terrain-Generator",
|
||||||
|
"title.screen.bclib.worldgen.end_void": "Kleine End-Inseln erzeugen"
|
||||||
}
|
}
|
|
@ -57,5 +57,6 @@
|
||||||
"title.bclib.the_end": "The End",
|
"title.bclib.the_end": "The End",
|
||||||
"title.screen.bclib.worldgen.custom_biome_source": "Use Custom Biome Source",
|
"title.screen.bclib.worldgen.custom_biome_source": "Use Custom Biome Source",
|
||||||
"title.screen.bclib.worldgen.legacy_square": "Use Legacy Map (1.17)",
|
"title.screen.bclib.worldgen.legacy_square": "Use Legacy Map (1.17)",
|
||||||
"title.screen.bclib.worldgen.custom_end_terrain": "Custom End Terrain Generator"
|
"title.screen.bclib.worldgen.custom_end_terrain": "Custom End Terrain Generator",
|
||||||
|
"title.screen.bclib.worldgen.end_void": "Generate small Islands"
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue