- changed 'export' button to 'set as defaults' (ctrl+click == reset defaults)

- fixed lakes generating with ocean biome
- added custom sediment disks for sand, dirt, clay, gravel
- allow shipwrecks to spawn in a chunks that are fully ocean (previously only deep ocean)
This commit is contained in:
dags- 2020-03-17 00:03:22 +00:00
parent 07959f8188
commit 739bdacebe
27 changed files with 501 additions and 84 deletions

View File

@ -29,8 +29,8 @@ import com.terraforged.api.material.WGTags;
import com.terraforged.core.util.concurrent.ThreadPool;
import com.terraforged.feature.FeatureManager;
import com.terraforged.mod.data.DataGen;
import com.terraforged.mod.feature.feature.DiskFeature;
import com.terraforged.mod.feature.tree.SaplingManager;
import com.terraforged.mod.settings.SettingsHelper;
import com.terraforged.mod.util.Environment;
import net.minecraft.world.gen.feature.Feature;
import net.minecraftforge.common.MinecraftForge;
@ -38,7 +38,6 @@ import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
@ -65,15 +64,10 @@ public class TerraForgedMod {
}
}
@SubscribeEvent
public static void server(FMLDedicatedServerSetupEvent event) {
Log.info("Setting dedicated server");
SettingsHelper.setDedicatedServer();
}
@SubscribeEvent
public static void registerFeatures(RegistryEvent.Register<Feature<?>> event) {
FeatureManager.registerTemplates(event);
event.getRegistry().register(DiskFeature.INSTANCE);
}
private static void onShutdown(FMLServerStoppingEvent event) {

View File

@ -174,12 +174,11 @@ public class BiomeProvider extends AbstractBiomeProvider {
return getModifierManager().modify(biomeMap.getBiome(cell), cell, x, z);
}
if (cell.tag == context.terrain.river || cell.tag == context.terrain.riverBanks) {
if (cell.tag == context.terrain.river || cell.tag == context.terrain.riverBanks || cell.tag == context.terrain.lake) {
Biome biome = biomeMap.getBiome(cell);
if (overridesRiver(biome)) {
return biome;
}
return biomeMap.getRiver(cell.temperature, cell.moisture, cell.biome);
}

View File

@ -43,6 +43,7 @@ import com.terraforged.feature.matcher.dynamic.DynamicMatcher;
import com.terraforged.feature.matcher.feature.FeatureMatcher;
import com.terraforged.feature.modifier.FeatureModifierLoader;
import com.terraforged.feature.modifier.FeatureModifiers;
import com.terraforged.feature.predicate.BiomePredicate;
import com.terraforged.feature.predicate.DeepWater;
import com.terraforged.feature.predicate.FeaturePredicate;
import com.terraforged.feature.predicate.MinHeight;
@ -305,13 +306,13 @@ public class TerraChunkGenerator extends ObfHelperChunkGenerator<GenerationSetti
}
// block ugly features
modifiers.getPredicates().add(Matchers.STONE_BLOBS, FeaturePredicate.DENY);
modifiers.getPredicates().add(FeatureMatcher.of(Feature.DISK), FeaturePredicate.DENY);
modifiers.getPredicates().add(Matchers.stoneBlobs(), FeaturePredicate.DENY);
modifiers.getPredicates().add(Matchers.sedimentDisks(), FeaturePredicate.DENY);
modifiers.getPredicates().add(FeatureMatcher.of(Feature.LAKE), FeaturePredicate.DENY);
modifiers.getPredicates().add(FeatureMatcher.of(Feature.SPRING_FEATURE), FeaturePredicate.DENY);
// limit to deep oceans
modifiers.getPredicates().add(FeatureMatcher.of(Feature.SHIPWRECK), DeepWater.INSTANCE);
modifiers.getPredicates().add(FeatureMatcher.of(Feature.SHIPWRECK), BiomePredicate.oceans());
modifiers.getPredicates().add(FeatureMatcher.of(Feature.OCEAN_RUIN), DeepWater.INSTANCE);
modifiers.getPredicates().add(FeatureMatcher.of(Feature.OCEAN_MONUMENT), DeepWater.INSTANCE);

View File

@ -78,7 +78,7 @@ public class TerraCommand {
@SubscribeEvent
public static void start(FMLServerStartingEvent event) {
Log.info("Registering find command!");
Log.info("Registering /terra command");
register(event.getCommandDispatcher());
}

View File

@ -75,8 +75,6 @@ public abstract class Search implements Supplier<BlockPos> {
z += dz;
}
System.out.println("LAST POS: " + pos);
return BlockPos.ZERO;
}

View File

@ -25,15 +25,36 @@
package com.terraforged.mod.feature;
import com.terraforged.feature.matcher.BiomeFeatureMatcher;
import com.terraforged.feature.matcher.biome.BiomeMatcher;
import com.terraforged.feature.matcher.feature.FeatureMatcher;
import com.terraforged.mod.feature.feature.DiskFeature;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.Feature;
public class Matchers {
public static final FeatureMatcher STONE_BLOBS = FeatureMatcher.builder()
.or("minecraft:ore").and("minecraft:dirt")
.or("minecraft:ore").and("minecraft:gravel")
.or("minecraft:ore").and("minecraft:granite")
.or("minecraft:ore").and("minecraft:diorite")
.or("minecraft:ore").and("minecraft:andesite")
.build();
public static FeatureMatcher stoneBlobs() {
return FeatureMatcher.builder()
.or("minecraft:ore").and("minecraft:dirt")
.or("minecraft:ore").and("minecraft:gravel")
.or("minecraft:ore").and("minecraft:granite")
.or("minecraft:ore").and("minecraft:diorite")
.or("minecraft:ore").and("minecraft:andesite")
.build();
}
public static BiomeFeatureMatcher sedimentDisks() {
return new BiomeFeatureMatcher(
BiomeMatcher.of(Biome.Category.RIVER, Biome.Category.SWAMP),
FeatureMatcher.builder()
.or(Feature.DISK).and("minecraft:sand")
.or(Feature.DISK).and("minecraft:gravel")
.or(Feature.DISK).and("minecraft:dirt")
.or(DiskFeature.INSTANCE).and("minecraft:sand")
.or(DiskFeature.INSTANCE).and("minecraft:gravel")
.or(DiskFeature.INSTANCE).and("minecraft:dirt")
.build()
);
}
}

View File

@ -0,0 +1,60 @@
package com.terraforged.mod.feature.feature;
import me.dags.noise.Module;
import me.dags.noise.Source;
import net.minecraft.block.BlockState;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.GenerationSettings;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.SphereReplaceConfig;
import java.util.Random;
public class DiskFeature extends Feature<SphereReplaceConfig> {
public static final DiskFeature INSTANCE = new DiskFeature();
private final Module domain = Source.simplex(1, 6, 3);
private DiskFeature() {
super(SphereReplaceConfig::deserialize);
setRegistryName("terraforged", "disk");
}
@Override
public boolean place(IWorld worldIn, ChunkGenerator<? extends GenerationSettings> generator, Random rand, BlockPos pos, SphereReplaceConfig config) {
if (!worldIn.getFluidState(pos).isTagged(FluidTags.WATER)) {
return false;
} else {
int i = 0;
float radius2 = (config.radius * config.radius) * 0.65F;
BlockPos.Mutable blockPos = new BlockPos.Mutable();
for(int x = pos.getX() - config.radius; x <= pos.getX() + config.radius; ++x) {
for(int z = pos.getZ() - config.radius; z <= pos.getZ() + config.radius; ++z) {
int dx = x - pos.getX();
int dz = z - pos.getZ();
float rad2 = domain.getValue(x, z) * radius2;
if (dx * dx + dz * dz <= rad2) {
for(int y = pos.getY() - config.ySize; y <= pos.getY() + config.ySize && y + 1 < generator.getSeaLevel(); ++y) {
blockPos.setPos(x, y, z);
BlockState current = worldIn.getBlockState(blockPos);
for(BlockState target : config.targets) {
if (target.getBlock() == current.getBlock()) {
worldIn.setBlockState(blockPos, config.state, 2);
++i;
break;
}
}
}
}
}
}
return i > 0;
}
}
}

View File

@ -0,0 +1,32 @@
package com.terraforged.mod.feature.placement;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.gen.placement.HeightWithChanceConfig;
import net.minecraft.world.gen.placement.Placement;
import java.util.Random;
import java.util.stream.Stream;
public class BetterAtSurfaceWithChanceMultiple extends Placement<HeightWithChanceConfig> {
public BetterAtSurfaceWithChanceMultiple() {
super(HeightWithChanceConfig::deserialize);
}
@Override
public Stream<BlockPos> getPositions(IWorld world, ChunkGenerator<?> generator, Random random, HeightWithChanceConfig config, BlockPos pos) {
return PosStream.of(config.count, next -> {
if (random.nextFloat() < config.chance) {
int x = random.nextInt(16) + pos.getX();
int z = random.nextInt(16) + pos.getZ();
int y = world.getHeight(Heightmap.Type.MOTION_BLOCKING, x, z);
next.setPos(x, y, z);
return true;
}
return false;
});
}
}

View File

@ -0,0 +1,8 @@
package com.terraforged.mod.feature.placement;
import net.minecraft.util.math.BlockPos;
public interface PosGenerator {
boolean generate(BlockPos.Mutable next);
}

View File

@ -0,0 +1,76 @@
package com.terraforged.mod.feature.placement;
import net.minecraft.util.math.BlockPos;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public final class PosStream {
private static final ThreadLocal<BlockPos.Mutable> MUTABLE_THREAD_LOCAL = ThreadLocal.withInitial(BlockPos.Mutable::new);
private PosStream() {
}
public static Stream<BlockPos> of(int count, Populator populator) {
return StreamSupport.stream(new PosSpliterator(count, populator), false);
}
@FunctionalInterface
public interface Populator {
/**
* Populates the BlockPos.Mutable with the next x,y,z coordinates
*
* @param next the BlockPos.Mutable to populate
* @return true if the populated BlockPos.Mutable should be used next in the stream
*/
boolean populate(BlockPos.Mutable next);
}
private static class PosSpliterator implements Spliterator<BlockPos> {
private final int attempts;
private final Populator populator;
private final BlockPos.Mutable pos = MUTABLE_THREAD_LOCAL.get();
private int counter = -1;
private PosSpliterator(int attempts, Populator populator) {
this.attempts = attempts;
this.populator = populator;
}
@Override
public boolean tryAdvance(Consumer<? super BlockPos> action) {
if (counter < attempts) {
counter++;
if (populator.populate(pos)) {
action.accept(pos);
}
return true;
}
return false;
}
@Override
public Spliterator<BlockPos> trySplit() {
// cannot split
return null;
}
@Override
public long estimateSize() {
return attempts;
}
@Override
public int characteristics() {
// assume that positions are generated from a seeded random .: ordered
return Spliterator.ORDERED;
}
}
}

View File

@ -25,9 +25,7 @@
package com.terraforged.mod.gui;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.terraforged.core.settings.Settings;
import com.terraforged.mod.gui.element.TerraButton;
import com.terraforged.mod.gui.element.TerraLabel;
import com.terraforged.mod.gui.page.FeaturePage;
import com.terraforged.mod.gui.page.FilterPage;
@ -44,14 +42,6 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.CreateWorldScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class SettingsScreen extends OverlayScreen {
@ -63,9 +53,10 @@ public class SettingsScreen extends OverlayScreen {
private final TerraSettings settings = new TerraSettings();
private int pageIndex = 0;
private boolean hasChanged = false;
public SettingsScreen(CreateWorldScreen parent) {
NBTHelper.deserialize(parent.chunkProviderSettingsJson, settings);
SettingsHelper.applyDefaults(parent.chunkProviderSettingsJson, settings);
this.parent = parent;
this.pages = new Page[]{
new GeneratorPage(settings, preview),
@ -90,6 +81,7 @@ public class SettingsScreen extends OverlayScreen {
if (pageIndex < pages.length) {
Page page = pages[pageIndex];
page.callback(() -> this.hasChanged = true);
TerraLabel title = new TerraLabel(page.getTitle());
title.visible = true;
title.x = 16;
@ -119,8 +111,7 @@ public class SettingsScreen extends OverlayScreen {
// -106
addButton(new Button(buttonsCenter - (buttonWidth * 2 + (buttonPad * 3)), buttonsRow, buttonWidth,
buttonHeight, "<<", NO_ACTION) {
addButton(new Button(buttonsCenter - (buttonWidth * 2 + (buttonPad * 3)), buttonsRow, buttonWidth, buttonHeight, "<<", NO_ACTION) {
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
super.active = hasPrevious();
@ -135,15 +126,10 @@ public class SettingsScreen extends OverlayScreen {
init();
}
}
private boolean hasPrevious() {
return pageIndex > 0;
}
});
// +56
addButton(new Button(buttonsCenter + buttonWidth + (buttonPad * 3), buttonsRow, buttonWidth, buttonHeight,
">>", NO_ACTION) {
addButton(new Button(buttonsCenter + buttonWidth + (buttonPad * 3), buttonsRow, buttonWidth, buttonHeight, ">>", NO_ACTION) {
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
super.active = hasNext();
@ -158,19 +144,45 @@ public class SettingsScreen extends OverlayScreen {
init();
}
}
private boolean hasNext() {
return pageIndex + 1 < pages.length;
}
});
addButton(new Button(width - buttonWidth - 15, buttonsRow, buttonWidth, buttonHeight, "Export", NO_ACTION) {
addButton(new TerraButton("Set Defaults", "Use the current settings as the defaults", "CTRL + click to clear them") {
private boolean ctrl = false;
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
if (Screen.hasControlDown()) {
if (!ctrl) {
ctrl = true;
setMessage("Clear Defaults");
}
super.active = true;
} else {
if (ctrl) {
ctrl = false;
setMessage("Set Defaults");
}
super.active = hasChanged;
}
super.render(mouseX, mouseY, partialTicks);
}
@Override
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
export(settings);
if (Screen.hasControlDown()) {
SettingsHelper.clearDefaults();
hasChanged = true;
} else {
for (Page page : pages) {
page.save();
}
hasChanged = false;
SettingsHelper.exportDefaults(settings);
}
}
});
}.init(width - buttonWidth - 55, buttonsRow, 90, buttonHeight));
super.init();
}
@ -239,19 +251,11 @@ public class SettingsScreen extends OverlayScreen {
Minecraft.getInstance().displayGuiScreen(parent);
}
private void export(Settings settings) {
for (Page page : pages) {
page.save();
}
CompoundNBT tag = NBTHelper.serializeCompact(settings);
JsonElement json = NBTHelper.toJson(tag);
File config = new File(Minecraft.getInstance().gameDir, "config");
File file = new File(config, SettingsHelper.SETTINGS_FILE_NAME);
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
new GsonBuilder().setPrettyPrinting().create().toJson(json, writer);
Util.getOSType().openURI(file.getParentFile().toURI());
} catch (IOException e) {
e.printStackTrace();
}
private boolean hasNext() {
return pageIndex + 1 < pages.length;
}
private boolean hasPrevious() {
return pageIndex > 0;
}
}

View File

@ -27,9 +27,59 @@ package com.terraforged.mod.gui.element;
import net.minecraftforge.fml.client.gui.widget.ExtendedButton;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class TerraButton extends ExtendedButton implements Element {
private final List<String> tooltip;
public TerraButton(String displayString) {
super(0, 0, 200, 20, displayString, b -> {});
this.tooltip = Collections.emptyList();
}
public TerraButton(String displayString, String... tooltip) {
super(0, 0, 200, 20, displayString, b -> {});
this.tooltip = Arrays.asList(tooltip);
}
public TerraButton init(int x, int y, int width, int height) {
this.x = x;
this.y = y;
setWidth(width);
setHeight(height);
return this;
}
@Override
public List<String> getTooltip() {
return tooltip;
}
public static TerraButton create(String title, int x, int y, int width, int height, String tooltip, Runnable action) {
TerraButton button = new TerraButton(title) {
private final List<String> tooltips = Collections.singletonList(tooltip);
@Override
public List<String> getTooltip() {
return tooltips;
}
@Override
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
action.run();
}
};
button.x = x;
button.y = y;
button.setWidth(width);
button.setHeight(height);
return button;
}
}

View File

@ -61,8 +61,10 @@ public abstract class TerraSlider extends Slider implements Slider.ISlider, Elem
@Override
public void onRelease(double mouseX, double mouseY) {
if (dragging) {
callback.run();
}
super.onRelease(mouseX, mouseY);
callback.run();
}
protected abstract void onChange(Slider slider, CompoundNBT value);

View File

@ -27,7 +27,17 @@ package com.terraforged.mod.gui.page;
public abstract class BasePage extends Page {
private Runnable changeListener = () -> {};
public BasePage() {
super(4, 0, 0.7F, 0.3F);
}
public void callback(Runnable runnable) {
changeListener = runnable;
}
protected void update() {
changeListener.run();
}
}

View File

@ -53,6 +53,6 @@ public class FeaturePage extends BasePage {
@Override
public void init(OverlayScreen parent) {
Column left = getColumn(0);
addElements(left.left, left.top, left, featureSettings, false, left.scrollPane::addButton, NO_CALLBACK);
addElements(left.left, left.top, left, featureSettings, false, left.scrollPane::addButton, this::update);
}
}

View File

@ -59,7 +59,9 @@ public class FilterPage extends BasePage {
addElements(0, 0, column, filterSettings, true, column.scrollPane::addButton, this::update);
}
private void update() {
@Override
protected void update() {
super.update();
preview.apply(settings -> NBTHelper.deserialize(filterSettings, settings.filters));
}
}

View File

@ -59,7 +59,8 @@ public class GeneratorPage extends BasePage {
addElements(left.left, left.top, left, generatorSettings, true, left.scrollPane::addButton, this::update);
}
private void update() {
protected void update() {
super.update();
preview.apply(settings -> NBTHelper.deserialize(generatorSettings, settings.generator));
}
}

View File

@ -64,6 +64,8 @@ public abstract class Page implements IGuiEventListener, OverlayRenderer {
this.columns = new Column[columnSizes.length];
}
public abstract void callback(Runnable runnable);
public abstract void save();
public abstract void init(OverlayScreen parent);

View File

@ -60,7 +60,8 @@ public class RiverPage extends BasePage {
addElements(0, 0, center, riverSettings, true, center.scrollPane::addButton, this::update);
}
private void update() {
protected void update() {
super.update();
preview.apply(settings -> NBTHelper.deserialize(riverSettings, settings.rivers));
}
}

View File

@ -53,6 +53,6 @@ public class StructurePage extends BasePage {
@Override
public void init(OverlayScreen parent) {
Column left = getColumn(0);
addElements(left.left, left.top, left, structureSettings, false, left.scrollPane::addButton, NO_CALLBACK);
addElements(left.left, left.top, left, structureSettings, false, left.scrollPane::addButton, this::update);
}
}

View File

@ -60,7 +60,8 @@ public class TerrainPage extends BasePage {
addElements(0, 0, center, terrainSettings, true, center.scrollPane::addButton, this::update);
}
private void update() {
protected void update() {
super.update();
preview.apply(settings -> NBTHelper.deserialize(terrainSettings, settings.terrain));
}
}

View File

@ -87,7 +87,7 @@ public class PreviewPage extends BasePage {
update();
}
private void update() {
protected void update() {
preview.update(settings, previewerSettings);
}

View File

@ -1,26 +1,30 @@
package com.terraforged.mod.settings;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.terraforged.mod.Log;
import com.terraforged.mod.TerraWorld;
import com.terraforged.mod.util.nbt.NBTHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.IWorld;
import net.minecraft.world.storage.WorldInfo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class SettingsHelper {
public static final String SETTINGS_FILE_NAME = "terraforged-generator.json";
private static boolean dedicated = false;
public static void setDedicatedServer() {
dedicated = true;
}
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static int getVersion(WorldInfo info) {
if (info.getGeneratorOptions().isEmpty()) {
@ -38,16 +42,44 @@ public class SettingsHelper {
return version.getInt("value");
}
public static TerraSettings getSettings(IWorld world) {
if (dedicated) {
public static void clearDefaults() {
File file = new File("config", SettingsHelper.SETTINGS_FILE_NAME);
if (file.exists() && file.delete()) {
Log.info("Deleted generator defaults");
}
}
public static void exportDefaults(TerraSettings settings) {
CompoundNBT tag = NBTHelper.serializeCompact(settings);
JsonElement json = NBTHelper.toJson(tag);
File config = new File(Minecraft.getInstance().gameDir, "config");
File file = new File(config, SettingsHelper.SETTINGS_FILE_NAME);
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
GSON.toJson(json, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void applyDefaults(CompoundNBT options, TerraSettings dest) {
if (options.isEmpty()) {
try (Reader reader = new BufferedReader(new FileReader(new File("config", SETTINGS_FILE_NAME)))) {
Log.info("Loading generator settings from json");
return new Gson().fromJson(reader, TerraSettings.class);
} catch (Throwable ignored) {
return getSettings(world.getWorldInfo());
JsonElement json = new JsonParser().parse(reader);
options = NBTHelper.fromJson(json);
} catch (IOException ignored) {
}
}
return getSettings(world.getWorldInfo());
NBTHelper.deserialize(options, dest);
}
public static TerraSettings getSettings(IWorld world) {
try (Reader reader = new BufferedReader(new FileReader(new File("config", SETTINGS_FILE_NAME)))) {
Log.info("Loading generator settings from json");
return new Gson().fromJson(reader, TerraSettings.class);
} catch (Throwable ignored) {
return getSettings(world.getWorldInfo());
}
}
public static TerraSettings getSettings(WorldInfo info) {

View File

@ -47,6 +47,12 @@ public class NBTHelper {
return output.getValue();
}
public static CompoundNBT fromJson(JsonElement json) {
Dynamic<JsonElement> input = new Dynamic<>(JsonOps.INSTANCE, json);
Dynamic<INBT> output = input.convert(NBTDynamicOps.INSTANCE);
return (CompoundNBT) output.getValue();
}
public static Stream<CompoundNBT> stream(CompoundNBT tag) {
return tag.keySet().stream()
.map(tag::getCompound)

View File

@ -0,0 +1,37 @@
{
"match": [
[
"minecraft:disk",
"minecraft:clay"
]
],
"replace": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "terraforged:disk",
"config": {
"state": {
"Name": "minecraft:clay"
},
"radius": 4,
"y_size": 1,
"targets": [
{
"Name": "minecraft:dirt"
},
{
"Name": "minecraft:clay"
}
]
}
},
"decorator": {
"name": "minecraft:count_top_solid",
"config": {
"count": 1
}
}
}
}
}

View File

@ -0,0 +1,40 @@
{
"match": [
[
"minecraft:disk",
"minecraft:dirt"
]
],
"replace": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "terraforged:disk",
"config": {
"state": {
"Name": "minecraft:sand"
},
"radius": 7,
"y_size": 2,
"targets": [
{
"Name": "minecraft:dirt"
},
{
"Name": "minecraft:grass_block",
"Properties": {
"snowy": "false"
}
}
]
}
},
"decorator": {
"name": "minecraft:count_top_solid",
"config": {
"count": 3
}
}
}
}
}

View File

@ -0,0 +1,40 @@
{
"match": [
[
"minecraft:disk",
"minecraft:gravel"
]
],
"replace": {
"name": "minecraft:decorated",
"config": {
"feature": {
"name": "terraforged:disk",
"config": {
"state": {
"Name": "minecraft:gravel"
},
"radius": 6,
"y_size": 2,
"targets": [
{
"Name": "minecraft:dirt"
},
{
"Name": "minecraft:grass_block",
"Properties": {
"snowy": "false"
}
}
]
}
},
"decorator": {
"name": "minecraft:count_top_solid",
"config": {
"count": 1
}
}
}
}
}