First pass on data driven worldgen

This commit is contained in:
modmuss50 2020-11-01 20:08:19 +00:00
parent 1d00090cb4
commit 98857f5119
29 changed files with 1424 additions and 330 deletions

View file

@ -24,6 +24,7 @@
package techreborn.init;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.block.*;
@ -33,6 +34,7 @@ import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.structure.rule.RuleTest;
import net.minecraft.util.Identifier;
import reborncore.api.blockentity.IUpgrade;
import reborncore.common.fluid.FluidValue;
import reborncore.common.powerSystem.PowerAcceptorBlockEntity;
@ -83,11 +85,11 @@ import techreborn.items.tool.MiningLevel;
import techreborn.utils.InitUtils;
import org.jetbrains.annotations.Nullable;
import techreborn.world.TechRebornOre;
import techreborn.world.WorldTargetType;
import techreborn.world.DataDrivenFeature;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class TRContent {
@ -418,8 +420,8 @@ public class TRContent {
return block.asItem();
}
public TechRebornOre asNewOres(WorldTargetType targetType, RuleTest ruleTest) {
return new TechRebornOre(targetType, ruleTest, block.getDefaultState(), maxY, veinSize, veinsPerChunk);
public DataDrivenFeature asNewOres(Identifier identifier, Predicate<BiomeSelectionContext> targetType, RuleTest ruleTest) {
return new DataDrivenFeature(identifier, targetType, ruleTest, block.getDefaultState(), maxY, veinSize, veinsPerChunk);
}
}

View file

@ -0,0 +1,62 @@
package techreborn.world;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
import net.minecraft.util.Util;
import net.minecraft.world.biome.Biome;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
public class BiomeSelectorDeserialiser {
private static final Map<String, Predicate<BiomeSelectionContext>> SIMPLE_SELECTOR_MAP = Util.make(new HashMap<>(), map -> {
map.put("all", BiomeSelectors.all());
map.put("overworld", BiomeSelectors.foundInOverworld());
map.put("end", BiomeSelectors.foundInTheEnd());
map.put("nether", BiomeSelectors.foundInTheNether());
});
public static Predicate<BiomeSelectionContext> deserialise(JsonElement jsonElement) {
if (jsonElement.isJsonPrimitive() && jsonElement.getAsJsonPrimitive().isString()) {
Predicate<BiomeSelectionContext> selector = SIMPLE_SELECTOR_MAP.get(jsonElement.getAsString().toLowerCase(Locale.ROOT));
if (selector == null) {
throw new JsonParseException("Could not find selector for " + jsonElement.getAsString());
}
return selector;
}
if (jsonElement.isJsonArray()) {
JsonArray jsonArray = jsonElement.getAsJsonArray();
Set<Biome.Category> categorySet = EnumSet.noneOf(Biome.Category.class);
for (JsonElement element : jsonArray) {
if (!(element.isJsonPrimitive() && element.getAsJsonPrimitive().isString())) {
throw new JsonParseException("json array must only contain strings");
}
Biome.Category category = Biome.Category.byName(element.getAsString());
if (category == null) {
throw new JsonParseException("Could not find biome category: " + element.getAsString());
}
categorySet.add(category);
}
return context -> categorySet.contains(context.getBiome().getCategory());
}
// TODO support more complex selectors here
throw new JsonParseException("Could not parse biome selector");
}
}

View file

@ -0,0 +1,129 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.world;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.JsonOps;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.minecraft.block.BlockState;
import net.minecraft.structure.rule.RuleTest;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.Predicate;
public class DataDrivenFeature {
private static final Logger LOGGER = LogManager.getLogger();
private final Predicate<BiomeSelectionContext> biomeSelector;
private final ConfiguredFeature<?, ?> configuredFeature;
private final GenerationStep.Feature generationStep;
private final Identifier identifier;
public DataDrivenFeature(Identifier identifier, Predicate<BiomeSelectionContext> biomeSelector, ConfiguredFeature<?, ?> configuredFeature, GenerationStep.Feature generationStep) {
this.identifier = identifier;
this.biomeSelector = biomeSelector;
this.configuredFeature = configuredFeature;
this.generationStep = generationStep;
}
@Deprecated
public DataDrivenFeature(Identifier identifier, Predicate<BiomeSelectionContext> biomeSelector, RuleTest ruleTest, BlockState blockState, int maxY, int veinSize, int veinCount) {
this(identifier, biomeSelector, Feature.ORE.configure(
new OreFeatureConfig(ruleTest, blockState, veinSize)
)
.method_30377(maxY)
.spreadHorizontally()
.repeat(veinCount), GenerationStep.Feature.UNDERGROUND_ORES);
}
public static DataDrivenFeature deserialise(Identifier identifier, JsonObject jsonObject) {
if (!JsonHelper.hasElement(jsonObject, "biomeSelector")) {
throw new JsonParseException("Could not find biomeSelector element");
}
Predicate<BiomeSelectionContext> biomeSelector = BiomeSelectorDeserialiser.deserialise(jsonObject.get("biomeSelector"));
if (!JsonHelper.hasElement(jsonObject, "configuredFeature")) {
throw new JsonParseException("Could not find configuredFeature element");
}
DataResult<ConfiguredFeature<?, ?>> dataResult = ConfiguredFeature.CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, jsonObject.get("configuredFeature")));
ConfiguredFeature<?, ?> configuredFeature = dataResult.getOrThrow(true, s -> {
throw new JsonParseException(s);
});
if (!JsonHelper.hasElement(jsonObject, "generationStep")) {
throw new JsonParseException("Could not find generationStep element");
}
DataResult<WorldGenCodecs.GenerationStepFeature> genStepDataResult = WorldGenCodecs.GenerationStepFeature.CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, jsonObject.get("generationStep")));
GenerationStep.Feature generationStep = genStepDataResult.getOrThrow(true, s -> {
throw new JsonParseException(s);
}).getFeature();
return new DataDrivenFeature(identifier, biomeSelector, configuredFeature, generationStep);
}
public JsonObject serialise() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("biomeSelector", "overworld");
jsonObject.add("generationStep", WorldGenCodecs.GenerationStepFeature.CODEC.encodeStart(JsonOps.INSTANCE, WorldGenCodecs.GenerationStepFeature.byFeature(generationStep)).getOrThrow(true, LOGGER::error));
jsonObject.add("configuredFeature", ConfiguredFeature.CODEC.encodeStart(JsonOps.INSTANCE, configuredFeature).getOrThrow(true, LOGGER::error));
return jsonObject;
}
public ConfiguredFeature<?, ?> getConfiguredFeature() {
return configuredFeature;
}
public RegistryKey<ConfiguredFeature<?, ?>> getRegistryKey() {
return RegistryKey.of(BuiltinRegistries.CONFIGURED_FEATURE.getKey(), identifier);
}
public Identifier getIdentifier() {
return identifier;
}
public GenerationStep.Feature getGenerationStep() {
return generationStep;
}
public Predicate<BiomeSelectionContext> getBiomeSelector() {
return biomeSelector;
}
}

View file

@ -24,11 +24,18 @@
package techreborn.world;
import com.google.gson.JsonElement;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
import net.minecraft.block.Blocks;
import net.minecraft.structure.rule.BlockStateMatchRuleTest;
import net.minecraft.structure.rule.RuleTest;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.util.math.Direction;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.UniformIntDistribution;
import net.minecraft.world.gen.decorator.ChanceDecoratorConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;
@ -39,23 +46,25 @@ import net.minecraft.world.gen.stateprovider.SimpleBlockStateProvider;
import net.minecraft.world.gen.stateprovider.WeightedBlockStateProvider;
import net.minecraft.world.gen.trunk.StraightTrunkPlacer;
import org.apache.logging.log4j.util.TriConsumer;
import reborncore.common.util.IdentifiableObject;
import techreborn.blocks.misc.BlockRubberLog;
import techreborn.config.TechRebornConfig;
import techreborn.init.TRContent;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class DefaultWorldGen {
private static final RuleTest END_STONE = new BlockStateMatchRuleTest(Blocks.END_STONE.getDefaultState());
public static WorldGenConfig getDefaultWorldGen() {
return new WorldGenConfig(getOres(), getRubberTree());
}
private static ConfiguredFeature<?, ?> getRubberTree() {
WeightedBlockStateProvider logProvider = new WeightedBlockStateProvider();
logProvider.addState(TRContent.RUBBER_LOG.getDefaultState(), 10);
@ -83,30 +92,53 @@ public class DefaultWorldGen {
));
}
private static List<TechRebornOre> getOres() {
List<TechRebornOre> ores = new ArrayList<>();
TriConsumer<WorldTargetType, RuleTest, TRContent.Ores> addOre = (worldTargetType, ruleTest, ore) -> ores.add(ore.asNewOres(worldTargetType, ruleTest));
public static List<DataDrivenFeature> getDefaultFeatures() {
List<DataDrivenFeature> features = new ArrayList<>();
TriConsumer<Predicate<BiomeSelectionContext>, RuleTest, TRContent.Ores> addOre = (worldTargetType, ruleTest, ore) ->
features.add(ore.asNewOres(new Identifier("techreborn", Registry.BLOCK.getId(ore.block).getPath()), worldTargetType, ruleTest));
addOre.accept(WorldTargetType.NETHER, OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.CINNABAR);
addOre.accept(WorldTargetType.NETHER, OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.PYRITE);
addOre.accept(WorldTargetType.NETHER, OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.SPHALERITE);
addOre.accept(BiomeSelectors.foundInTheNether(), OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.CINNABAR);
addOre.accept(BiomeSelectors.foundInTheNether(), OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.PYRITE);
addOre.accept(BiomeSelectors.foundInTheNether(), OreFeatureConfig.Rules.BASE_STONE_NETHER, TRContent.Ores.SPHALERITE);
addOre.accept(WorldTargetType.END, END_STONE, TRContent.Ores.PERIDOT);
addOre.accept(WorldTargetType.END, END_STONE, TRContent.Ores.SHELDONITE);
addOre.accept(WorldTargetType.END, END_STONE, TRContent.Ores.SODALITE);
addOre.accept(WorldTargetType.END, END_STONE, TRContent.Ores.TUNGSTEN);
addOre.accept(BiomeSelectors.foundInTheEnd(), END_STONE, TRContent.Ores.PERIDOT);
addOre.accept(BiomeSelectors.foundInTheEnd(), END_STONE, TRContent.Ores.SHELDONITE);
addOre.accept(BiomeSelectors.foundInTheEnd(), END_STONE, TRContent.Ores.SODALITE);
addOre.accept(BiomeSelectors.foundInTheEnd(), END_STONE, TRContent.Ores.TUNGSTEN);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.BAUXITE);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.COPPER);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.GALENA);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.IRIDIUM);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.LEAD);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.RUBY);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.SAPPHIRE);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.SILVER);
addOre.accept(WorldTargetType.DEFAULT, OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.TIN);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.BAUXITE);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.COPPER);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.GALENA);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.IRIDIUM);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.LEAD);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.RUBY);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.SAPPHIRE);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.SILVER);
addOre.accept(BiomeSelectors.foundInOverworld(), OreFeatureConfig.Rules.BASE_STONE_OVERWORLD, TRContent.Ores.TIN);
return Collections.unmodifiableList(ores);
features.add(new DataDrivenFeature(
new Identifier("techreborn", "rubber_tree"),
BiomeSelectors.categories(Biome.Category.FOREST, Biome.Category.TAIGA, Biome.Category.SWAMP),
getRubberTree(),
GenerationStep.Feature.VEGETAL_DECORATION
));
return features;
}
// Used to export the worldgen jsons
public static void export() {
for (DataDrivenFeature defaultFeature : getDefaultFeatures()) {
JsonElement jsonElement = defaultFeature.serialise();
String json = jsonElement.toString();
Path dir = Paths.get("..\\src\\main\\resources\\data\\techreborn\\techreborn\\features");
try {
Files.write(dir.resolve(defaultFeature.getIdentifier().getPath() + ".json"), json.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View file

@ -25,6 +25,8 @@
package techreborn.world;
import net.minecraft.block.sapling.SaplingGenerator;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DecoratedFeatureConfig;
import net.minecraft.world.gen.feature.TreeFeatureConfig;
@ -33,12 +35,18 @@ import org.jetbrains.annotations.Nullable;
import java.util.Random;
public class RubberSaplingGenerator extends SaplingGenerator {
private final Identifier identifier = new Identifier("techreborn", "rubber_tree");
@Nullable
@Override
protected ConfiguredFeature<TreeFeatureConfig, ?> createTreeFeature(Random random, boolean bl) {
DecoratedFeatureConfig decoratedFeatureConfig = (DecoratedFeatureConfig) WorldGenerator.activeConfig.getRubberTree().getConfig();
MutableRegistry<ConfiguredFeature<?, ?>> registry = WorldGenerator.worldGenObseravable.getA();
if (!registry.containsId(identifier)) {
throw new RuntimeException("Could not find registered rubber tree feature!");
}
DecoratedFeatureConfig decoratedFeatureConfig = (DecoratedFeatureConfig) registry.get(identifier).getConfig();
//noinspection unchecked
return (ConfiguredFeature<TreeFeatureConfig, ?>) decoratedFeatureConfig.feature.get();
}
}

View file

@ -1,103 +0,0 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.world;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.BlockState;
import net.minecraft.structure.rule.RuleTest;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.OreFeatureConfig;
public class TechRebornOre {
public static final Codec<TechRebornOre> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
WorldTargetType.CODEC.fieldOf("target").forGetter(TechRebornOre::getTargetType),
RuleTest.field_25012.fieldOf("rule").forGetter(TechRebornOre::getRuleTest),
BlockState.CODEC.fieldOf("blockState").forGetter(TechRebornOre::getBlockState),
Codec.INT.fieldOf("maxY").forGetter(TechRebornOre::getMaxY),
Codec.INT.fieldOf("veinSize").forGetter(TechRebornOre::getVeinCount),
Codec.INT.fieldOf("veinCount").forGetter(TechRebornOre::getVeinCount)
).apply(instance, TechRebornOre::new)
);
private final WorldTargetType targetType;
private final RuleTest ruleTest;
private final BlockState blockState;
private final int maxY;
private final int veinSize;
private final int veinCount;
private final ConfiguredFeature<?, ?> configuredFeature;
public TechRebornOre(WorldTargetType targetType, RuleTest ruleTest, BlockState blockState, int maxY, int veinSize, int veinCount) {
this.targetType = targetType;
this.ruleTest = ruleTest;
this.blockState = blockState;
this.maxY = maxY;
this.veinSize = veinSize;
this.veinCount = veinCount;
this.configuredFeature = Feature.ORE.configure(
new OreFeatureConfig(ruleTest, blockState, veinSize)
)
.method_30377(maxY)
.spreadHorizontally()
.repeat(veinCount);
}
public ConfiguredFeature<?, ?> getConfiguredFeature() {
return configuredFeature;
}
public Identifier getIdentifier() {
return new Identifier("techreborn", "ore_" + Registry.BLOCK.getId(blockState.getBlock()).toString().replace(":", "_"));
}
public WorldTargetType getTargetType() {
return targetType;
}
public RuleTest getRuleTest() {
return ruleTest;
}
public BlockState getBlockState() {
return blockState;
}
public int getMaxY() {
return maxY;
}
public int getVeinSize() {
return veinSize;
}
public int getVeinCount() {
return veinCount;
}
}

View file

@ -0,0 +1,62 @@
package techreborn.world;
import com.mojang.serialization.Codec;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.world.gen.GenerationStep;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
public class WorldGenCodecs {
// just a wrapper around GenerationStep.Feature with a codec
public static enum GenerationStepFeature implements StringIdentifiable {
RAW_GENERATION("RAW_GENERATION", GenerationStep.Feature.RAW_GENERATION),
LAKES("LAKES", GenerationStep.Feature.LAKES),
LOCAL_MODIFICATIONS("LOCAL_MODIFICATIONS", GenerationStep.Feature.LOCAL_MODIFICATIONS),
UNDERGROUND_STRUCTURES("UNDERGROUND_STRUCTURES", GenerationStep.Feature.UNDERGROUND_STRUCTURES),
SURFACE_STRUCTURES("SURFACE_STRUCTURES", GenerationStep.Feature.SURFACE_STRUCTURES),
STRONGHOLDS("STRONGHOLDS", GenerationStep.Feature.STRONGHOLDS),
UNDERGROUND_ORES("UNDERGROUND_ORES", GenerationStep.Feature.UNDERGROUND_ORES),
UNDERGROUND_DECORATION("UNDERGROUND_DECORATION", GenerationStep.Feature.UNDERGROUND_DECORATION),
VEGETAL_DECORATION("VEGETAL_DECORATION", GenerationStep.Feature.VEGETAL_DECORATION),
TOP_LAYER_MODIFICATION("TOP_LAYER_MODIFICATION", GenerationStep.Feature.TOP_LAYER_MODIFICATION);
public static final Codec<GenerationStepFeature> CODEC = StringIdentifiable.createCodec(GenerationStepFeature::values, GenerationStepFeature::byName);
private static final Map<String, GenerationStepFeature> BY_NAME = Arrays.stream(values()).collect(Collectors.toMap(GenerationStepFeature::getName, (carver) -> carver));
private static final Map<GenerationStep.Feature, GenerationStepFeature> BY_FEATURE = Arrays.stream(values()).collect(Collectors.toMap(GenerationStepFeature::getFeature, (carver) -> carver));
private final String name;
private final GenerationStep.Feature feature;
GenerationStepFeature(String name, GenerationStep.Feature feature) {
this.name = name;
this.feature = feature;
}
public GenerationStep.Feature getFeature() {
return feature;
}
public String getName() {
return this.name;
}
@Nullable
public static WorldGenCodecs.GenerationStepFeature byName(String name) {
return BY_NAME.get(name);
}
@Nullable
public static WorldGenCodecs.GenerationStepFeature byFeature(GenerationStep.Feature feature) {
return BY_FEATURE.get(feature);
}
@Override
public String asString() {
return name;
}
}
}

View file

@ -1,58 +0,0 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.world;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.TreeFeatureConfig;
import java.util.List;
public class WorldGenConfig {
public static final Codec<WorldGenConfig> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
Codec.list(TechRebornOre.CODEC).fieldOf("ores").forGetter(WorldGenConfig::getOres),
ConfiguredFeature.CODEC.fieldOf("rubberTree").forGetter(WorldGenConfig::getRubberTree)
)
.apply(instance, WorldGenConfig::new)
);
private final List<TechRebornOre> ores;
private final ConfiguredFeature<?, ?> rubberTree;
public WorldGenConfig(List<TechRebornOre> ores, ConfiguredFeature<?, ?> rubberTree) {
this.ores = ores;
this.rubberTree = rubberTree;
}
public ConfiguredFeature<?, ?> getRubberTree() {
return rubberTree;
}
public List<TechRebornOre> getOres() {
return ores;
}
}

View file

@ -0,0 +1,110 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.world;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
public class WorldGenConfigReloader implements IdentifiableResourceReloadListener {
private static final Logger LOGGER = LogManager.getLogger();
@Override
public CompletableFuture<Void> reload(Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor) {
return CompletableFuture.supplyAsync(() -> loadConfig(manager), prepareExecutor)
.thenCompose(synchronizer::whenPrepared)
.thenApplyAsync(this::apply, applyExecutor);
}
private List<DataDrivenFeature> loadConfig(ResourceManager manager) {
final Collection<Identifier> featureResources = manager.findResources("techreborn/features", s -> s.endsWith(".json"));
final List<DataDrivenFeature> features = new LinkedList<>();
for (Identifier resource : featureResources) {
DataDrivenFeature identifiableObject = parse(DataDrivenFeature::deserialise, resource, manager);
if (identifiableObject != null) {
features.add(identifiableObject);
}
}
LOGGER.info("Loaded " + features.size() + " features");
return features;
}
@Nullable
private <T> T parse(BiFunction<Identifier, JsonObject, T> deserialiser, Identifier resource, ResourceManager manager) {
try(InputStreamReader inputStreamReader = new InputStreamReader(manager.getResource(resource).getInputStream(), StandardCharsets.UTF_8)) {
JsonElement jsonElement = new JsonParser().parse(inputStreamReader);
return deserialiser.apply(resource, jsonElement.getAsJsonObject());
} catch (JsonParseException |IOException e) {
LOGGER.error("Failed to parse " + resource.toString());
LOGGER.error(e);
}
return null;
}
private Void apply(List<DataDrivenFeature> features) {
WorldGenerator.worldGenObseravable.pushB(features);
return null;
}
@Override
public Identifier getFabricId() {
return new Identifier("techreborn", "worldgenerator");
}
public static List<DataDrivenFeature> getActiveFeatures() {
return WorldGenerator.worldGenObseravable.getB();
}
@Override
public Collection<Identifier> getFabricDependencies() {
// Load before tags, so we are soon enough to get into the world gen
return Collections.singletonList(ResourceReloadListenerKeys.TAGS);
}
}

View file

@ -24,107 +24,82 @@
package techreborn.world;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
import net.fabricmc.fabric.api.biome.v1.ModificationPhase;
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biome.Category;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.decorator.ChanceDecoratorConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.TreeFeatureConfig;
import net.minecraft.world.gen.foliage.FoliagePlacerType;
import org.jetbrains.annotations.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import reborncore.common.util.BiObseravable;
import reborncore.mixin.common.AccessorFoliagePlacerType;
import techreborn.config.TechRebornConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* @author drcrazy
*/
public class WorldGenerator {
private static final Logger LOGGER = LogManager.getLogger();
public static Feature<TreeFeatureConfig> RUBBER_TREE_FEATURE;
public static RubberTreeDecorator RUBBER_TREE_DECORATOR;
public static FoliagePlacerType<RubberTreeFeature.FoliagePlacer> RUBBER_TREE_FOLIAGE_PLACER_TYPE;
@Nullable
public static WorldGenConfig activeConfig;
private static final List<Biome> checkedBiomes = new ArrayList<>();
public static BiObseravable<MutableRegistry<ConfiguredFeature<?, ?>>, List<DataDrivenFeature>> worldGenObseravable = new BiObseravable<>();
private static final IntArrayList modifiedRegistries = new IntArrayList();
public static void initWorldGen() {
setupTrees();
registerTreeDecorators();
activeConfig = DefaultWorldGen.getDefaultWorldGen();
// DefaultWorldGen.export();
DataResult<JsonElement> result = WorldGenConfig.CODEC.encodeStart(JsonOps.INSTANCE, activeConfig);
JsonElement jsonElement = result.getOrThrow(true, System.out::println);
String json = jsonElement.toString();
worldGenObseravable.listen(WorldGenerator::applyToActiveRegistry);
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new WorldGenConfigReloader());
DynamicRegistrySetupCallback.EVENT.register(registryManager -> {
worldGenObseravable.pushA(registryManager.get(BuiltinRegistries.CONFIGURED_FEATURE.getKey()));
});
for (Biome biome : BuiltinRegistries.BIOME) {
populateBiome(biome, activeConfig);
}
//Handles modded biomes
RegistryEntryAddedCallback.event(BuiltinRegistries.BIOME).register((i, identifier, biome) -> populateBiome(biome, activeConfig));
BiomeModifications.create(new Identifier("techreborn", "features")).add(ModificationPhase.ADDITIONS, BiomeSelectors.all(), (biomeSelectionContext, biomeModificationContext) -> {
for (DataDrivenFeature feature : worldGenObseravable.getB()) {
if (feature.getBiomeSelector().test(biomeSelectionContext)) {
biomeModificationContext.getGenerationSettings().addFeature(feature.getGenerationStep(), feature.getRegistryKey());
}
}
});
}
private static void setupTrees() {
public static void applyToActiveRegistry(MutableRegistry<ConfiguredFeature<?, ?>> registry, List<DataDrivenFeature> features) {
int hashCode = registry.hashCode();
if (modifiedRegistries.contains(hashCode)){
LOGGER.debug("Already modified world gen on this registry");
return;
}
modifiedRegistries.add(registry.hashCode());
LOGGER.debug("Applying " + features.size() + " features to active registry: " + registry);
for (DataDrivenFeature feature : features) {
registry.add(feature.getRegistryKey(), feature.getConfiguredFeature(), Lifecycle.stable());
}
}
private static void registerTreeDecorators() {
RUBBER_TREE_FEATURE = Registry.register(Registry.FEATURE, new Identifier("techreborn:rubber_tree"), new RubberTreeFeature(TreeFeatureConfig.CODEC));
RUBBER_TREE_DECORATOR = Registry.register(Registry.DECORATOR, new Identifier("techreborn:rubber_tree"), new RubberTreeDecorator(ChanceDecoratorConfig.CODEC));
RUBBER_TREE_FOLIAGE_PLACER_TYPE = AccessorFoliagePlacerType.register("techreborn:rubber_tree", RubberTreeFeature.FoliagePlacer.CODEC);
}
private static void populateBiome(Biome biome, WorldGenConfig config) {
if (checkedBiomes.contains(biome)) {
//Just to be sure we dont add the stuff twice to the same biome
return;
}
checkedBiomes.add(biome);
for (TechRebornOre ore : config.getOres()) {
if (ore.getTargetType().isApplicable(biome.getCategory())) {
addFeature(biome, ore.getIdentifier(), GenerationStep.Feature.UNDERGROUND_ORES, ore.getConfiguredFeature());
}
}
if (biome.getCategory() == Category.FOREST || biome.getCategory() == Category.TAIGA || biome.getCategory() == Category.SWAMP) {
addFeature(biome, new Identifier("techreborn:rubber_tree"), GenerationStep.Feature.VEGETAL_DECORATION, config.getRubberTree());
}
}
private static void addFeature(Biome biome, Identifier identifier, GenerationStep.Feature feature, ConfiguredFeature<?, ?> configuredFeature) {
List<List<Supplier<ConfiguredFeature<?, ?>>>> features = biome.getGenerationSettings().getFeatures();
int stepIndex = feature.ordinal();
while (features.size() <= stepIndex) {
features.add(Lists.newArrayList());
}
List<Supplier<ConfiguredFeature<?, ?>>> stepList = features.get(feature.ordinal());
if (stepList instanceof ImmutableList) {
features.set(feature.ordinal(), stepList = new ArrayList<>(stepList));
}
if (!BuiltinRegistries.CONFIGURED_FEATURE.getKey(configuredFeature).isPresent()) {
if (BuiltinRegistries.CONFIGURED_FEATURE.getOrEmpty(identifier).isPresent()) {
throw new RuntimeException("Duplicate feature: " + identifier.toString());
}
BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_FEATURE, identifier, configuredFeature);
}
stepList.add(() -> configuredFeature);
}
}

View file

@ -1,63 +0,0 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.world;
import com.mojang.serialization.Codec;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.world.biome.Biome;
import java.util.function.Predicate;
public enum WorldTargetType implements StringIdentifiable {
DEFAULT("default", category -> category != Biome.Category.NETHER && category != Biome.Category.THEEND),
NETHER("nether", category -> category == Biome.Category.NETHER),
END("end", category -> category == Biome.Category.THEEND);
private final String name;
private final Predicate<Biome.Category> biomeCategoryPredicate;
public static final Codec<WorldTargetType> CODEC = StringIdentifiable.createCodec(WorldTargetType::values, WorldTargetType::getByName);
WorldTargetType(String name, Predicate<Biome.Category> biomeCategoryPredicate) {
this.name = name;
this.biomeCategoryPredicate = biomeCategoryPredicate;
}
public String getName() {
return name;
}
public boolean isApplicable(Biome.Category biomeCategory) {
return biomeCategoryPredicate.test(biomeCategory);
}
public static WorldTargetType getByName(String name) {
return null;
}
@Override
public String asString() {
return name;
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:bauxite_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 10
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "nether",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_nether",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:cinnabar_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 126
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:copper_ore"
},
"size": 8
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 16
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:galena_ore"
},
"size": 8
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 16
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:iridium_ore"
},
"size": 3
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:lead_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 16
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,52 @@
{
"biomeSelector": "end",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"block_state": {
"Name": "minecraft:end_stone"
},
"predicate_type": "minecraft:blockstate_match"
},
"state": {
"Name": "techreborn:peridot_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 250
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "nether",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_nether",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:pyrite_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 126
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,129 @@
{
"biomeSelector": [
"forest",
"taiga",
"swamp"
],
"generationStep": "VEGETAL_DECORATION",
"configuredFeature": {
"config": {
"feature": {
"config": {
"max_water_depth": 0,
"ignore_vines": false,
"heightmap": "OCEAN_FLOOR",
"minimum_size": {
"limit": 1,
"lower_size": 0,
"upper_size": 1,
"type": "minecraft:two_layers_feature_size"
},
"decorators": [],
"trunk_provider": {
"entries": [
{
"weight": 10,
"data": {
"Properties": {
"shouldsap": "true",
"hassap": "false",
"facing": "north",
"axis": "y"
},
"Name": "techreborn:rubber_log"
}
},
{
"weight": 1,
"data": {
"Properties": {
"shouldsap": "true",
"hassap": "true",
"facing": "north",
"axis": "y"
},
"Name": "techreborn:rubber_log"
}
},
{
"weight": 1,
"data": {
"Properties": {
"shouldsap": "true",
"hassap": "true",
"facing": "south",
"axis": "y"
},
"Name": "techreborn:rubber_log"
}
},
{
"weight": 1,
"data": {
"Properties": {
"shouldsap": "true",
"hassap": "true",
"facing": "west",
"axis": "y"
},
"Name": "techreborn:rubber_log"
}
},
{
"weight": 1,
"data": {
"Properties": {
"shouldsap": "true",
"hassap": "true",
"facing": "east",
"axis": "y"
},
"Name": "techreborn:rubber_log"
}
}
],
"type": "minecraft:weighted_state_provider"
},
"leaves_provider": {
"state": {
"Properties": {
"persistent": "false",
"distance": "7"
},
"Name": "techreborn:rubber_leaves"
},
"type": "minecraft:simple_state_provider"
},
"foliage_placer": {
"height": 3,
"spireHeight": 3,
"spireBlockState": {
"Properties": {
"persistent": "false",
"distance": "7"
},
"Name": "techreborn:rubber_leaves"
},
"radius": 2,
"offset": 0,
"type": "techreborn:rubber_tree"
},
"trunk_placer": {
"base_height": 6,
"height_rand_a": 3,
"height_rand_b": 0,
"type": "minecraft:straight_trunk_placer"
}
},
"type": "techreborn:rubber_tree"
},
"decorator": {
"config": {
"chance": 50
},
"type": "techreborn:rubber_tree"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:ruby_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:sapphire_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,52 @@
{
"biomeSelector": "end",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"block_state": {
"Name": "minecraft:end_stone"
},
"predicate_type": "minecraft:blockstate_match"
},
"state": {
"Name": "techreborn:sheldonite_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 250
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:silver_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 16
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,52 @@
{
"biomeSelector": "end",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"block_state": {
"Name": "minecraft:end_stone"
},
"predicate_type": "minecraft:blockstate_match"
},
"state": {
"Name": "techreborn:sodalite_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 250
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "nether",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_nether",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:sphalerite_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 126
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,50 @@
{
"biomeSelector": "overworld",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"tag": "minecraft:base_stone_overworld",
"predicate_type": "minecraft:tag_match"
},
"state": {
"Name": "techreborn:tin_ore"
},
"size": 8
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 60
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 16
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -0,0 +1,52 @@
{
"biomeSelector": "end",
"generationStep": "UNDERGROUND_ORES",
"configuredFeature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"feature": {
"config": {
"target": {
"block_state": {
"Name": "minecraft:end_stone"
},
"predicate_type": "minecraft:blockstate_match"
},
"state": {
"Name": "techreborn:tungsten_ore"
},
"size": 6
},
"type": "minecraft:ore"
},
"decorator": {
"config": {
"bottom_offset": 0,
"top_offset": 0,
"maximum": 250
},
"type": "minecraft:range"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {},
"type": "minecraft:square"
}
},
"type": "minecraft:decorated"
},
"decorator": {
"config": {
"count": 3
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
}

View file

@ -30,7 +30,8 @@
"fabricloader": ">=0.6.3",
"fabric": "*",
"reborncore": "*",
"team_reborn_energy": ">=0.1.0"
"team_reborn_energy": ">=0.1.0",
"fabric-biome-api-v1": ">=3.0.0"
},
"authors": [
"Team Reborn",