diff --git a/ore_distribution.png b/ore_distribution.png new file mode 100644 index 000000000..4899b6696 Binary files /dev/null and b/ore_distribution.png differ diff --git a/src/gametest/groovy/techreborn/OreDistributionVisualiser.groovy b/src/gametest/groovy/techreborn/OreDistributionVisualiser.groovy new file mode 100644 index 000000000..f30eb75fb --- /dev/null +++ b/src/gametest/groovy/techreborn/OreDistributionVisualiser.groovy @@ -0,0 +1,123 @@ +/* + * 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 + +import net.minecraft.Bootstrap +import net.minecraft.SharedConstants +import net.minecraft.util.registry.BuiltinRegistries +import net.minecraft.world.EmptyBlockView +import net.minecraft.world.gen.HeightContext +import net.minecraft.world.gen.chunk.DebugChunkGenerator +import techreborn.world.OreDistribution +import techreborn.world.TargetDimension + +import javax.imageio.ImageIO +import java.awt.* +import java.awt.image.BufferedImage +import java.nio.file.Paths +import java.util.List + +class OreDistributionVisualiser { + private static final Color[] colors = new Color[] { + Color.black, + Color.red, + Color.pink, + Color.orange, + Color.yellow, + Color.green, + Color.magenta, + Color.cyan, + Color.blue + } + + static void main(String[] args) { + // Start the game up enough + SharedConstants.createGameVersion() + Bootstrap.initialize() + + generateOreDistributionVisualization() + } + + static void generateOreDistributionVisualization() throws IOException { + def heightContext = new FixedHeightContext(-64, 360) + + BufferedImage bi = new BufferedImage(450, 220, BufferedImage.TYPE_INT_ARGB) + Graphics2D png = bi.createGraphics() + Font font = new Font("TimesRoman", Font.BOLD, 20) + png.setFont(font) + + png.setPaint(Color.black) + // Draw 0 + png.drawLine(0, -heightContext.minY, (overworldOres().size() * 10) + 20, -heightContext.minY) + + png.setPaint(Color.blue) + // Draw ground + png.drawLine(0, -heightContext.minY + 64, (overworldOres().size() * 10) + 20, -heightContext.minY + 64) + + int c = 1 + for (OreDistribution value : overworldOres()) { + png.setPaint(colors[c]) + + def yMin = value.minOffset.getY(heightContext) + -heightContext.minY + def yMax = -heightContext.minY + value.maxY + + png.fill3DRect(c * 10, yMin, 10, yMax - yMin, true) + + png.drawString(value.name() + "(%d -> %d)".formatted(value.minOffset.getY(heightContext), value.maxY), 190, 25 * c) + + c += 1 + } + + ImageIO.write(bi, "PNG", Paths.get("ore_distribution.png").toFile()) + } + + private static List overworldOres() { + return Arrays.stream(OreDistribution.values()) + .filter(ore -> ore.dimension == TargetDimension.OVERWORLD) + .toList() + } + + private static class FixedHeightContext extends HeightContext { + final int minY + final int height + + FixedHeightContext(int minY, int height) { + super(new DebugChunkGenerator(BuiltinRegistries.BIOME), EmptyBlockView.INSTANCE) + + this.minY = minY + this.height = height + } + + @Override + int getMinY() { + return minY + } + + @Override + int getHeight() { + return height + } + } +} diff --git a/src/main/java/techreborn/init/TRContent.java b/src/main/java/techreborn/init/TRContent.java index a25cd763e..179d426d0 100644 --- a/src/main/java/techreborn/init/TRContent.java +++ b/src/main/java/techreborn/init/TRContent.java @@ -82,7 +82,7 @@ import techreborn.items.UpgradeItem; import techreborn.items.armor.QuantumSuitItem; import techreborn.items.tool.MiningLevel; import techreborn.utils.InitUtils; -import techreborn.world.TargetDimension; +import techreborn.world.OreDistribution; import java.util.*; import java.util.function.Function; @@ -376,21 +376,21 @@ public class TRContent { private final static Map deepslateMap = new HashMap<>(); public enum Ores implements ItemConvertible { - BAUXITE(6, 12, 10, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - CINNABAR(6, 5, 0, 128, MiningLevel.IRON, TargetDimension.NETHER), - GALENA(8, 12, 10, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - IRIDIUM(3, 4, 5, 80, MiningLevel.DIAMOND, TargetDimension.OVERWORLD), - LEAD(6, 16, 20, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - PERIDOT(6, 6, 0, 360, MiningLevel.DIAMOND, TargetDimension.END), - PYRITE(6, 6, 0, 128, MiningLevel.DIAMOND, TargetDimension.NETHER), - RUBY(6, 8, 10, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - SAPPHIRE(6, 7, 10, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - SHELDONITE(6, 4, 0, 360, MiningLevel.DIAMOND, TargetDimension.END), - SILVER(6, 16, 20, 80, MiningLevel.IRON, TargetDimension.OVERWORLD), - SODALITE(6, 4, 0, 360, MiningLevel.DIAMOND, TargetDimension.END), - SPHALERITE(6, 4, 0, 128, MiningLevel.IRON, TargetDimension.NETHER), - TIN(8, 16, 18, 80, MiningLevel.STONE, TargetDimension.OVERWORLD), - TUNGSTEN(6, 3, 0, 360, MiningLevel.DIAMOND, TargetDimension.END), + BAUXITE(MiningLevel.IRON, OreDistribution.BAUXITE), + CINNABAR(MiningLevel.IRON, OreDistribution.CINNABAR), + GALENA(MiningLevel.IRON, OreDistribution.GALENA), + IRIDIUM(MiningLevel.DIAMOND, OreDistribution.IRIDIUM), + LEAD(MiningLevel.IRON, OreDistribution.LEAD), + PERIDOT(MiningLevel.DIAMOND, OreDistribution.PERIDOT), + PYRITE(MiningLevel.DIAMOND, OreDistribution.PYRITE), + RUBY(MiningLevel.IRON, OreDistribution.RUBY), + SAPPHIRE(MiningLevel.IRON, OreDistribution.SAPPHIRE), + SHELDONITE(MiningLevel.DIAMOND, OreDistribution.SHELDONITE), + SILVER(MiningLevel.IRON, OreDistribution.SILVER), + SODALITE(MiningLevel.DIAMOND, OreDistribution.SODALITE), + SPHALERITE(MiningLevel.IRON, OreDistribution.SPHALERITE), + TIN(MiningLevel.STONE, OreDistribution.TIN), + TUNGSTEN(MiningLevel.DIAMOND, OreDistribution.TUNGSTEN), DEEPSLATE_BAUXITE(BAUXITE, MiningLevel.IRON), DEEPSLATE_GALENA(GALENA, MiningLevel.IRON), @@ -407,14 +407,9 @@ public class TRContent { public final String name; public final Block block; - public final int veinSize; - public final int veinsPerChunk; - public final int offsetBottom; // Min height of ore in number of blocks from the bottom of the world - public final int maxY; // Max height of ore in numbers of blocks from the bottom of the world - public final TargetDimension dimension; + public final OreDistribution distribution; - Ores(int veinSize, int veinsPerChunk, int offsetBottom, int maxY, MiningLevel miningLevel, TargetDimension dimension) { - this.dimension = dimension; + Ores(MiningLevel miningLevel, OreDistribution distribution) { name = this.toString().toLowerCase(Locale.ROOT); block = new OreBlock(FabricBlockSettings.of(Material.STONE) .breakByTool(FabricToolTags.PICKAXES, miningLevel.intLevel) @@ -422,15 +417,13 @@ public class TRContent { .sounds(BlockSoundGroup.STONE) .strength(2f, 2f) ); - this.veinSize = veinSize; - this.veinsPerChunk = veinsPerChunk; - this.offsetBottom = offsetBottom; - this.maxY = maxY; + InitUtils.setup(block, name + "_ore"); + this.distribution = distribution; } Ores(TRContent.Ores stoneOre, MiningLevel miningLevel) { - this(0, 0, 0, 0, miningLevel, null); + this(miningLevel, null); deepslateMap.put(stoneOre, this); } diff --git a/src/main/java/techreborn/world/OreDistribution.java b/src/main/java/techreborn/world/OreDistribution.java new file mode 100644 index 000000000..09da4c331 --- /dev/null +++ b/src/main/java/techreborn/world/OreDistribution.java @@ -0,0 +1,59 @@ +/* + * 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 net.minecraft.world.gen.YOffset; + +public enum OreDistribution { + BAUXITE(6, 12, YOffset.aboveBottom(0), 20, TargetDimension.OVERWORLD), + CINNABAR(6, 5, YOffset.aboveBottom(0), 128, TargetDimension.NETHER), + GALENA(8, 12, YOffset.aboveBottom(25), 40, TargetDimension.OVERWORLD), + IRIDIUM(3, 4, YOffset.aboveBottom(0), 0, TargetDimension.OVERWORLD), + LEAD(6, 16, YOffset.aboveBottom(40), 40, TargetDimension.OVERWORLD), + PERIDOT(6, 6, YOffset.aboveBottom(0), 360, TargetDimension.END), + PYRITE(6, 6, YOffset.aboveBottom(0), 128, TargetDimension.NETHER), + RUBY(6, 8, YOffset.fixed(20), 120, TargetDimension.OVERWORLD), + SAPPHIRE(6, 7, YOffset.fixed(20), 120, TargetDimension.OVERWORLD), + SHELDONITE(6, 4, YOffset.aboveBottom(0), 360, TargetDimension.END), + SILVER(6, 16, YOffset.aboveBottom(40), 60,TargetDimension.OVERWORLD), + SODALITE(6, 4, YOffset.aboveBottom(0), 360, TargetDimension.END), + SPHALERITE(6, 4, YOffset.aboveBottom(0), 128, TargetDimension.NETHER), + TIN(8, 16, YOffset.fixed(25), 80, TargetDimension.OVERWORLD), + TUNGSTEN(6, 3, YOffset.aboveBottom(0), 360, TargetDimension.END); + + public final int veinSize; + public final int veinsPerChunk; + public final YOffset minOffset; + public final int maxY; // Max height of ore in numbers of blocks from the bottom of the world + public final TargetDimension dimension; + + OreDistribution(int veinSize, int veinsPerChunk, YOffset minOffset, int maxY, TargetDimension dimension) { + this.veinSize = veinSize; + this.veinsPerChunk = veinsPerChunk; + this.minOffset = minOffset; + this.maxY = maxY; + this.dimension = dimension; + } +} diff --git a/src/main/java/techreborn/world/OreFeature.java b/src/main/java/techreborn/world/OreFeature.java index 0d61a8a1c..3103a63f1 100644 --- a/src/main/java/techreborn/world/OreFeature.java +++ b/src/main/java/techreborn/world/OreFeature.java @@ -53,7 +53,7 @@ public class OreFeature { } private ConfiguredFeature configureAndRegisterFeature() { - final OreFeatureConfig oreFeatureConfig = switch (ore.dimension) { + final OreFeatureConfig oreFeatureConfig = switch (ore.distribution.dimension) { case OVERWORLD -> createOverworldFeatureConfig(); case NETHER -> createSimpleFeatureConfig(OreConfiguredFeatures.BASE_STONE_NETHER); case END -> createSimpleFeatureConfig(new BlockStateMatchRuleTest(Blocks.END_STONE.getDefaultState())); @@ -69,14 +69,14 @@ public class OreFeature { return new OreFeatureConfig(List.of( OreFeatureConfig.createTarget(OreConfiguredFeatures.STONE_ORE_REPLACEABLES, this.ore.block.getDefaultState()), OreFeatureConfig.createTarget(OreConfiguredFeatures.DEEPSLATE_ORE_REPLACEABLES, this.ore.getDeeplate().block.getDefaultState()) - ), ore.veinSize); + ), ore.distribution.veinSize); } return createSimpleFeatureConfig(OreConfiguredFeatures.STONE_ORE_REPLACEABLES); } private OreFeatureConfig createSimpleFeatureConfig(RuleTest test) { - return new OreFeatureConfig(test, this.ore.block.getDefaultState(), ore.veinSize); + return new OreFeatureConfig(test, this.ore.block.getDefaultState(), ore.distribution.veinSize); } private PlacedFeature configureAndRegisterPlacedFeature() { @@ -87,10 +87,10 @@ public class OreFeature { private List getPlacementModifiers() { return modifiers( - CountPlacementModifier.of(ore.veinsPerChunk), + CountPlacementModifier.of(ore.distribution.veinsPerChunk), HeightRangePlacementModifier.uniform( - YOffset.aboveBottom(ore.offsetBottom), - YOffset.fixed(ore.maxY) + ore.distribution.minOffset, + YOffset.fixed(ore.distribution.maxY) ) ); } @@ -104,7 +104,7 @@ public class OreFeature { } public Predicate getBiomeSelector() { - return ore.dimension.biomeSelector; + return ore.distribution.dimension.biomeSelector; } public RegistryKey getPlacedFeatureRegistryKey() { diff --git a/src/main/java/techreborn/world/WorldGenerator.java b/src/main/java/techreborn/world/WorldGenerator.java index 98a47da98..a3d4cd232 100644 --- a/src/main/java/techreborn/world/WorldGenerator.java +++ b/src/main/java/techreborn/world/WorldGenerator.java @@ -81,7 +81,7 @@ public class WorldGenerator { private static List getOreFeatures() { return Arrays.stream(TRContent.Ores.values()) - .filter(ores -> ores.dimension != null) + .filter(ores -> ores.distribution != null) .map(OreFeature::new) .toList(); }